TRIQS/TRIQS 4.0.0
Researching Interacting Quantum Systems
Loading...
Searching...
No Matches
density.cpp
Go to the documentation of this file.
1// Copyright (c) 2013-2018 Commissariat à l'énergie atomique et aux énergies alternatives (CEA)
2// Copyright (c) 2013-2018 Centre national de la recherche scientifique (CNRS)
3// Copyright (c) 2018-2023 Simons Foundation
4// Copyright (c) 2023 Hugo U.R. Strand
5//
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You may obtain a copy of the License at
17// https://www.gnu.org/licenses/gpl-3.0.txt
18//
19// Authors: Michel Ferrero, Alexander Hampel, Olivier Parcollet, Hugo U. R. Strand, Nils Wentzell
20
25
26#include "./density.hpp"
27#include "./functions2.hpp"
28#include "../gf/defs.hpp"
30#include "../gf/targets.hpp"
31#include "../../mesh/imfreq.hpp"
33#include "../../mesh/refreq.hpp"
36
37#include <cmath>
38#include <iostream>
39#include <string>
40
41namespace triqs::gfs {
42
43 using nda::array;
44
45 //-------------------------------------------------------
46 // For Imaginary Matsubara Frequency functions
47 // ------------------------------------------------------
48
49 nda::matrix<dcomplex> density(gf_const_view<mesh::imfreq> g, array_const_view<dcomplex, 3> known_moments) {
50
51 if (g.mesh().positive_only())
52 TRIQS_RUNTIME_ERROR << "density is only implemented for g(i omega_n) with full mesh (positive and negative frequencies)";
53
54 nda::array_const_view<dcomplex, 3> mom_123;
55
56 // Assume vanishing 0th moment in tail fit
57 if (known_moments.is_empty()) return density(g, make_zero_tail(g, 1));
58
59 double _abs_tail0 = max_element(abs(known_moments(0, range::all, range::all)));
60 TRIQS_ASSERT2((_abs_tail0 < 1e-8),
61 "ERROR: Density implementation requires vanishing 0th moment\n error is :" + std::to_string(_abs_tail0) + "\n");
62
63 if (known_moments.shape()[0] < 4) {
64 auto [tail, error] = fit_tail(g, known_moments);
65 TRIQS_ASSERT2((error < 1e-2),
66 "ERROR: High frequency moments have an error greater than 1e-2.\n Error = " + std::to_string(error)
67 + "\n Please make sure you treat the constant offset analytically!\n");
68 if (error > 1e-4)
69 std::cerr << "WARNING: High frequency moments have an error greater than 1e-4.\n Error = " << error
70 << "\n Please make sure you treat the constant offset analytically!\n";
71 TRIQS_ASSERT2((first_dim(tail) > 3), "ERROR: Density implementation requires at least a proper 3rd high-frequency moment\n");
72 return density(g, tail);
73 } else
74 mom_123.rebind(known_moments(range(1, 4), range::all, range::all));
75
76 auto sh = g.target_shape();
77 long N1 = sh[0], N2 = sh[1];
78 nda::matrix<dcomplex> res(sh);
79 auto beta = g.mesh().beta();
80
81 auto S = g.mesh().statistic();
82 double b1 = 0, b2 = 0, b3 = 0; // pole location for tail model
83 double xi = 0; // +1, -1 for boson/fermion
84
85 if (S == Fermion) {
86 xi = -1.;
87 b1 = 0;
88 b2 = 1;
89 b3 = -1;
90 } else if (S == Boson) {
91 xi = 1.;
92 b1 = -1.;
93 b2 = 1.;
94 b3 = 1. / 2.;
95 } else
96 TRIQS_RUNTIME_ERROR << "ERROR: Unknown statistic in density\n";
97
98 // exact expression for sum over Matsubara frequencies for a single pole
99 // located at b with amplitude a
100 auto F = [&beta, &xi](dcomplex a, double b) { return xi * a / (-xi + exp(-beta * b)); };
101
102 for (int n1 = 0; n1 < N1; n1++)
103 for (int n2 = n1; n2 < N2; n2++) {
104 dcomplex m1 = mom_123(0, n1, n2), m2 = mom_123(1, n1, n2), m3 = mom_123(2, n1, n2);
105
106 // inverse of the Vandermonte matrix
107 //
108 // V =
109 // [ 1, 1, 1 ]
110 // [ b1, b2, b3 ]
111 // [ b1^2, b2^2, b3^2 ]
112 //
113 // V * a = m => a = V^{-1} * m
114
115 dcomplex a1, a2, a3; // amplitudes for each pole in tail model
116
117 if (S == Fermion) {
118 a1 = m1 - m3;
119 a2 = (m2 + m3) / 2;
120 a3 = (m3 - m2) / 2;
121 } else if (S == Boson) {
122 a1 = m1 / 6. - m2 / 2. + m3 / 3.;
123 a2 = -m1 / 2. + m2 / 2. + m3;
124 a3 = 4. * m1 / 3. - 4. * m3 / 3.;
125 } else
126 TRIQS_RUNTIME_ERROR << "ERROR: Unknown statistic in density\n";
127
128 dcomplex r = 0;
129 for (auto w : g.mesh()) r += g[w](n1, n2) - (a1 / (w - b1) + a2 / (w - b2) + a3 / (w - b3));
130 res(n1, n2) = r / beta + m1 + F(a1, b1) + F(a2, b2) + F(a3, b3);
131 res(n1, n2) *= -xi;
132
133 if (n2 > n1) res(n2, n1) = conj(res(n1, n2));
134 }
135
136 return res;
137 }
138
139 //-------------------------------------------------------
140 dcomplex density(gf_const_view<mesh::imfreq, scalar_valued> g, array_const_view<dcomplex, 1> known_moments) {
141 auto km = array<dcomplex, 3>(make_shape(known_moments.shape()[0], 1, 1));
142 if (!known_moments.is_empty()) km(range::all, 0, 0) = known_moments();
144 return res;
145 }
146
147 //-------------------------------------------------------
148 // For Real Frequency functions
149 // ------------------------------------------------------
150
152 nda::matrix<dcomplex> density(gf_const_view<mesh::refreq> g) {
153
154 double wmin = g.mesh().w_min();
155 double dw = g.mesh().delta();
156
157 EXPECTS(wmin < 0.);
158
159 auto N0 = static_cast<int>(std::floor(-wmin / dw)) + 1; // frequency index at or above w=0
160 double dw0 = -wmin - (N0 - 1) * dw; // last interval width to w=0
161
162 nda::matrix<dcomplex> res(g.target_shape());
163
164 // Trapetzoidal integration, with partial right interval
165 res = 0.5 * g[0];
166 for (auto widx : range(1, N0)) res += g[widx];
167 if (abs(dw0) > 1e-9) {
168 double a = dw0 / dw;
169 res += 0.5 * ((a * a - 1.) * g[N0 - 1] + a * (2. - a) * g[N0]);
170 } else
171 res -= 0.5 * g[N0 - 1];
172
173 // Filter out divergent real parts of g that are inf
174 // e.g. flat dos at dos edge (but keep complex matrix structure)
175 diagonal(res) = dcomplex(0., 1.) * imag(diagonal(res));
176 res *= dcomplex(0., 1.) * dw / M_PI; // scale to density
177
178 // writing back into res is problematic due to lazy expressions
179 // return directly instead
180 return 0.5 * (res + dagger(res)); // A = i( g - g^+ )
181 }
182
184 nda::matrix<dcomplex> density(gf_const_view<mesh::refreq> g, double beta) {
185
186 auto [N, M] = g.target_shape();
187 EXPECTS(beta > 0 and N == M);
188
189 auto res = nda::matrix<dcomplex>::zeros(N, N);
190 for (auto w : g.mesh()) res += g[w] / (1. + exp(beta * w));
191
192 // -- Required to filter out divergent real parts of g that are inf
193 // -- eg flat dos at dos edge
194 diagonal(res) = dcomplex(0., 1.) * imag(diagonal(res));
195 res *= dcomplex(0., 1.) * g.mesh().delta() / M_PI; // scale to density
196
197 // writing back into res is problematic due to lazy expressions
198 // return directly instead
199 return 0.5 * (res + dagger(res)); // A = i( g - g^+ )
200 }
201
202 //-------------------------------------------------------
206
208
209 //-------------------------------------------------------
210 // For Legendre functions
211 // ------------------------------------------------------
212
213 nda::matrix<dcomplex> density(gf_const_view<mesh::legendre> gl) {
214 nda::matrix<dcomplex> res(gl.target_shape());
215 res() = 0.0;
216
217 // Calculate <cdag_j c_i> = -G_ij(beta^{-}) using Eq. (1,2) of PhysRevB.84.075145
218 for (auto l : gl.mesh()) res -= std::sqrt(2 * l.index() + 1) * gl[l];
219 res /= gl.mesh().beta();
220
221 // Transpose to get <cdag_i c_j> instead of <cdag_j c_i>
222 return transpose(res);
223 }
224
226
227} // namespace triqs::gfs
A read-only, non-owning view of a Green's function.
mesh_t const & mesh() const
Get the mesh of the Green's function.
std::array< long, Target::rank > target_shape() const
Get the shape of the target.
Provides common type aliases, forward declarations and internal helpers for the Green's function cont...
Provides functions to compute the density (occupation) from Green's functions.
TRIQS exception hierarchy and related macros.
Provides tail fitting, slicing, inversion, reality and matrix-multiplication functions for Green's fu...
Provides the triqs::gfs::gf_const_view container, a read-only non-owning view of a Green's function.
nda::matrix< dcomplex > density(gf_const_view< mesh::imfreq > g, array_const_view< dcomplex, 3 > known_moments)
Compute the density from a Green's function.
Definition density.cpp:49
auto reinterpret_scalar_valued_gf_as_matrix_valued(block_gf< M, T, L, A > &g)
Apply reinterpret_scalar_valued_gf_as_matrix_valued block-wise to each block of the block Green's fun...
G::regular_type::real_t imag(G const &g)
Take the imaginary part of a Green's function (no check), returning a new Green's function with a rea...
G::regular_type conj(G const &g)
Complex-conjugate a Green's function, returning a new Green's function.
gf< M, matrix_valued > transpose(gf_view< M, matrix_valued > g)
Transpose the target matrix of a matrix-valued Green's function, returning a new Green's function.
auto make_zero_tail(G const &g, int n_moments=10)
Create a zero-initialized tail object for a given Green function object.
std::pair< typename A::regular_type, double > fit_tail(G const &g, A const &known_moments={})
Fit the high-frequency tail of a Green's function using a least-squares procedure.
#define TRIQS_RUNTIME_ERROR
Throw a triqs::runtime_error with the current source location.
#define TRIQS_ASSERT2(X,...)
Like TRIQS_ASSERT but lets the caller add a custom message.
std::complex< double > dcomplex
Convenience alias for std::complex<double>.
string to_string(string const &str)
Identity overload for std::string.
Common macros used in TRIQS.
Provides a mesh type on the imaginary frequency axis.
Provides a mesh type for Legendre polynomials as basis functions.
Provides a mesh type on the real frequency axis.
Provides the target types that fix the value stored at each mesh point of a Green's function.