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
TimeDependentUtils.h
Go to the documentation of this file.
1 
7 #ifndef SPARROW_TIMEDEPENDENTUTILS_H
8 #define SPARROW_TIMEDEPENDENTUTILS_H
9 
14 #include <Eigen/Core>
15 #include <cereal/cereal.hpp>
16 #include <map>
17 
18 namespace Scine {
19 
20 namespace Sparrow {
21 
23  double c1 = 1, c2 = 1, d = 1;
24 
25  template<class Archive>
26  void serialize(Archive& archive) {
27  archive(CEREAL_NVP(c1), CEREAL_NVP(c2), CEREAL_NVP(d));
28  }
29 };
30 
38  public:
47  static Eigen::VectorXd generateEnergyDifferenceVector(int nOccupiedOrbitals, int nVirtualOrbitals,
48  const Utils::SingleParticleEnergies& energies);
58  template<Utils::Reference restrictedness>
59  static std::vector<std::string>
60  generateExcitationsLabels(const Utils::SpinAdaptedContainer<restrictedness, std::vector<Utils::Excitation>>& excitations);
61 
71  static std::vector<std::string> generateExcitationsLabels(const std::vector<Utils::Excitation>& excitations,
72  const Eigen::Matrix<bool, -1, 1>& isBeta = {});
73 
81  template<Utils::Reference restrictedness>
85 
93  static void generateVirtualOrbitalIndices(const std::vector<int>& occupiedOrbitalsIndices,
94  std::vector<int>& virtualOrbitalsIndices);
101  static std::vector<Utils::Excitation> generateExcitations(const std::vector<int>& occupiedOrbitalsIndices,
102  const std::vector<int>& virtualOrbitalsIndices);
111  template<Utils::Reference restrictedness>
114 
142  template<Utils::Reference restrictedness>
143  static std::vector<int>
145 
146  enum class Direction { To, From };
183  template<typename Derived, typename DerivedResult>
184  static void transformOrder(const Eigen::MatrixBase<Derived>& toTransform, const Eigen::MatrixBase<DerivedResult>& result,
185  const std::vector<int>& orderVector, Direction direction);
189  template<typename Type>
190  static void transformOrder(const std::vector<Type>& toTransform, std::vector<Type>& result,
191  const std::vector<int>& orderVector, Direction direction);
192 
201 
205  template<typename T>
206  static auto flatten(Utils::SpinAdaptedContainer<Utils::Reference::Restricted, std::vector<T>> in) -> std::vector<T>;
207 
211  template<typename T>
212  static auto flatten(Utils::SpinAdaptedContainer<Utils::Reference::Unrestricted, std::vector<T>> in) -> std::vector<T>;
213 };
214 
216  -> Eigen::VectorXd {
217  return in.restricted;
218 }
220  -> Eigen::VectorXd {
221  Eigen::VectorXd out(in.alpha.size() + in.beta.size());
222  out << in.alpha, in.beta;
223  return out;
224 }
225 
226 template<typename T>
227 inline auto TimeDependentUtils::flatten(Utils::SpinAdaptedContainer<Utils::Reference::Restricted, std::vector<T>> in)
228  -> std::vector<T> {
229  return in.restricted;
230 }
231 template<typename T>
232 inline auto TimeDependentUtils::flatten(Utils::SpinAdaptedContainer<Utils::Reference::Unrestricted, std::vector<T>> in)
233  -> std::vector<T> {
234  std::vector<T> out;
235  out.reserve(in.alpha.size() + in.beta.size());
236  std::copy(in.alpha.begin(), in.alpha.end(), std::back_inserter(out));
237  std::copy(in.beta.begin(), in.beta.end(), std::back_inserter(out));
238  return out;
239 }
240 
241 inline Eigen::VectorXd TimeDependentUtils::generateEnergyDifferenceVector(int nOccupiedOrbitals, int nVirtualOrbitals,
242  const Utils::SingleParticleEnergies& energies) {
243  auto const& energyLevels = energies.getRestrictedEnergies();
244 
245  Eigen::VectorXd energyDifferenceVector(nOccupiedOrbitals * nVirtualOrbitals);
246  for (int occ = 0; occ < nOccupiedOrbitals; ++occ) {
247  for (int vir = 0; vir < nVirtualOrbitals; ++vir) {
248  energyDifferenceVector(nVirtualOrbitals * occ + vir) = energyLevels[nOccupiedOrbitals + vir] - energyLevels[occ];
249  }
250  }
251  return energyDifferenceVector;
252 }
253 
254 template<>
255 inline void TimeDependentUtils::generateEnergyDifferenceVector<Utils::Reference::Unrestricted>(
258  const auto& alphaEnergies = energies.getAlphaEnergies();
259  const auto& betaEnergies = energies.getBetaEnergies();
260  auto const nAlphaMOs = alphaEnergies.size();
261  auto const nBetaMOs = betaEnergies.size();
262  const std::vector<int>& occupiedAlphaOrbitals = occupation.getFilledAlphaOrbitals();
263  const std::vector<int>& occupiedBetaOrbitals = occupation.getFilledBetaOrbitals();
264  auto const nOccAlpha = occupiedAlphaOrbitals.size();
265  auto const nOccBeta = occupiedBetaOrbitals.size();
266  auto const nVirAlpha = nAlphaMOs - nOccAlpha;
267  auto const nVirBeta = nBetaMOs - nOccBeta;
268 
269  energyDifferenceVector.alpha.resize(nOccAlpha * nVirAlpha);
270  energyDifferenceVector.beta.resize(nOccBeta * nVirBeta);
271 
272  int alphaIter = 0;
273  for (auto const& occ : occupiedAlphaOrbitals) {
274  for (unsigned int mo = 0; mo < nAlphaMOs; ++mo) {
275  if ((std::find(occupiedAlphaOrbitals.begin(), occupiedAlphaOrbitals.end(), mo) == occupiedAlphaOrbitals.end())) {
276  energyDifferenceVector.alpha[alphaIter] = alphaEnergies[mo] - alphaEnergies[occ];
277  alphaIter++;
278  }
279  }
280  }
281  int betaIter = 0;
282  for (auto const& occ : occupiedBetaOrbitals) {
283  for (unsigned int mo = 0; mo < nBetaMOs; ++mo) {
284  if ((std::find(occupiedBetaOrbitals.begin(), occupiedBetaOrbitals.end(), mo) == occupiedBetaOrbitals.end())) {
285  energyDifferenceVector.beta[betaIter] = betaEnergies[mo] - betaEnergies[occ];
286  betaIter++;
287  }
288  }
289  }
290 }
291 
292 template<>
293 inline void TimeDependentUtils::generateEnergyDifferenceVector<Utils::Reference::Restricted>(
294  const Utils::SingleParticleEnergies& energies, const Utils::LcaoUtils::ElectronicOccupation& occupation,
295  Utils::SpinAdaptedContainer<Utils::Reference::Restricted, Eigen::VectorXd>& energyDifferenceVector) {
296  std::vector<int> occupiedOrbitals = occupation.getFilledRestrictedOrbitals();
297  const auto& energiesLevels = energies.getRestrictedEnergies();
298  auto const nMOs = energiesLevels.size();
299  auto const nOcc = occupiedOrbitals.size();
300  auto const nVir = nMOs - nOcc;
301 
302  energyDifferenceVector.restricted.resize(nOcc * nVir);
303 
304  int iter = 0;
305  for (int occ : occupiedOrbitals) {
306  for (unsigned int mo = 0; mo < nMOs; mo++) {
307  if ((std::find(occupiedOrbitals.begin(), occupiedOrbitals.end(), mo) == occupiedOrbitals.end())) {
308  energyDifferenceVector.restricted[iter] = energiesLevels[mo] - energiesLevels[occ];
309  iter++;
310  }
311  }
312  }
313 }
314 
315 inline void TimeDependentUtils::generateVirtualOrbitalIndices(const std::vector<int>& occupiedOrbitalsIndices,
316  std::vector<int>& virtualOrbitalsIndices) {
317  unsigned int nMOs = occupiedOrbitalsIndices.size() + virtualOrbitalsIndices.size();
318  unsigned int iterEmpty = 0;
319  unsigned int iterFilled = 0;
320  for (int i = 0; i < static_cast<int>(nMOs); ++i) {
321  if (iterFilled < occupiedOrbitalsIndices.size() && i == occupiedOrbitalsIndices[iterFilled]) {
322  ++iterFilled;
323  }
324  else {
325  virtualOrbitalsIndices[iterEmpty] = i;
326  ++iterEmpty;
327  }
328  }
329 }
330 
331 inline std::vector<Utils::Excitation> TimeDependentUtils::generateExcitations(const std::vector<int>& occupiedOrbitalsIndices,
332  const std::vector<int>& virtualOrbitalsIndices) {
333  std::vector<Utils::Excitation> excitations(occupiedOrbitalsIndices.size() * virtualOrbitalsIndices.size());
334 
335  int iter = 0;
336  for (int occ : occupiedOrbitalsIndices) {
337  for (int vir : virtualOrbitalsIndices) {
338  excitations[iter].occ = occ;
339  excitations[iter].vir = vir;
340  iter++;
341  }
342  }
343  return excitations;
344 }
345 template<>
347 TimeDependentUtils::generateExcitations<Utils::Reference::Restricted>(const Utils::MolecularOrbitals& mos,
348  const Utils::LcaoUtils::ElectronicOccupation& occupation) {
349  int nMOs = mos.restrictedMatrix().cols();
350  const auto& occupiedOrbitals = occupation.getFilledRestrictedOrbitals();
351  std::vector<int> virtualOrbitals(nMOs - occupiedOrbitals.size());
352 
353  generateVirtualOrbitalIndices(occupiedOrbitals, virtualOrbitals);
355  excitations.restricted.resize(occupiedOrbitals.size() * virtualOrbitals.size());
356 
357  int iter = 0;
358  for (int occ : occupiedOrbitals) {
359  for (int vir : virtualOrbitals) {
360  excitations.restricted[iter].occ = occ;
361  excitations.restricted[iter].vir = vir;
362  iter++;
363  }
364  }
365  return excitations;
366 }
367 
368 template<>
369 inline Utils::SpinAdaptedContainer<Utils::Reference::Unrestricted, std::vector<Utils::Excitation>>
370 TimeDependentUtils::generateExcitations<Utils::Reference::Unrestricted>(const Utils::MolecularOrbitals& mos,
371  const Utils::LcaoUtils::ElectronicOccupation& occupation) {
372  int nMOs = mos.alphaMatrix().cols();
373  const auto& occupiedAlphaOrbitals = occupation.getFilledAlphaOrbitals();
374  const auto& occupiedBetaOrbitals = occupation.getFilledBetaOrbitals();
375  std::vector<int> virtualAlphaOrbitals(nMOs - occupiedAlphaOrbitals.size());
376  std::vector<int> virtualBetaOrbitals(nMOs - occupiedBetaOrbitals.size());
377 
378  generateVirtualOrbitalIndices(occupiedAlphaOrbitals, virtualAlphaOrbitals);
379  generateVirtualOrbitalIndices(occupiedBetaOrbitals, virtualBetaOrbitals);
380  Utils::SpinAdaptedContainer<Utils::Reference::Unrestricted, std::vector<Utils::Excitation>> excitations;
381  excitations.alpha.resize(occupiedAlphaOrbitals.size() * virtualAlphaOrbitals.size());
382  excitations.beta.resize(occupiedBetaOrbitals.size() * virtualBetaOrbitals.size());
383 
384  int iter = 0;
385  for (int occ : occupiedAlphaOrbitals) {
386  for (int vir : virtualAlphaOrbitals) {
387  excitations.alpha[iter].occ = occ;
388  excitations.alpha[iter].vir = vir;
389  iter++;
390  }
391  }
392  iter = 0;
393  for (int occ : occupiedBetaOrbitals) {
394  for (int vir : virtualBetaOrbitals) {
395  excitations.beta[iter].occ = occ;
396  excitations.beta[iter].vir = vir;
397  iter++;
398  }
399  }
400  return excitations;
401 }
402 
403 namespace detail {
405  bool value = true;
406 };
407 
408 inline auto occToVirLabel(int occupiedIndex, int virtualIndex) -> std::string {
409  return std::to_string(occupiedIndex) + " -> " + std::to_string(virtualIndex);
410 }
411 
412 inline auto occToVirLabel(int occupiedIndex, int virtualIndex, BetaExcitation isBeta) -> std::string {
413  std::string spinLabel = isBeta.value ? "b" : "a";
414  return std::to_string(occupiedIndex) + spinLabel + " -> " + std::to_string(virtualIndex) + spinLabel;
415 }
416 } // namespace detail
417 
418 template<>
419 inline std::vector<std::string> TimeDependentUtils::generateExcitationsLabels<Utils::Reference::Restricted>(
420  const Utils::SpinAdaptedContainer<Utils::Reference::Restricted, std::vector<Utils::Excitation>>& excitations) {
421  int nExc = excitations.restricted.size();
422  std::vector<std::string> labels;
423 
424  labels.reserve(nExc);
425 
426  for (int i = 0; i < nExc; ++i) {
427  int indexOccupied = excitations.restricted[i].occ;
428  int indexVirtual = excitations.restricted[i].vir;
429  labels.push_back(detail::occToVirLabel(indexOccupied, indexVirtual));
430  }
431  return labels;
432 }
433 
434 template<>
435 inline std::vector<std::string> TimeDependentUtils::generateExcitationsLabels<Utils::Reference::Unrestricted>(
436  const Utils::SpinAdaptedContainer<Utils::Reference::Unrestricted, std::vector<Utils::Excitation>>& excitations) {
437  int nAlphaExc = excitations.alpha.size();
438  int nBetaExc = excitations.beta.size();
439 
440  std::vector<std::string> labels;
441  labels.reserve(nAlphaExc + nBetaExc);
442 
443  for (int i = 0; i < nAlphaExc; ++i) {
444  int indexOccupied = excitations.alpha[i].occ;
445  int indexVirtual = excitations.alpha[i].vir;
446  labels.push_back(detail::occToVirLabel(indexOccupied, indexVirtual, detail::BetaExcitation{false}));
447  }
448 
449  for (int i = 0; i < nBetaExc; ++i) {
450  int indexOccupied = excitations.beta[i].occ;
451  int indexVirtual = excitations.beta[i].vir;
452  labels.push_back(detail::occToVirLabel(indexOccupied, indexVirtual, detail::BetaExcitation{true}));
453  }
454  return labels;
455 }
456 
457 inline std::vector<std::string> TimeDependentUtils::generateExcitationsLabels(const std::vector<Utils::Excitation>& excitations,
458  const Eigen::Matrix<bool, -1, 1>& isBeta) {
459  assert(static_cast<Eigen::Index>(excitations.size()) == isBeta.size() || isBeta.size() == 0);
460  std::vector<std::string> labels;
461  labels.reserve(excitations.size());
462 
463  for (unsigned int i = 0; i < excitations.size(); ++i) {
464  int occ = excitations[i].occ;
465  int vir = excitations[i].vir;
466  if (isBeta.size() != 0) {
467  labels.push_back(detail::occToVirLabel(occ, vir, detail::BetaExcitation{isBeta(i)}));
468  }
469  else {
470  labels.push_back(detail::occToVirLabel(occ, vir));
471  }
472  }
473  return labels;
474 }
475 
476 template<>
477 inline std::vector<int> TimeDependentUtils::generateEnergyOrderMap<Utils::Reference::Restricted>(
479  std::multimap<double, int> energyOrderMap;
480  std::vector<int> orderedIndices;
481  const Eigen::VectorXd& energies = energyDifferenceVector.restricted;
482  orderedIndices.reserve(energies.size());
483  for (int i = 0; i < energies.size(); ++i) {
484  energyOrderMap.insert({energies(i), i});
485  }
486  for (const auto& element : energyOrderMap) {
487  orderedIndices.push_back(element.second);
488  }
489  return orderedIndices;
490 }
491 
492 template<>
493 inline std::vector<int> TimeDependentUtils::generateEnergyOrderMap<Utils::Reference::Unrestricted>(
494  const Utils::SpinAdaptedContainer<Utils::Reference::Unrestricted, Eigen::VectorXd>& energyDifferenceVector) {
495  std::multimap<double, int> energyOrderMap;
496  std::vector<int> orderedIndices;
497  const Eigen::VectorXd& alpha = energyDifferenceVector.alpha;
498  const Eigen::VectorXd& beta = energyDifferenceVector.beta;
499  Eigen::VectorXd concatenated(alpha.size() + beta.size());
500  concatenated << alpha, beta;
501  orderedIndices.reserve(concatenated.size());
502  for (int i = 0; i < concatenated.size(); ++i) {
503  energyOrderMap.insert({concatenated(i), i});
504  }
505  for (const auto& element : energyOrderMap) {
506  orderedIndices.push_back(element.second);
507  }
508  return orderedIndices;
509 }
510 
511 template<typename Derived, typename DerivedResult>
512 inline void TimeDependentUtils::transformOrder(const Eigen::MatrixBase<Derived>& toTransform,
513  const Eigen::MatrixBase<DerivedResult>& result,
514  const std::vector<int>& orderVector, Direction direction) {
515  assert(direction == Direction::To || direction == Direction::From);
516  assert(static_cast<Eigen::Index>(orderVector.size()) == toTransform.rows());
517  auto& castResult = const_cast<Eigen::MatrixBase<DerivedResult>&>(result).derived();
518  castResult.resize(toTransform.rows(), toTransform.cols());
519  if (direction == Direction::To) {
520  for (unsigned int i = 0; i < orderVector.size(); ++i) {
521  castResult.row(i) = toTransform.row(orderVector[i]);
522  }
523  }
524  else { // Direction::From
525  for (unsigned int i = 0; i < orderVector.size(); ++i) {
526  castResult.row(orderVector[i]) = toTransform.row(i);
527  }
528  }
529 }
530 
531 template<typename Type>
532 inline void TimeDependentUtils::transformOrder(const std::vector<Type>& toTransform, std::vector<Type>& result,
533  const std::vector<int>& orderVector, Direction direction) {
534  assert(direction == Direction::To || direction == Direction::From);
535  assert(static_cast<Eigen::Index>(orderVector.size()) == static_cast<Eigen::Index>(toTransform.size()));
536  result.resize(toTransform.size());
537  if (direction == Direction::To) {
538  for (unsigned int i = 0; i < orderVector.size(); ++i) {
539  result[i] = toTransform[orderVector[i]];
540  }
541  }
542  else { // Direction::From
543  for (unsigned int i = 0; i < orderVector.size(); ++i) {
544  result[orderVector[i]] = toTransform[i];
545  }
546  }
547 }
548 
549 } // namespace Sparrow
550 } // namespace Scine
551 
552 #endif // SPARROW_TIMEDEPENDENTUTILS_H
Definition: TimeDependentUtils.h:22
static std::vector< int > generateEnergyOrderMap(const Utils::SpinAdaptedContainer< restrictedness, Eigen::VectorXd > &energyDifferenceVector)
Generates a mapping from the &quot;standard&quot; excitation order to increasing energy order.
static std::vector< Utils::Excitation > generateExcitations(const std::vector< int > &occupiedOrbitalsIndices, const std::vector< int > &virtualOrbitalsIndices)
Given occupied and virtual orbital indices, generates a vector of occ-&gt;vir excitations.
Definition: TimeDependentUtils.h:331
static void generateVirtualOrbitalIndices(const std::vector< int > &occupiedOrbitalsIndices, std::vector< int > &virtualOrbitalsIndices)
Fills a vector of virtual orbital indices having just size and occupied indices.
Definition: TimeDependentUtils.h:315
static std::vector< std::string > generateExcitationsLabels(const Utils::SpinAdaptedContainer< restrictedness, std::vector< Utils::Excitation >> &excitations)
Function generating a vector of &quot;occ-&gt;vir&quot; excitation labels.
static void transformOrder(const Eigen::MatrixBase< Derived > &toTransform, const Eigen::MatrixBase< DerivedResult > &result, const std::vector< int > &orderVector, Direction direction)
Transforms a vector or matrix from one ordering to another, or back.
Definition: TimeDependentUtils.h:512
static auto flatten(const Utils::SpinAdaptedContainer< Utils::Reference::Restricted, Eigen::VectorXd > &in) -> Eigen::VectorXd
Transforms the SpinAdaptedContainer to a Eigen::VectorXd by extracting its &quot;restricted&quot; member...
Definition: TimeDependentUtils.h:215
Definition: TimeDependentUtils.h:404
Class containing utility functions for excites-states calculations such as (NDDO-)CIS or TD-DFT(B)...
Definition: TimeDependentUtils.h:37
static Eigen::VectorXd generateEnergyDifferenceVector(int nOccupiedOrbitals, int nVirtualOrbitals, const Utils::SingleParticleEnergies &energies)
Calculates the occupied-&gt;virtual energy difference vector.
Definition: TimeDependentUtils.h:241