29#include <nda/algorithms.hpp>
30#include <nda/linalg/eigh.hpp>
37namespace triqs::lattice {
39 using namespace arrays;
41 void tight_binding::check_hoppings() {
43 if (displ_vec_.size() != overlap_mat_vec_.size())
TRIQS_RUNTIME_ERROR <<
" Number of displacements != Number of matrices";
44 for (
int i = 0; i < displ_vec_.size(); ++i) {
45 if (displ_vec_[i].
size() != bl_.ndim())
46 TRIQS_RUNTIME_ERROR <<
"displacement of incorrect size : got " << displ_vec_[i].size() <<
"instead of " << bl_.ndim();
47 if (first_dim(overlap_mat_vec_[i]) !=
n_orbitals())
49 if (second_dim(overlap_mat_vec_[i]) !=
n_orbitals())
54 for (
int j = 0; j < displ_vec_.size(); ++j) {
55 if (displ_vec_[i] == -displ_vec_[j]) {
57 if (max_element(abs(overlap_mat_vec_[i] - dagger(overlap_mat_vec_[j]))) > 1.e-12)
58 TRIQS_RUNTIME_ERROR <<
"hopping matrix of displacement " << displ_vec_[i] << overlap_mat_vec_[i]
59 <<
"\nis not hermitian conjugate of matrix for displacement " << displ_vec_[j] << overlap_mat_vec_[j] <<
"\n";
63 if (not found)
TRIQS_RUNTIME_ERROR <<
"opposite hopping vector of " << displ_vec_[i] <<
" cannot be found";
81 std::pair<array<double, 1>, array<double, 2>>
dos(
tight_binding const &TB,
int nkpts,
int neps) {
85 int norb =
static_cast<int>(TB.
lattice().n_orbitals());
87 array<double, 1> tempeval(norb);
88 array<dcomplex, 3> evec(norb, norb, grid.
size());
89 array<double, 2> eval(norb, grid.
size());
91 for (; grid; ++grid) {
92 double ee = real(TB.
fourier((*grid)(range(ndim)))(0, 0));
93 eval(0, grid.
index()) = ee;
94 evec(0, 0, grid.
index()) = 1;
97 for (; grid; ++grid) {
99 array_view<double, 1> eval_sl = eval(range::all, grid.
index());
100 array_view<dcomplex, 2> evec_sl = evec(range::all, range::all, grid.
index());
101 std::tie(eval_sl, evec_sl) = nda::linalg::eigh(TB.
fourier((*grid)(range(ndim))));
106 array<double, 1> epsilon(neps);
107 double epsmax = max_element(eval);
108 double epsmin = min_element(eval);
109 double deps = (epsmax - epsmin) / neps;
111 for (
int i = 0; i < neps; ++i) epsilon(i) = epsmin + (i + 0.5) * deps;
116 array<double, 2> rho(neps, norb);
118 for (
int l = 0; l < norb; l++) {
119 for (
int j = 0; j < grid.
size(); j++) {
120 int a = int((eval(l, j) - epsmin) / deps);
121 if (a ==
int(neps)) a = a - 1;
122 for (
int k = 0; k < norb; k++) { rho(a, k) += real(conj(evec(k, l, j)) * evec(k, l, j)); }
125 rho /= grid.
size() * deps;
126 return std::make_pair(epsilon, rho);
131 std::pair<array<double, 1>, array<double, 1>> dos_patch(tight_binding
const &TB,
const array<double, 2> &triangles,
int neps,
int ndiv) {
139 int ntri =
static_cast<int>(triangles.shape(0)) / 3;
140 array<double, 1>
dos(neps);
143 int ndim = TB.lattice().ndim();
146 if (triangles.shape(1) != ndim)
TRIQS_RUNTIME_ERROR <<
"dos_patch : the second dimension of the 'triangle' array in not " << ndim;
149 int nk = ntri * ndiv * ndiv;
151 double epsmax = -100000, epsmin = 100000;
152 array<dcomplex, 2> thop(1, 1);
153 array<double, 1> energ(nk), weight(nk);
157 array<double, 1> a(ndim), b(ndim), c(ndim), g(ndim), rv(ndim);
162 for (
int tri = 0; tri < ntri; tri++) {
163 a = triangles(pt, range::all);
165 b = triangles(pt, range::all);
167 c = triangles(pt, range::all);
169 g = ((a + b +
c) / 3.0 - a) /
double(ndiv);
173 double area = abs(0.5 * ((b(0) - a(0)) * (
c(1) - a(1)) - (b(1) - a(1)) * (
c(0) - a(0))) / (ndiv * ndiv));
175 for (
int i = 0; i < ndiv; i++) {
176 s = i / double(ndiv);
177 for (
int j = 0; j < ndiv - i; j++) {
178 t = j / double(ndiv);
179 for (
int k = 0; k < 2; k++) {
181 rv = a + s * (b - a) + t * (c - a) + (k + 1.0) * g;
183 if (k == 0 || j < ndiv - i - 1) {
185 energ(k_index) =
real(TB.fourier(rv)(0, 0));
188 weight(k_index) = area;
189 if (energ(k_index) > epsmax) epsmax = energ(k_index);
190 if (energ(k_index) < epsmin) epsmin = energ(k_index);
198 assert(k_index == nk);
201 array<double, 1> epsilon(neps);
202 double deps = (epsmax - epsmin) / neps;
203 for (
int i = 0; i < neps; ++i) epsilon(i) = epsmin + i / (neps - 1.0) * (epsmax - epsmin);
208 for (
int j = 0; j < nk; j++) {
209 ind = int((energ(j) - epsmin) / deps);
210 if (ind ==
int(neps)) ind--;
211 dos(ind) += weight(j);
214 return {std::move(epsilon), std::move(
dos)};
218 array<dcomplex, 3> hopping_stack(
tight_binding const &TB, nda::array_const_view<double, 2> k_stack) {
219 array<dcomplex, 3> res(TB.n_orbitals(), TB.n_orbitals(), k_stack.shape(1));
220 for (
int i = 0; i < k_stack.shape(1); ++i) res(range::all, range::all, i) = TB.fourier(k_stack(range::all, i));
225 array<double, 2> energies_on_bz_path(
tight_binding const &TB,
k_t const &K1,
k_t const &K2,
int n_pts) {
226 int norb =
static_cast<int>(TB.lattice().n_orbitals());
227 int ndim = TB.lattice().ndim();
228 array<double, 2> eval(norb, n_pts);
229 k_t dk = (K2 - K1) /
double(n_pts), k = K1;
230 for (
int i = 0; i < n_pts; ++i, k += dk) { eval(range::all, i) = nda::linalg::eigvalsh(TB.fourier(k(range(ndim)))()); }
235 array<dcomplex, 3> energy_matrix_on_bz_path(
tight_binding const &TB,
k_t const &K1,
k_t const &K2,
int n_pts) {
236 int norb =
static_cast<int>(TB.lattice().n_orbitals());
237 int ndim = TB.lattice().ndim();
238 array<dcomplex, 3> eval(norb, norb, n_pts);
239 k_t dk = (K2 - K1) /
double(n_pts), k = K1;
240 for (
int i = 0; i < n_pts; ++i, k += dk) { eval(range::all, range::all, i) = TB.fourier(k(range(ndim)))(); }
245 array<double, 2> energies_on_bz_grid(
tight_binding const &TB,
int n_pts) {
247 int norb =
static_cast<int>(TB.lattice().n_orbitals());
248 int ndim = TB.lattice().ndim();
250 array<double, 2> eval(norb, grid.size());
251 for (; grid; ++grid) { eval(range::all, grid.index()) = nda::linalg::eigvalsh(TB.fourier((*grid)(range(ndim)))()); }
int size() const
Get the total number of blocks.
int ndim() const
Get the number of dimensions of the Bravais lattice.
Forward iterator generating uniformly-spaced points in the d-dimensional unit cube .
int size() const
Total number of grid points, equal to (trailing factors are 1 for dim < 3).
int index() const
Linear index of the current grid point in the iteration order (x fastest, then y, then z).
Tight-binding Hamiltonian on a Bravais lattice with fully localised orbitals.
auto fourier(K const &k) const
Compute the Fourier transform for a given momentum vector (or array of momentum vectors).
long n_orbitals() const
Number of orbitals (also the size of the Bloch Hamiltonian matrix ).
bravais_lattice const & lattice() const
Get the underlying Bravais lattice.
tight_binding(bravais_lattice bl, std::vector< nda::vector< long > > displ_vec, std::vector< nda::matrix< dcomplex > > overlap_mat_vec)
Construct a tight-binding Hamiltonian on a given Bravais lattice from explicit displacement and overl...
auto const & displ_vec() const
Get the list of displacement vectors, in units of the lattice basis vectors.
auto const & overlap_mat_vec() const
Get the list of overlap (hopping) matrices, aligned with the displacement vectors.
TRIQS exception hierarchy and related macros.
Provides a forward iterator generating a regular grid of points in a cuboid.
G::regular_type::real_t real(G const &g)
Take the real part of a Green's function (no check), returning a new Green's function with a real tar...
nda::vector< double > k_t
Reciprocal space vector type.
std::pair< array< double, 1 >, array< double, 2 > > dos(tight_binding const &TB, int nkpts, int neps)
Compute the density of states of a tight-binding Hamiltonian on a regular k-grid.
many_body_operator_generic< T > c(IndexTypes... indices)
Create an annihilation operator .
#define TRIQS_RUNTIME_ERROR
Throw a triqs::runtime_error with the current source location.
Ordered dictionary mapping lattice displacements to hopping (overlap) matrices.
Provides a tight-binding Hamiltonian class for Bravais lattices and associated utilities.