7 #ifndef SPARROW_TIMEDEPENDENTUTILS_H
8 #define SPARROW_TIMEDEPENDENTUTILS_H
15 #include <cereal/cereal.hpp>
23 double c1 = 1, c2 = 1, d = 1;
25 template<
class Archive>
26 void serialize(Archive& archive) {
27 archive(CEREAL_NVP(c1), CEREAL_NVP(c2), CEREAL_NVP(d));
58 template<Utils::Reference restrictedness>
59 static std::vector<std::string>
72 const Eigen::Matrix<bool, -1, 1>& isBeta = {});
81 template<Utils::Reference restrictedness>
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>
142 template<Utils::Reference restrictedness>
143 static std::vector<int>
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);
217 return in.restricted;
221 Eigen::VectorXd out(in.alpha.size() + in.beta.size());
222 out << in.alpha, in.beta;
229 return in.restricted;
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));
243 auto const& energyLevels = energies.getRestrictedEnergies();
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];
251 return energyDifferenceVector;
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;
269 energyDifferenceVector.alpha.resize(nOccAlpha * nVirAlpha);
270 energyDifferenceVector.beta.resize(nOccBeta * nVirBeta);
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];
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];
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;
302 energyDifferenceVector.restricted.resize(nOcc * nVir);
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];
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]) {
325 virtualOrbitalsIndices[iterEmpty] = i;
332 const std::vector<int>& virtualOrbitalsIndices) {
333 std::vector<Utils::Excitation> excitations(occupiedOrbitalsIndices.size() * virtualOrbitalsIndices.size());
336 for (
int occ : occupiedOrbitalsIndices) {
337 for (
int vir : virtualOrbitalsIndices) {
338 excitations[iter].occ = occ;
339 excitations[iter].vir = vir;
349 int nMOs = mos.restrictedMatrix().cols();
350 const auto& occupiedOrbitals = occupation.getFilledRestrictedOrbitals();
351 std::vector<int> virtualOrbitals(nMOs - occupiedOrbitals.size());
353 generateVirtualOrbitalIndices(occupiedOrbitals, virtualOrbitals);
355 excitations.restricted.resize(occupiedOrbitals.size() * virtualOrbitals.size());
358 for (
int occ : occupiedOrbitals) {
359 for (
int vir : virtualOrbitals) {
360 excitations.restricted[iter].occ = occ;
361 excitations.restricted[iter].vir = vir;
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());
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());
385 for (
int occ : occupiedAlphaOrbitals) {
386 for (
int vir : virtualAlphaOrbitals) {
387 excitations.alpha[iter].occ = occ;
388 excitations.alpha[iter].vir = vir;
393 for (
int occ : occupiedBetaOrbitals) {
394 for (
int vir : virtualBetaOrbitals) {
395 excitations.beta[iter].occ = occ;
396 excitations.beta[iter].vir = vir;
408 inline auto occToVirLabel(
int occupiedIndex,
int virtualIndex) -> std::string {
409 return std::to_string(occupiedIndex) +
" -> " + std::to_string(virtualIndex);
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;
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;
424 labels.reserve(nExc);
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));
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();
440 std::vector<std::string> labels;
441 labels.reserve(nAlphaExc + nBetaExc);
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}));
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}));
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());
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) {
470 labels.push_back(detail::occToVirLabel(occ, vir));
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});
486 for (
const auto& element : energyOrderMap) {
487 orderedIndices.push_back(element.second);
489 return orderedIndices;
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});
505 for (
const auto& element : energyOrderMap) {
506 orderedIndices.push_back(element.second);
508 return orderedIndices;
511 template<
typename Derived,
typename DerivedResult>
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]);
525 for (
unsigned int i = 0; i < orderVector.size(); ++i) {
526 castResult.row(orderVector[i]) = toTransform.row(i);
531 template<
typename Type>
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]];
543 for (
unsigned int i = 0; i < orderVector.size(); ++i) {
544 result[orderVector[i]] = toTransform[i];
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 "standard" 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->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 "occ->vir" 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 "restricted" 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->virtual energy difference vector.
Definition: TimeDependentUtils.h:241