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