votca 2026-dev
Loading...
Searching...
No Matches
dftcoupling.cc
Go to the documentation of this file.
1/*
2 * Copyright 2009-2020 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// Third party includes
21#include <boost/format.hpp>
22
23// VOTCA includes
25
26// Local VOTCA includes
27#include "votca/xtp/aomatrix.h"
29
30namespace votca {
31namespace xtp {
32
33using boost::format;
34using std::flush;
35
37 degeneracy_ = options.get("degeneracy").as<double>();
39 numberofstatesA_ = options.get("levA").as<Index>();
40 numberofstatesB_ = options.get("levB").as<Index>();
41 // Optional TB output: monomer MO energies (KS and QP), raw H/S matrices,
42 // and diagnostics. Default false to keep XML output compact for KMC/rate
43 // workflows that only need the scalar effective couplings.
45 options.ifExistsReturnElseReturnDefault<bool>("output_tb", false);
46}
47
48// =============================================================================
49// WriteMatrixToProperty
50// Write an Eigen matrix as space-separated rows into an XML property node.
51// Each row is stored as attribute "row_N". Unit conversion applied if given.
52// =============================================================================
54 const std::string& name,
55 const Eigen::MatrixXd& mat,
56 double conversion) {
57 tools::Property& mat_prop = prop.add(name, "");
58 mat_prop.setAttribute("rows", mat.rows());
59 mat_prop.setAttribute("cols", mat.cols());
60 for (Index i = 0; i < mat.rows(); i++) {
61 std::string row_str;
62 for (Index j = 0; j < mat.cols(); j++) {
63 if (j > 0) row_str += " ";
64 row_str += (format("%1$1.6e") % (mat(i, j) * conversion)).str();
65 }
66 mat_prop.setAttribute("row_" + std::to_string(i), row_str);
67 }
68}
69
70// =============================================================================
71// WriteToProperty
72// Write the scalar effective coupling for one (levelA, levelB) pair.
73// Backward compatible: attribute names unchanged.
74// =============================================================================
76 const Orbitals& orbitalsA,
77 const Orbitals& orbitalsB, Index a,
78 Index b) const {
79 double J = getCouplingElement(a, b, orbitalsA, orbitalsB);
80 tools::Property& coupling = type_summary.add("coupling", "");
81 coupling.setAttribute("levelA", a);
82 coupling.setAttribute("levelB", b);
83 coupling.setAttribute("j", (format("%1$1.6e") % J).str());
84}
85
86// =============================================================================
87// Addoutput
88// Write all results to the XML property tree.
89// Extends the existing pairwise coupling output with:
90// - monomer_energies: isolated MO energies [eV] for TB site energies
91// - tb_matrices: raw H and S block matrices [H in eV, S dimensionless]
92// - diagnostics: minimum S eigenvalue as basis quality indicator
93// The existing <coupling> elements are unchanged for backward compatibility.
94// =============================================================================
96 const Orbitals& orbitalsA,
97 const Orbitals& orbitalsB) const {
98 tools::Property& dftcoupling = type_summary.add(Identify(), "");
99 dftcoupling.setAttribute("homoA", orbitalsA.getHomo());
100 dftcoupling.setAttribute("homoB", orbitalsB.getHomo());
101
102 // helper lambda: write one carrier type (hole or electron) into a
103 // property node, including existing pairwise couplings, monomer energies
104 // (KS always, QPpert when available), raw TB matrices, and diagnostics.
105 auto WriteCarrier = [&](tools::Property& carrier_summary, Index start_a,
106 Index end_a, Index start_b, Index end_b,
107 const Eigen::MatrixXd& JAB_dimer,
108 const Eigen::MatrixXd& S_AxB,
109 const Eigen::VectorXd& moEnA_KS,
110 const Eigen::VectorXd& moEnB_KS,
111 const Eigen::VectorXd& moEnA_QP,
112 const Eigen::VectorXd& moEnB_QP, double min_S_eval) {
113 // --- existing pairwise effective couplings (backward compatible) ---
114 for (Index a = start_a; a <= end_a; ++a) {
115 for (Index b = start_b; b <= end_b; ++b) {
116 WriteToProperty(carrier_summary, orbitalsA, orbitalsB, a, b);
117 }
118 }
119
120 // --- TB output: monomer energies, raw matrices, diagnostics ---
121 // Only written when output_tb_ = true. For KMC/rate workflows that only
122 // need scalar couplings, leave output_tb_ = false to keep XML compact.
123 if (output_tb_) {
124 // Monomer MO energies
125 // eV_KS: Kohn-Sham DFT eigenvalue (always present)
126 // eV_QP: QPpert quasiparticle energy (only when GW was run)
127 {
128 bool hasQP_A = (moEnA_QP.size() == moEnA_KS.size());
129 bool hasQP_B = (moEnB_QP.size() == moEnB_KS.size());
130
131 tools::Property& mono_prop =
132 carrier_summary.add("monomer_energies", "");
133 mono_prop.setAttribute("has_qp",
134 (hasQP_A && hasQP_B) ? "true" : "false");
135
136 tools::Property& propA = mono_prop.add("fragmentA", "");
137 for (Index i = 0; i < moEnA_KS.size(); i++) {
138 tools::Property& e = propA.add("mo", "");
139 e.setAttribute("level", start_a + i);
140 e.setAttribute("eV_KS", (format("%1$1.6e") % moEnA_KS(i)).str());
141 if (hasQP_A) {
142 e.setAttribute("eV_QP", (format("%1$1.6e") % moEnA_QP(i)).str());
143 }
144 }
145 tools::Property& propB = mono_prop.add("fragmentB", "");
146 for (Index i = 0; i < moEnB_KS.size(); i++) {
147 tools::Property& e = propB.add("mo", "");
148 e.setAttribute("level", start_b + i);
149 e.setAttribute("eV_KS", (format("%1$1.6e") % moEnB_KS(i)).str());
150 if (hasQP_B) {
151 e.setAttribute("eV_QP", (format("%1$1.6e") % moEnB_QP(i)).str());
152 }
153 }
154 }
155
156 // Raw TB matrices (H in eV, S dimensionless)
157 {
158 Index levA_range = moEnA_KS.size();
159 Index levB_range = moEnB_KS.size();
160 tools::Property& tb_prop = carrier_summary.add("tb_matrices", "");
161 tb_prop.setAttribute("n_A", levA_range);
162 tb_prop.setAttribute("n_B", levB_range);
163
164 WriteMatrixToProperty(tb_prop, "H_AA",
165 JAB_dimer.topLeftCorner(levA_range, levA_range),
167 WriteMatrixToProperty(tb_prop, "S_AA",
168 S_AxB.topLeftCorner(levA_range, levA_range));
170 tb_prop, "H_BB",
171 JAB_dimer.bottomRightCorner(levB_range, levB_range),
173 WriteMatrixToProperty(tb_prop, "S_BB",
174 S_AxB.bottomRightCorner(levB_range, levB_range));
175 WriteMatrixToProperty(tb_prop, "H_AB",
176 JAB_dimer.topRightCorner(levA_range, levB_range),
178 WriteMatrixToProperty(tb_prop, "S_AB",
179 S_AxB.topRightCorner(levA_range, levB_range));
180 }
181
182 // Basis diagnostics
183 {
184 tools::Property& diag_prop = carrier_summary.add("diagnostics", "");
185 diag_prop.setAttribute("min_S_eigenvalue",
186 (format("%1$1.6e") % min_S_eval).str());
187 diag_prop.setAttribute("basis_ok",
188 (min_S_eval > 0.01) ? "true" : "false");
189 }
190 } // output_tb_
191 };
192
193 // --- hole block ---
194 tools::Property& hole_summary = dftcoupling.add("hole", "");
195 WriteCarrier(hole_summary, Range_orbA.first, orbitalsA.getHomo(),
196 Range_orbB.first, orbitalsB.getHomo(), JAB_dimer_hole_,
200
201 // --- electron block ---
202 tools::Property& electron_summary = dftcoupling.add("electron", "");
203 WriteCarrier(electron_summary, orbitalsA.getLumo(),
204 Range_orbA.first + Range_orbA.second - 1, orbitalsB.getLumo(),
205 Range_orbB.first + Range_orbB.second - 1, JAB_dimer_elec_,
209}
210
212 const Orbitals& orbital, Index numberofstates) const {
213 const Eigen::VectorXd& MOEnergies = orbital.MOs().eigenvalues();
214 if (std::abs(MOEnergies(orbital.getHomo()) - MOEnergies(orbital.getLumo())) <
215 degeneracy_) {
216 throw std::runtime_error(
217 "Homo Lumo Gap is smaller than degeneracy. "
218 "Either your degeneracy is too large or your Homo and Lumo are "
219 "degenerate");
220 }
221
222 Index minimal = orbital.getHomo() - numberofstates + 1;
223 Index maximal = orbital.getLumo() + numberofstates - 1;
224
225 std::vector<Index> deg_min = orbital.CheckDegeneracy(minimal, degeneracy_);
226 minimal = *std::min_element(deg_min.begin(), deg_min.end());
227
228 std::vector<Index> deg_max = orbital.CheckDegeneracy(maximal, degeneracy_);
229 maximal = *std::max_element(deg_max.begin(), deg_max.end());
230
231 std::pair<Index, Index> result;
232 result.first = minimal; // start index
233 result.second = maximal - minimal + 1; // size
234
235 return result;
236}
237
239 const Orbitals& orbitalsA,
240 const Orbitals& orbitalsB) const {
241 Index levelsA = Range_orbA.second;
242 if (degeneracy_ != 0) {
243 std::vector<Index> list_levelsA =
244 orbitalsA.CheckDegeneracy(levelA, degeneracy_);
245 std::vector<Index> list_levelsB =
246 orbitalsB.CheckDegeneracy(levelB, degeneracy_);
247
248 double JAB_sq = 0;
249 for (Index iA : list_levelsA) {
250 Index indexA = iA - Range_orbA.first;
251 for (Index iB : list_levelsB) {
252 Index indexB = iB - Range_orbB.first + levelsA;
253 double JAB_one_level = JAB(indexA, indexB);
254 JAB_sq += JAB_one_level * JAB_one_level;
255 }
256 }
257 return std::sqrt(JAB_sq /
258 double(list_levelsA.size() * list_levelsB.size())) *
260 } else {
261 Index indexA = levelA - Range_orbA.first;
262 Index indexB = levelB - Range_orbB.first + levelsA;
263 return JAB(indexA, indexB) * tools::conv::hrt2ev;
264 }
265}
266
267// =============================================================================
268// CalculateCouplings
269// Computes the Lowdin-orthogonalized effective coupling matrix JAB, and also
270// stores the raw (pre-Lowdin) projected Fock matrix and overlap for each
271// carrier type, along with isolated monomer MO energies, for TB use.
272// =============================================================================
274 const Orbitals& orbitalsB,
275 const Orbitals& orbitalsAB) {
276
277 XTP_LOG(Log::error, *pLog_) << "Calculating electronic couplings" << flush;
278
279 CheckAtomCoordinates(orbitalsA, orbitalsB, orbitalsAB);
280
281 Index basisA = orbitalsA.getBasisSetSize();
282 Index basisB = orbitalsB.getBasisSetSize();
283
284 if ((basisA == 0) || (basisB == 0)) {
285 throw std::runtime_error("Basis set size is not stored in monomers");
286 }
287
290
291 Index levelsA = Range_orbA.second;
292 Index levelsB = Range_orbB.second;
293
295 << "Levels:Basis A[" << levelsA << ":" << basisA << "]"
296 << " B[" << levelsB << ":" << basisB << "]" << flush;
297
298 if ((levelsA == 0) || (levelsB == 0)) {
299 throw std::runtime_error(
300 "No information about number of occupied/unoccupied levels is stored");
301 }
302
303 // --- project monomer MOs onto dimer orbital basis ---
304 auto MOsA = orbitalsA.MOs().eigenvectors().middleCols(Range_orbA.first,
305 Range_orbA.second);
306 auto MOsB = orbitalsB.MOs().eigenvectors().middleCols(Range_orbB.first,
307 Range_orbB.second);
308
309 XTP_LOG(Log::info, *pLog_) << "Calculating overlap matrix for basisset: "
310 << orbitalsAB.getDFTbasisName() << flush;
311
312 Eigen::MatrixXd overlap =
313 CalculateOverlapMatrix(orbitalsAB) * orbitalsAB.MOs().eigenvectors();
314
316 << "Projecting monomers onto dimer orbitals" << flush;
317 Eigen::MatrixXd A_AB = MOsA.transpose() * overlap.topRows(basisA);
318 Eigen::MatrixXd B_AB = MOsB.transpose() * overlap.bottomRows(basisB);
319
320 Eigen::VectorXd mag_A = A_AB.rowwise().squaredNorm();
321 if (mag_A.any() < 0.95) {
323 << "\nWarning: "
324 << "Projection of orbitals of monomer A on dimer is insufficient,mag="
325 << mag_A.minCoeff() << flush;
326 }
327 Eigen::VectorXd mag_B = B_AB.rowwise().squaredNorm();
328 if (mag_B.any() < 0.95) {
330 << "\nWarning: "
331 << "Projection of orbitals of monomer B on dimer is insufficient,mag="
332 << mag_B.minCoeff() << flush;
333 }
334
335 // --- stack projected MOs into combined basis ---
336 Eigen::MatrixXd psi_AxB_dimer_basis(levelsA + levelsB, A_AB.cols());
337 psi_AxB_dimer_basis.topRows(levelsA) = A_AB;
338 psi_AxB_dimer_basis.bottomRows(levelsB) = B_AB;
339
340 // --- full projected Fock matrix and overlap (all MOs combined) ---
342 << "Projecting the Fock matrix onto the dimer basis" << flush;
343 Eigen::MatrixXd JAB_dimer_full = psi_AxB_dimer_basis *
344 orbitalsAB.MOs().eigenvalues().asDiagonal() *
345 psi_AxB_dimer_basis.transpose();
346
347 XTP_LOG(Log::info, *pLog_) << "Constructing Overlap matrix" << flush;
348 Eigen::MatrixXd S_AxB_full =
349 psi_AxB_dimer_basis * psi_AxB_dimer_basis.transpose();
350
351 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(S_AxB_full);
352 Eigen::MatrixXd Sm1 = es.operatorInverseSqrt();
353 XTP_LOG(Log::info, *pLog_) << "Smallest eigenvalue of overlap matrix is "
354 << es.eigenvalues()(0) << flush;
355
356 // Lowdin-orthogonalized effective coupling (existing, unchanged)
357 JAB = Sm1 * JAB_dimer_full * Sm1;
358
359 // -----------------------------------------------------------------------
360 // New: store raw matrices and monomer energies per carrier type.
361 //
362 // The combined basis is ordered [A_occ, ..., A_unocc, B_occ, ..., B_unocc]
363 // since Range_orbA and Range_orbB each span HOMO-n to LUMO+n.
364 //
365 // For TB purposes we want separate hole and electron sub-blocks.
366 // Within the full (levelsA + levelsB) basis:
367 // hole A: rows/cols [0, holesA)
368 // electron A: rows/cols [holesA, levelsA)
369 // hole B: rows/cols [levelsA, levelsA+holesB)
370 // electron B: rows/cols [levelsA+holesB, levelsA+levelsB)
371 // where holesA = homoA - Range_orbA.first + 1, etc.
372 // -----------------------------------------------------------------------
373
374 Index homoA_idx = orbitalsA.getHomo();
375 Index homoB_idx = orbitalsB.getHomo();
376
377 // Number of hole and electron states per fragment within the range
378 Index holesA = homoA_idx - Range_orbA.first + 1;
379 Index elecsA = levelsA - holesA;
380 Index holesB = homoB_idx - Range_orbB.first + 1;
381 Index elecsB = levelsB - holesB;
382
383 // Permutation to reorder [A_occ, A_unocc, B_occ, B_unocc] into
384 // [A_occ, B_occ] for holes and [A_unocc, B_unocc] for electrons.
385 // Build index vectors for each block.
386 std::vector<Index> hole_idx, elec_idx;
387 for (Index i = 0; i < holesA; i++) hole_idx.push_back(i);
388 for (Index i = 0; i < holesB; i++) hole_idx.push_back(levelsA + i);
389 for (Index i = holesA; i < levelsA; i++) elec_idx.push_back(i);
390 for (Index i = holesB; i < levelsB; i++) elec_idx.push_back(levelsA + i);
391
392 // Extract hole sub-block
393 Index nh = hole_idx.size();
394 Eigen::MatrixXd JAB_hole(nh, nh), S_hole(nh, nh);
395 for (Index i = 0; i < nh; i++) {
396 for (Index j = 0; j < nh; j++) {
397 JAB_hole(i, j) = JAB_dimer_full(hole_idx[i], hole_idx[j]);
398 S_hole(i, j) = S_AxB_full(hole_idx[i], hole_idx[j]);
399 }
400 }
401
402 // Extract electron sub-block
403 Index ne = elec_idx.size();
404 Eigen::MatrixXd JAB_elec(ne, ne), S_elec(ne, ne);
405 for (Index i = 0; i < ne; i++) {
406 for (Index j = 0; j < ne; j++) {
407 JAB_elec(i, j) = JAB_dimer_full(elec_idx[i], elec_idx[j]);
408 S_elec(i, j) = S_AxB_full(elec_idx[i], elec_idx[j]);
409 }
410 }
411
412 // Store raw matrices
413 JAB_dimer_hole_ = JAB_hole;
414 S_AxB_hole_ = S_hole;
415 JAB_dimer_elec_ = JAB_elec;
416 S_AxB_elec_ = S_elec;
417
418 // Minimum S eigenvalues per carrier type
419 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es_h(S_hole);
420 min_S_eigenvalue_hole_ = es_h.eigenvalues()(0);
421 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es_e(S_elec);
422 min_S_eigenvalue_elec_ = es_e.eigenvalues()(0);
423
425 << "Smallest S eigenvalue hole/elec: " << min_S_eigenvalue_hole_ << " / "
426 << min_S_eigenvalue_elec_ << flush;
427
428 // -----------------------------------------------------------------------
429 // Monomer MO energies — KS and QPpert (if available)
430 //
431 // KS energies: always present, directly from mos_.eigenvalues().
432 //
433 // QPpert energies: present only when a GW calculation was run on the
434 // monomer. QPpert_energies_ is indexed over the GW window [qpmin, qpmax],
435 // which must contain the DFT coupling range [Range_orbX.first, ..] for
436 // the QP energies to be valid for our MOs. We verify this and fall back
437 // to empty vectors (written as absent from the XML) if the window does
438 // not cover the required range.
439 // -----------------------------------------------------------------------
440
441 // Helper lambda: extract QPpert energies for a given MO range,
442 // returning an empty vector if GW is unavailable or the window
443 // does not cover the requested range.
444 auto ExtractQPEnergies = [&](const Orbitals& orb, Index mo_start,
445 Index n_mos) -> Eigen::VectorXd {
446 if (!orb.hasQPpert()) return Eigen::VectorXd{};
447 Index qpmin = orb.getGWAmin();
448 Index qpmax = orb.getGWAmax();
449 if (mo_start < qpmin || mo_start + n_mos - 1 > qpmax) {
451 << TimeStamp() << " WARNING: QPpert window [" << qpmin << "," << qpmax
452 << "] does not fully cover MO range [" << mo_start << ","
453 << mo_start + n_mos - 1 << "] -- QP energies omitted for this range"
454 << flush;
455 return Eigen::VectorXd{};
456 }
457 // QPpert_energies_ is indexed from qpmin, so offset accordingly
458 return orb.QPpertEnergies().segment(mo_start - qpmin, n_mos) *
460 };
461
462 // KS energies — hole MOs: Range_orbA.first .. homoA
464 orbitalsA.MOs().eigenvalues().segment(Range_orbA.first, holesA) *
467 orbitalsB.MOs().eigenvalues().segment(Range_orbB.first, holesB) *
469
470 // KS energies — electron MOs: lumo .. lumo + elecsX - 1
472 orbitalsA.MOs().eigenvalues().segment(orbitalsA.getLumo(), elecsA) *
475 orbitalsB.MOs().eigenvalues().segment(orbitalsB.getLumo(), elecsB) *
477
478 // QPpert energies — extracted over the same ranges; empty if unavailable
479 moEnergiesA_hole_QP_ = ExtractQPEnergies(orbitalsA, Range_orbA.first, holesA);
480 moEnergiesB_hole_QP_ = ExtractQPEnergies(orbitalsB, Range_orbB.first, holesB);
482 ExtractQPEnergies(orbitalsA, orbitalsA.getLumo(), elecsA);
484 ExtractQPEnergies(orbitalsB, orbitalsB.getLumo(), elecsB);
485
486 if (orbitalsA.hasQPpert()) {
488 << TimeStamp() << " QPpert energies available for fragment A" << flush;
489 }
490 if (orbitalsB.hasQPpert()) {
492 << TimeStamp() << " QPpert energies available for fragment B" << flush;
493 }
494
495 XTP_LOG(Log::error, *pLog_) << "Done with electronic couplings" << flush;
496}
497
498} // namespace xtp
499} // namespace votca
const Eigen::VectorXd & eigenvalues() const
Definition eigensystem.h:30
const Eigen::MatrixXd & eigenvectors() const
Definition eigensystem.h:33
class to manage program options with xml serialization functionality
Definition property.h:55
Property & add(const std::string &key, const std::string &value)
add a new property to structure
Definition property.cc:108
Property & get(const std::string &key)
get existing property
Definition property.cc:79
T as() const
return value as type
Definition property.h:283
T ifExistsReturnElseReturnDefault(const std::string &key, T defaultvalue) const
Definition property.h:321
void setAttribute(const std::string &attribute, const T &value)
set an attribute
Definition property.h:314
Eigen::MatrixXd CalculateOverlapMatrix(const Orbitals &orbitalsAB) const
void CheckAtomCoordinates(const Orbitals &orbitalsA, const Orbitals &orbitalsB, const Orbitals &orbitalsAB) const
void WriteToProperty(tools::Property &type_summary, const Orbitals &orbitalsA, const Orbitals &orbitalsB, Index a, Index b) const
Eigen::MatrixXd JAB_dimer_elec_
Definition dftcoupling.h:92
Eigen::VectorXd moEnergiesA_hole_QP_
Eigen::MatrixXd JAB_dimer_hole_
Definition dftcoupling.h:90
std::pair< Index, Index > Range_orbA
std::pair< Index, Index > DetermineRangeOfStates(const Orbitals &orbital, Index numberofstates) const
void Initialize(tools::Property &) override
Eigen::VectorXd moEnergiesB_elec_KS_
double getCouplingElement(Index levelA, Index levelB, const Orbitals &orbitalsA, const Orbitals &orbitalsB) const
Eigen::MatrixXd S_AxB_hole_
Definition dftcoupling.h:91
Eigen::VectorXd moEnergiesB_elec_QP_
void Addoutput(tools::Property &type_summary, const Orbitals &orbitalsA, const Orbitals &orbitalsB) const override
static void WriteMatrixToProperty(tools::Property &prop, const std::string &name, const Eigen::MatrixXd &mat, double conversion=1.0)
Write an Eigen matrix as rows of space-separated values into an XML property node....
Eigen::VectorXd moEnergiesB_hole_KS_
Eigen::VectorXd moEnergiesA_elec_KS_
Eigen::VectorXd moEnergiesA_hole_KS_
Eigen::VectorXd moEnergiesA_elec_QP_
std::pair< Index, Index > Range_orbB
void CalculateCouplings(const Orbitals &orbitalsA, const Orbitals &orbitalsB, const Orbitals &orbitalsAB) override
Eigen::VectorXd moEnergiesB_hole_QP_
Eigen::MatrixXd S_AxB_elec_
Definition dftcoupling.h:93
std::string Identify() const
Definition dftcoupling.h:40
Eigen::MatrixXd JAB
Definition dftcoupling.h:79
Container for molecular orbitals and derived one-particle data.
Definition orbitals.h:47
Index getHomo() const
Return the default HOMO index used by spin-agnostic callers.
Definition orbitals.h:107
const Eigen::VectorXd & QPpertEnergies() const
Return read-only access to perturbative quasiparticle energies.
Definition orbitals.h:441
std::vector< Index > CheckDegeneracy(Index level, double energy_difference) const
Definition orbitals.cc:56
bool hasQPpert() const
Report whether perturbative quasiparticle energies are available.
Definition orbitals.h:436
Index getBasisSetSize() const
Return the number of AO basis functions in the DFT basis.
Definition orbitals.h:72
Index getGWAmin() const
Return the lower GW orbital index.
Definition orbitals.h:361
const tools::EigenSystem & MOs() const
Return read-only access to alpha/restricted molecular orbitals.
Definition orbitals.h:192
Index getGWAmax() const
Return the upper GW orbital index.
Definition orbitals.h:364
const std::string & getDFTbasisName() const
Return the DFT basis-set name.
Definition orbitals.h:304
Index getLumo() const
Return the default LUMO index used by spin-agnostic callers.
Definition orbitals.h:105
Timestamp returns the current time as a string Example: cout << TimeStamp().
Definition logger.h:224
#define XTP_LOG(level, log)
Definition logger.h:40
const double ev2hrt
Definition constants.h:54
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