Loading...
Searching...
No Matches
local_orbital.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * LocalOrbitalQuantumStateInterpolator — evaluates any model that is a
5 * local-orbital Hamiltonian: Bloch sum to H(k), then diagonalize.
6 *
7 * Named for the model it reads, not for the method that built it. Wannier
8 * functions, projected atomic orbitals and Shirley's optimal basis all produce
9 * an H(R) of exactly this shape, so they share this evaluator; a method that
10 * produces no Hamiltonian -- a Fourier star-function fit of the eigenvalues --
11 * gets its own file beside this one.
12 *
13 * It owns its Hamiltonian rather than referencing one, so an interpolator
14 * outlives whatever built it. That matters: the model is built inside the
15 * factory and the caller keeps only the interface.
16 *
17 * The eigenproblem is the dense generalized one the plane-wave side already
18 * solves for ultrasoft pseudopotentials, so it goes through the same
19 * SubspaceDiagonalizer rather than a second LAPACK wrapper. S(k) is the
20 * identity for an orthonormal basis, which the Hamiltonian returns for a model
21 * with no overlap blocks, and Wannier functions are orthonormal by
22 * construction.
23 */
24
25#include <map>
26#include <memory>
27#include <stdexcept>
28#include <string>
29#include <utility>
30#include <vector>
31
37
38namespace q3 {
39
41 public:
43 std::string method_description = "local-orbital")
44 : hamiltonian_(std::move(hamiltonian))
45 , method_description_(std::move(method_description))
46 , diagonalizer_(SubspaceDiagonalizerFactory::create(serial_execution_policy)) {}
47
48 [[nodiscard]] int number_of_bands() const override {
49 return hamiltonian_.number_of_orbitals();
50 }
51
52 [[nodiscard]] std::vector<Real> eigenvalues_at(const Vector3D& kpoint) const override {
53 const int dimension = hamiltonian_.number_of_orbitals();
54 std::vector<Complex> hamiltonian_at_kpoint = hamiltonian_.hamiltonian_at_kpoint(kpoint);
55 std::vector<Complex> overlap_at_kpoint = hamiltonian_.overlap_at_kpoint(kpoint);
56 std::vector<Real> eigenvalues(static_cast<std::size_t>(dimension), 0.0);
57 /// zhegv wants somewhere to put the vectors even when only values are read back.
58 std::vector<Complex> eigenvectors(static_cast<std::size_t>(dimension) * dimension,
59 Complex(0.0, 0.0));
60
61 const int status = diagonalizer_->solve(dimension,
62 hamiltonian_at_kpoint.data(),
63 overlap_at_kpoint.data(),
64 eigenvalues.data(),
65 eigenvectors.data());
66 if (status != 0) {
67 throw std::runtime_error(
68 "LocalOrbitalQuantumStateInterpolator::eigenvalues_at: the eigensolver failed with "
69 "status " +
70 std::to_string(status) +
71 "; a positive status above the basis size means the overlap S(k) is not positive "
72 "definite, i.e. the model's orbitals are linearly dependent at this k-point");
73 }
74 return eigenvalues;
75 }
76
77 [[nodiscard]] std::string description() const override {
78 return method_description_ + ": " + std::to_string(hamiltonian_.number_of_orbitals()) +
79 " orbitals on " + std::to_string(hamiltonian_.lattice_vectors().size()) +
80 " lattice vectors";
81 }
82
83 /**
84 * The total Bloch-sum weight. For a Hamiltonian from a k -> R transform it
85 * must equal the number of k-points the transform ran over (the
86 * Wigner-Seitz degeneracy identity), which is the one check on the model a
87 * consumer can make without knowing how it was built.
88 */
89 [[nodiscard]] std::map<std::string, Real> diagnostics() const override {
90 Real total_weight = 0.0;
91 for (const LocalOrbitalLatticeVector& vector : hamiltonian_.lattice_vectors()) {
92 total_weight += vector.bloch_sum_weight;
93 }
94 return {{TOTAL_BLOCH_SUM_WEIGHT, total_weight}};
95 }
96
97 /// The name that diagnostic goes by, which a results file gives a key of its own.
98 static constexpr const char* TOTAL_BLOCH_SUM_WEIGHT = "total_bloch_sum_weight";
99
100 /// The model itself, for diagnostics (decay of H(R), the R set) and tests.
101 [[nodiscard]] const LocalOrbitalHamiltonian& hamiltonian() const {
102 return hamiltonian_;
103 }
104
105 private:
106 inline static const execution::SerialExecutionPolicy serial_execution_policy{};
107
108 LocalOrbitalHamiltonian hamiltonian_;
109 std::string method_description_;
110 std::unique_ptr<SubspaceDiagonalizer> diagonalizer_;
111};
112
113} // namespace q3
int number_of_orbitals() const
Definition init.hpp:119
std::vector< Complex > overlap_at_kpoint(const Vector3D &kpoint) const
S(k) by the same Bloch sum, or the identity when the basis is orthonormal.
Definition init.hpp:149
const std::vector< LocalOrbitalLatticeVector > & lattice_vectors() const
Definition init.hpp:123
std::vector< Complex > hamiltonian_at_kpoint(const Vector3D &kpoint) const
Definition init.hpp:140
static constexpr const char * TOTAL_BLOCH_SUM_WEIGHT
The name that diagnostic goes by, which a results file gives a key of its own.
std::string description() const override
One line for logs: the method and the size of the model.
LocalOrbitalQuantumStateInterpolator(LocalOrbitalHamiltonian hamiltonian, std::string method_description="local-orbital")
int number_of_bands() const override
Number of eigenvalues returned per k-point.
const LocalOrbitalHamiltonian & hamiltonian() const
The model itself, for diagnostics (decay of H(R), the R set) and tests.
std::vector< Real > eigenvalues_at(const Vector3D &kpoint) const override
Ascending eigenvalues in Rydberg at one k-point in crystal coordinates.
std::map< std::string, Real > diagnostics() const override
double Real
std::complex< double > Complex
One lattice vector of the Hamiltonian's real-space domain.
Definition init.hpp:48