16 std::pair<double, double>
dc_formulas(std::string
const method,
double const N_tot,
double const N_sigma,
long const n_orb,
double const U,
18 double Mag = N_sigma - (N_tot - N_sigma);
19 double L_orbit = 0.5 * (double(n_orb) - 1.0);
20 if (method ==
"cFLL") {
21 return {(U * (N_tot - 0.5) - 0.5 * J * (N_tot - 1.0)), 0.5 * U * N_tot * (N_tot - 1.0) - 0.5 * J * N_tot * (0.5 * N_tot - 1.0)};
22 }
else if (method ==
"sFLL") {
23 return {(U * (N_tot - 0.5) - J * (N_sigma - 0.5)),
24 0.5 * U * N_tot * (N_tot - 1.0) - 0.5 * J * N_tot * (N_tot * 0.5 - 1.0) - 0.25 * J * Mag * Mag};
25 }
else if (method ==
"cAMF") {
26 double C = (U + 2.0 * J * L_orbit) / (2 * L_orbit + 1.0);
28 (U * N_tot - 0.5 * N_tot * C),
29 (0.5 * U - 0.25 * C) * N_tot * N_tot
31 }
else if (method ==
"sAMF") {
32 return {(U * N_tot - ((U + 2.0 * L_orbit * J) / (2.0 * L_orbit + 1.0)) * N_sigma),
33 0.5 * U * N_tot * N_tot - 0.25 * ((U + 2.0 * L_orbit * J) / (2.0 * L_orbit + 1.0)) * N_tot * N_tot
34 - 0.25 * ((U + 2.0 * L_orbit * J) / (2.0 * L_orbit + 1.0)) * Mag * Mag};
35 }
else if (method ==
"cHeld") {
36 double U_mean = (U + (n_orb - 1) * (U - 2 * J) + (n_orb - 1) * (U - 3 * J)) / (2 * n_orb - 1);
38 (U_mean * (N_tot - 0.5)),
39 0.5 * U_mean * N_tot * (N_tot - 1.0)
42 throw std::runtime_error(
"Not implemented! Complain to the developers");
58 nda::array<nda::matrix<dcomplex>, 2>
const &density_matrix) {
59 auto [n_blocks, n_sig] = density_matrix.shape();
60 auto N_per_sigma = nda::zeros<double>(n_sig);
61 for (
auto sigma : range(n_sig))
62 for (
auto bl : range(n_blocks)) N_per_sigma(sigma) += real(trace(density_matrix(bl, sigma)));
63 auto N_total = stdr::fold_left(N_per_sigma, 0.0, std::plus<>());
69 for (
auto sigma : range(n_sig)) N_per_sigma(sigma) = 0.5 * N_total;
72 N_per_sigma(0) = 0.5 * N_total;
75 return {N_total, N_per_sigma};
80 : _spin_kind{spin_kind}, n_sigma{
n_sigma_from_spin_kind(spin_kind)}, method{std::move(method)}, U_int{U_int}, J_hund{J_hund} {};
83 nda::array<nda::matrix<dcomplex>, 2> dc_solver::get_density_matrix_from_gf(block_gf<imfreq, matrix_valued>
const &gimp) {
84 auto n_blocks = gimp.size() / n_sigma;
85 auto density_matrix = nda::array<nda::matrix<dcomplex>, 2>(n_blocks, n_sigma);
86 for (
auto bl : range(n_blocks))
87 for (auto sigma : range(n_sigma)) density_matrix(bl, sigma) =
density(gimp[bl + sigma * n_blocks]);
88 return density_matrix;
94 auto [n_blocks, n_sig] = density_matrix.shape();
97 for (
auto bl : range(n_blocks)) n_orb += density_matrix(bl, 0).shape()[0];
100 auto Sigma_DC = std::vector<nda::matrix<dcomplex>>(n_blocks * n_sig);
101 for (
auto bl : range(n_blocks))
102 for (
auto sigma : range(n_sig))
103 Sigma_DC[bl + sigma * n_blocks] = std::get<0>(
dc_formulas(method, N_total, N_per_sigma(sigma), n_orb, U_int, J_hund))
104 * nda::eye<dcomplex>(density_matrix(bl, sigma).shape()[0]);
111 auto [n_blocks, n_sig] = density_matrix.shape();
114 for (
auto bl : range(n_blocks)) n_orb += density_matrix(bl, 0).shape()[0];
117 auto E_DC = std::vector<double>(n_sig);
118 for (
auto sigma : range(n_sig)) E_DC[sigma] = std::get<1>(
dc_formulas(method, N_total, N_per_sigma(sigma), n_orb, U_int, J_hund));
123 for (
auto sigma : range(1, n_sig))
124 if (std::abs(E_DC[sigma] - E_DC[0]) > 1.e-10)
125 throw std::runtime_error(
"dc_energy: E_DC depends on spin channel");
137 return dc_energy(get_density_matrix_from_gf(gimp));
double dc_energy(block_gf< imfreq, matrix_valued > const &gimp)
Compute the double counting correction to the energy from a Green's function.
std::vector< nda::matrix< dcomplex > > dc_self_energy(block_gf< imfreq, matrix_valued > const &gimp)
Compute the double-counting self-energy from a Green's function.
dc_solver(spin_kind_e spin_kind, std::string method, double U_int, double J_hund)
Construct a double counting "solver".
std::pair< double, double > dc_formulas(std::string const method, double const N_tot, double const N_sigma, long const n_orb, double const U, double const J)
double counting formulas parameterized by density, U, and J
double density(one_body_elements_on_grid const &obe, double mu, block2_gf< Mesh, matrix_valued > const &Sigma_dynamic, nda::array< nda::matrix< dcomplex >, 2 > const &Sigma_static)
Compute the density of the lattice Green's function with a self-energy using Woodbury.
long n_sigma_from_spin_kind(spin_kind_e sk)
Number of σ channels for a given spin_kind_e.
spin_kind_e
Kind of σ index.
static std::pair< double, nda::vector< double > > get_total_density(spin_kind_e spin_kind, nda::array< nda::matrix< dcomplex >, 2 > const &density_matrix)