votca 2026-dev
Loading...
Searching...
No Matches
diabatwriter.cc
Go to the documentation of this file.
1/*
2 * Copyright 2009-2026 The VOTCA Development Team
3 * (http://www.votca.org)
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License")
6 *
7 * You may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19
20// Standard includes
21#include <cmath>
22#include <fstream>
23#include <stdexcept>
24
25// Third party includes
26#include <boost/format.hpp>
27
28// VOTCA includes
30
31// Local VOTCA includes
33
34namespace votca {
35namespace xtp {
36
37void DiabatWriter::WriteFile(const std::string& filename,
38 const Orbitals& orbitals, QMStateType type,
39 Index nstates) const {
40 std::ofstream out(filename);
41 if (!out.is_open()) {
42 throw std::runtime_error("DiabatWriter: could not open " + filename);
43 }
44 Write(out, orbitals, type, nstates);
45}
46
47void DiabatWriter::Write(std::ostream& out, const Orbitals& orbitals,
48 QMStateType type, Index nstates) const {
49
50 if (orbitals.hasUnrestrictedOrbitals() || orbitals.getSpin() != 1) {
51 throw std::runtime_error(
52 "DiabatWriter: only restricted closed-shell BSE is supported.");
53 }
54 if (type != QMStateType::Singlet && type != QMStateType::Triplet) {
55 throw std::runtime_error(
56 "DiabatWriter: only singlet or triplet BSE states can be written.");
57 }
58 const bool singlet = (type == QMStateType::Singlet);
59 if ((singlet && !orbitals.hasBSESinglets()) ||
60 (!singlet && !orbitals.hasBSETriplets())) {
61 throw std::runtime_error("DiabatWriter: orbitals contain no BSE " +
62 type.ToLongString() + " states.");
63 }
64 const tools::EigenSystem& es =
65 singlet ? orbitals.BSESinglets() : orbitals.BSETriplets();
66
67 const bool tda = orbitals.getTDAApprox();
68 const Index nbasis = orbitals.getBasisSetSize();
69 // doubly occupied levels (valence only if ECPs are used, consistent with
70 // the fchk written from the same orbitals)
71 const Index nocc = orbitals.getLumo();
72 const Index vmin = orbitals.getBSEvmin();
73 const Index cmin = orbitals.getBSEcmin();
74 const Index vtotal = orbitals.getBSEvmax() - vmin + 1;
75 const Index ctotal = orbitals.getBSEcmax() - cmin + 1;
76 if (orbitals.getBSEvmax() != nocc - 1 || cmin != nocc) {
77 throw std::runtime_error(
78 "DiabatWriter: BSE window does not start at HOMO/LUMO.");
79 }
80 if (es.eigenvectors().rows() != vtotal * ctotal) {
81 throw std::runtime_error(
82 "DiabatWriter: BSE eigenvector size does not match the BSE window.");
83 }
84 if (!tda && es.eigenvectors2().rows() != vtotal * ctotal) {
85 throw std::runtime_error(
86 "DiabatWriter: full BSE requested but no anti-resonant (Y) part "
87 "stored.");
88 }
89
90 Index nwrite = es.eigenvalues().size();
91 if (nstates > 0 && nstates < nwrite) {
92 nwrite = nstates;
93 }
94
95 Eigen::VectorXd osc = Eigen::VectorXd::Zero(nwrite);
96 if (singlet && orbitals.hasTransitionDipoles()) {
97 Eigen::VectorXd all = orbitals.Oscillatorstrengths();
98 const Index n = std::min<Index>(nwrite, all.size());
99 osc.head(n) = all.head(n);
100 }
101
102 const double e0 = orbitals.getDFTTotalEnergy();
103 const double spin_factor = 1.0 / std::sqrt(2.0);
104 const std::string rule(60, '-');
105
106 out << FormatIdentifier << "\n";
107 out << "# Written by VOTCA-XTP (orb2diabat) from BSE "
108 << (singlet ? "singlets" : "triplets") << ", "
109 << (tda ? "Tamm-Dancoff" : "full BSE") << ", window MO " << vmin + 1
110 << ".." << orbitals.getBSEcmax() + 1 << "\n";
111 out << "Method: " << (tda ? "TDA" : "TDDFT") << "\n";
112 out << "Orbitals are not spin-polarized.\n";
113 out << "Number of electrons: " << 2 * nocc << "\n";
114 out << "Number of alpha electrons: " << nocc << "\n";
115 out << "Number of beta electrons: " << nocc << "\n";
116 out << "Number of occupied orbitals (alpha): " << nocc << "\n";
117 out << "Number of virtual orbitals (alpha): " << nbasis - nocc << "\n";
118 out << "Number of occupied orbitals (beta): " << nocc << "\n";
119 out << "Number of virtual orbitals (beta): " << nbasis - nocc << "\n";
120 out << boost::format(
121 "Total energy of the reference ground state (a.u.): "
122 "%.12E\n") %
123 e0;
124 out << "\nState Information:\n\n";
125
126 for (Index i = 0; i < nwrite; ++i) {
127 const double omega = es.eigenvalues()(i);
128 Eigen::VectorXd x = spin_factor * es.eigenvectors().col(i);
129 Eigen::VectorXd y;
130 if (!tda) {
131 y = spin_factor * es.eigenvectors2().col(i);
132 }
133 const double nx = x.squaredNorm();
134 const double ny = tda ? 0.0 : y.squaredNorm();
135
136 out << "\n State index: " << i + 1 << "\n\n";
137 out << boost::format(" Total energy (a.u.): %.12E\n") % (e0 + omega);
138 out << boost::format(" Excitation energy (eV): %16.12f\n") %
139 (omega * tools::conv::hrt2ev);
140 out << " Multiplicity: " << (singlet ? "Singlet" : "Triplet") << "\n";
141 out << boost::format(" <S^2>: %9.6f\n") % (singlet ? 0.0 : 2.0);
142 out << boost::format(" Strength: %12.6f\n") % osc(i);
143 out << boost::format(" Normalization factor: %9.6f\n") % (2.0 * (nx - ny));
144 out << " Amplitudes:\n " << rule << "\n";
145 // VOTCA compound index of a (v,c) pair is v * ctotal + c
146 for (Index v = 0; v < vtotal; ++v) {
147 for (Index c = 0; c < ctotal; ++c) {
148 out << boost::format(" %6d --> %5d % .15E alpha\n") %
149 (vmin + v + 1) % (cmin + c + 1) % x(v * ctotal + c);
150 }
151 }
152 if (!tda) {
153 for (Index v = 0; v < vtotal; ++v) {
154 for (Index c = 0; c < ctotal; ++c) {
155 out << boost::format(" %6d <-- %5d % .15E alpha\n") %
156 (vmin + v + 1) % (cmin + c + 1) % y(v * ctotal + c);
157 }
158 }
159 }
160 out << " " << rule << "\n";
161 out << boost::format(" X: %12.8f Y: %11.8f\n") % (2.0 * nx) %
162 (2.0 * ny);
163 }
164 out << "\n";
165}
166
167} // namespace xtp
168} // namespace votca
const Eigen::MatrixXd & eigenvectors2() const
Definition eigensystem.h:36
const Eigen::VectorXd & eigenvalues() const
Definition eigensystem.h:30
const Eigen::MatrixXd & eigenvectors() const
Definition eigensystem.h:33
void Write(std::ostream &out, const Orbitals &orbitals, QMStateType type, Index nstates=-1) const
void WriteFile(const std::string &filename, const Orbitals &orbitals, QMStateType type, Index nstates=-1) const
static constexpr const char * FormatIdentifier
First line Diabat 2.0 uses to recognise its native state format.
Container for molecular orbitals and derived one-particle data.
Definition orbitals.h:47
Index getBSEvmax() const
Return the highest valence orbital included in BSE.
Definition orbitals.h:438
const tools::EigenSystem & BSETriplets() const
Return read-only access to triplet BSE eigenpairs.
Definition orbitals.h:497
Index getBSEcmin() const
Return the lowest conduction orbital included in BSE.
Definition orbitals.h:441
double getDFTTotalEnergy() const
Return the stored total DFT energy.
Definition orbitals.h:292
Index getSpin() const
Return the stored spin multiplicity.
Definition orbitals.h:252
bool hasUnrestrictedOrbitals() const
Report whether separate beta-spin orbitals are present.
Definition orbitals.h:718
const tools::EigenSystem & BSESinglets() const
Return read-only access to singlet BSE eigenpairs.
Definition orbitals.h:510
Index getBSEcmax() const
Return the highest conduction orbital included in BSE.
Definition orbitals.h:444
bool getTDAApprox() const
Return whether the Tamm-Dancoff approximation is enabled.
Definition orbitals.h:416
bool hasBSESinglets() const
Report whether singlet BSE eigenpairs are available.
Definition orbitals.h:505
Index getBSEvmin() const
Return the lowest valence orbital included in BSE.
Definition orbitals.h:435
Eigen::VectorXd Oscillatorstrengths() const
Definition orbitals.cc:657
bool hasTransitionDipoles() const
Report whether transition dipole moments have been computed.
Definition orbitals.h:577
bool hasBSETriplets() const
Report whether triplet BSE eigenpairs are available.
Definition orbitals.h:492
Index getBasisSetSize() const
Return the number of AO basis functions in the DFT basis.
Definition orbitals.h:72
Index getLumo() const
Return the default LUMO index used by spin-agnostic callers.
Definition orbitals.h:105
std::string ToLongString() const
Definition qmstate.cc:72
const double hrt2ev
Definition constants.h:53
Charge transport classes.
Definition ERIs.h:28
Provides a means for comparing floating point numbers.
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26