33namespace triqs::atom_diag {
35 using namespace triqs::arrays;
37#define ATOM_DIAG atom_diag<Complex>
38#define ATOM_DIAG_R atom_diag<false>
39#define ATOM_DIAG_C atom_diag<true>
40#define ATOM_DIAG_T typename atom_diag<Complex>
46 template <
bool Complex,
typename ProcessTerm>
50 std::sort(excluded_states.begin(), excluded_states.end());
51 auto is_excluded = [&excluded_states](
int A,
int ia) {
52 return std::binary_search(excluded_states.begin(), excluded_states.end(), std::make_pair(A, ia));
56 std::vector<vector<double>> weights;
59 int n_sp = atom.n_subspaces();
60 for (
int A = 0; A < n_sp; ++A) {
61 int sp_dim = atom.get_subspace_dim(A);
62 weights.emplace_back(nda::zeros<double>(sp_dim));
63 for (
int ia = 0; ia < sp_dim; ++ia) {
64 double w = std::exp(-beta * atom.get_eigenvalue(A, ia));
70 for (
auto &w : weights)
w /= z;
72 auto const &fops = atom.get_fops();
76 for (
auto const &[block, bl_size] :
gf_struct) {
78 for (
auto inner_index1 : range(bl_size))
79 for (
auto inner_index2 : range(bl_size)) {
80 int n1 = fops[{block, inner_index1}];
81 int n2 = fops[{block, inner_index2}];
83 for (
int A = 0; A < n_sp; ++A) {
84 int B = atom.cdag_connection(n2, A);
85 if (B == -1 || atom.c_connection(n1, B) != A)
continue;
86 for (
int ia = 0; ia < atom.get_subspace_dim(A); ++ia) {
87 if (is_excluded(A, ia))
continue;
88 for (
int ib = 0; ib < atom.get_subspace_dim(B); ++ib) {
89 if (is_excluded(B, ib))
continue;
90 auto residue = (weights[A](ia) + weights[B](ib)) * atom.c_matrix(n1, B)(ia, ib) * atom.cdag_matrix(n2, A)(ib, ia);
91 auto Ea = atom.get_eigenvalue(A, ia);
92 auto Eb = atom.get_eigenvalue(B, ib);
94 if (std::abs(residue) < std::numeric_limits<double>::epsilon())
continue;
95 proc(bl, inner_index1, inner_index2, Eb - Ea, residue);
107 template <
bool Complex>
112 for (
auto const &[block, bl_size] :
gf_struct) { lehmann.emplace_back(bl_size, bl_size); }
115 auto fill = [&lehmann](
int bl,
int n1,
int n2,
double pole, ATOM_DIAG_T::scalar_t residue) { lehmann[bl](n1, n2).emplace_back(pole, residue); };
116 atomic_g_lehmann_impl(atom, beta,
gf_struct, excluded_states, fill);
126 template <
bool Complex,
typename T>
127 inline void check_lehmann_struct([[maybe_unused]]
gf_lehmann_t<Complex> const &lehmann, [[maybe_unused]] block_gf_view<T> g) {
129 assert(lehmann.size() == g.size());
131 for (
auto const &block : g) {
132 assert(block.target_shape() == lehmann[bl].shape());
141 template <
bool Complex,
typename T,
typename ProcessTerm>
143 check_lehmann_struct<Complex>(lehmann, g);
146 for (
auto &block : g) {
147 auto shape = block.target_shape();
148 for (
auto n1 : range(shape[0]))
149 for (
auto n2 : range(shape[1])) {
150 for (
auto const &term : lehmann[bl](n1, n2)) proc(bl, n1, n2, term.first, term.second);
161 return [
gf, beta](
int bl,
int n1,
int n2,
double pole, ATOM_DIAG_T::scalar_t residue)
mutable {
164 auto w = -residue / (pole > 0 ? (1 + std::exp(-beta * pole)) : (std::exp(beta * pole) + 1));
167 for (
auto tau : g.mesh()) g[tau] +=
w * (pole > 0 ? std::exp(-
double(tau) * pole) : std::exp((beta - double(tau)) * pole));
174 template <
bool Complex>
176 double beta = mesh.
beta();
178 fill_block_gf_from_lehmann<Complex>(g(), lehmann, make_term_proc<Complex>(beta, g()));
187 template <
bool Complex>
191 atomic_g_lehmann_impl(atom, beta,
gf_struct, excluded_states, make_term_proc<Complex>(beta, g()));
201 template <
bool Complex>
auto make_term_proc(block_gf_view<imfreq> gf) {
202 return [gf](
int bl,
int n1,
int n2,
double pole, ATOM_DIAG_T::scalar_t residue)
mutable {
206 for (
auto iw : g.mesh()) g[iw] += residue / (iw - pole);
215 fill_block_gf_from_lehmann<Complex>(g(), lehmann, make_term_proc<Complex>(g()));
224 template <
bool Complex>
227 atomic_g_lehmann_impl(atom, beta,
gf_struct, excluded_states, make_term_proc<Complex>(g()));
237 template <
bool Complex>
auto make_term_proc(
double beta, block_gf_view<legendre> gf) {
238 return [gf, beta](
int bl,
int n1,
int n2,
double pole, ATOM_DIAG_T::scalar_t residue)
mutable {
242 double x = beta * pole / 2;
243 double w = -beta / (2 * std::cosh(x));
244 for (
auto l : g.mesh()) {
245 g[l] += residue * w * std::sqrt(2 * l.index() + 1) * (l.index() % 2 == 0 ? 1 : std::copysign(1, -x))
254 template <
bool Complex>
256 double beta = mesh.
beta();
258 fill_block_gf_from_lehmann<Complex>(g(), lehmann, make_term_proc<Complex>(beta, g()));
267 template <
bool Complex>
270 atomic_g_lehmann_impl(atom, beta,
gf_struct, excluded_states, make_term_proc<Complex>(beta, g()));
280 template <
bool Complex>
auto make_term_proc(block_gf_view<refreq> gf,
double broadening) {
281 return [gf, broadening](
int bl,
int n1,
int n2,
double pole, ATOM_DIAG_T::scalar_t residue)
mutable {
285 for (
auto w : g.mesh()) g[w] += residue / (w + 1i * broadening - pole);
292 template <
bool Complex>
295 fill_block_gf_from_lehmann<Complex>(g(), lehmann, make_term_proc<Complex>(g(), broadening));
304 template <
bool Complex>
308 atomic_g_lehmann_impl(atom, beta,
gf_struct, excluded_states, make_term_proc<Complex>(g(), broadening));
311 template block_gf<refreq>
atomic_g_w(ATOM_DIAG_R
const &,
double,
gf_struct_t const &, std::pair<double, double>
const &,
int,
double,
313 template block_gf<refreq>
atomic_g_w(ATOM_DIAG_C
const &,
double,
gf_struct_t const &, std::pair<double, double>
const &,
int,
double,
gf_struct_t gf_struct() const
Get the block structure.
Backward-compatibility umbrella header pulling in the nda array library.
Provides a lightweight exact diagonalization solver for fermionic Hamiltonians.
Build the atomic Green's function from a solved diagonalization problem on different meshes.
A non-owning view of a block Green's function.
The owning block Green's function container.
A mutable, non-owning view of a Green's function.
The owning Green's function container.
double beta() const noexcept
Get the inverse temperature .
double beta() const noexcept
Get the inverse temperature .
Umbrella header for the Green's function library.
std::vector< matrix< gf_scalar_lehmann_t< Complex > > > gf_lehmann_t
Lehmann representation of a block matrix-valued Green's function.
std::vector< std::pair< int, int > > excluded_states_t
List of excluded eigenstates.
block_gf< legendre > atomic_g_l(gf_lehmann_t< Complex > const &lehmann, gf_struct_t const &gf_struct, legendre const &mesh)
Build the atomic Green's function in the Legendre basis from a precomputed Lehmann representation.
block_gf< refreq > atomic_g_w(gf_lehmann_t< Complex > const &lehmann, gf_struct_t const &gf_struct, refreq const &mesh, double broadening=0)
Build the atomic retarded Green's function on a real-frequency mesh from a precomputed Lehmann repres...
block_gf< imtime > atomic_g_tau(gf_lehmann_t< Complex > const &lehmann, gf_struct_t const &gf_struct, imtime const &mesh)
Build the atomic imaginary-time Green's function from a precomputed Lehmann representation.
block_gf< imfreq > atomic_g_iw(gf_lehmann_t< Complex > const &lehmann, gf_struct_t const &gf_struct, imfreq const &mesh)
Build the atomic Matsubara Green's function from a precomputed Lehmann representation.
gf_lehmann_t< Complex > atomic_g_lehmann(atom_diag< Complex > const &atom, double beta, gf_struct_t const &gf_struct, excluded_states_t excluded_states={})
Build the Lehmann representation of the atomic Green's function.
std::vector< std::pair< std::string, long > > gf_struct_t
Type describing the structure of a block Green's function.
auto slice_target_to_scalar(G &&g, Args &&...1)
Slice the target of a matrix-valued Green's function down to a scalar-valued one.
double mod_cyl_bessel_i(int n, double x)
Get the modified spherical bessel function of the first kind of order evaluated at .
constexpr nda::clef::placeholder< 3 > w
Placeholder for the frequency .
Provides Legendre polynomials and related functions.