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") {
38 double U_mean = (U + (n_orb - 1) * (U - 2 * J) + (n_orb - 1) * (U - 3 * J)) / (2 * n_orb - 1);
40 (U_mean * (N_tot - 0.5)),
41 0.5 * U_mean * N_tot * (N_tot - 1.0)
44 throw std::runtime_error(
"Not implemented! Complain to the developers");
49 std::pair<nda::array<nda::matrix<double>, 2>, nda::matrix<double>>
51 double_counting(nda::array<nda::matrix<dcomplex>, 2>
const &density_matrix,
double U_int,
double J_hund, std::string
const method) {
53 auto [n_atoms, n_sigma] = density_matrix.shape();
54 auto Sigma_DC = nda::array<nda::matrix<double>, 2>(n_atoms, n_sigma);
55 auto E_DC = nda::matrix<double>(n_atoms, n_sigma);
58 for (
auto atom : nda::range(n_atoms))
59 for (
auto sigma : nda::range(n_sigma)) {
61 auto n_orb = density_matrix(atom, sigma).shape()[0];
62 Sigma_DC(atom, sigma) = nda::eye<double>(n_orb);
65 for (
auto atom : range(n_atoms)) {
66 auto Nsigma = nda::zeros<double>(n_sigma);
68 for (
auto sigma : range(n_sigma)) { Nsigma(sigma) += real(trace(density_matrix(atom, sigma))); }
69 auto Ntot = stdr::fold_left(Nsigma, 0, std::plus<>());
70 for (
auto sigma : range(n_sigma)) {
72 Nsigma(sigma) = Ntot / n_sigma;
73 }
else if (n_sigma == 1) {
74 Nsigma(sigma) = 0.5 * Ntot;
78 for (
auto sigma : range(n_sigma)) {
79 auto n_orb = density_matrix(atom, sigma).shape()[0];
80 n_orb = (n_sigma == 2) ? n_orb :
static_cast<long>(n_orb / 2);
81 auto [DC_val, E_val] =
dc_formulas(method, Ntot, Nsigma(sigma), n_orb, U_int, J_hund);
82 Sigma_DC(atom, sigma) *= DC_val;
83 E_DC(atom, sigma) = E_val;
86 return {Sigma_DC, E_DC};
90 std::pair<double, nda::vector<double>>
get_total_density(nda::array<nda::matrix<dcomplex>, 2>
const &density_matrix) {
91 auto [n_blocks, n_sigma] = density_matrix.shape();
92 auto N_per_sigma = nda::zeros<double>(n_sigma);
93 for (
auto sigma : range(n_sigma)) {
94 for (
auto bl : range(n_blocks)) { N_per_sigma(sigma) += real(trace(density_matrix(bl, sigma))); }
96 auto N_total = stdr::fold_left(N_per_sigma, 0, std::plus<>());
97 for (
auto sigma : range(n_sigma)) {
99 N_per_sigma(sigma) = N_total / n_sigma;
100 }
else if (n_sigma == 1) {
101 N_per_sigma(sigma) = 0.5 * N_total;
104 return {N_total, N_per_sigma};
108 nda::array<nda::matrix<double>, 2>
double_counting_sigma_dc(nda::array<nda::matrix<dcomplex>, 2>
const &density_matrix,
double U_int,
double J_hund,
109 std::string
const method) {
113 auto [n_blocks, n_sigma] = density_matrix.shape();
116 stdr::fold_left(density_matrix(
r_all, 0) | stdv::transform([](
auto x) {
return x.shape()[0]; }) | tl::to<std::vector>(), 0, std::plus<>());
117 n_orb = (n_sigma == 2) ? n_orb :
static_cast<long>(n_orb / 2);
119 auto Sigma_DC = nda::array<nda::matrix<double>, 2>(n_blocks, n_sigma);
120 for (
auto bl : range(n_blocks))
121 for (
auto sigma : range(n_sigma))
122 Sigma_DC(bl, sigma) = std::get<0>(
dc_formulas(method, N_total, N_per_sigma(sigma), n_orb, U_int, J_hund))
123 * nda::eye<double>(density_matrix(bl, sigma).shape()[0]);
129 std::string
const method) {
133 auto [n_blocks, n_sigma] = density_matrix.shape();
135 stdr::fold_left(density_matrix(
r_all, 0) | stdv::transform([](
auto x) {
return x.shape()[0]; }) | tl::to<std::vector>(), 0, std::plus<>());
136 n_orb = (n_sigma == 2) ? n_orb :
static_cast<long>(n_orb / 2);
138 auto E_DC = nda::matrix<double>(n_blocks, n_sigma);
139 for (
auto bl : range(n_blocks))
140 for (
auto sigma : range(n_sigma)) E_DC(bl, sigma) = std::get<1>(
dc_formulas(method, N_total, N_per_sigma(sigma), n_orb, U_int, J_hund));
146 : n_sigma{n_sigma}, method{std::move(method)}, U_int{U_int}, J_hund{J_hund} {};
148 nda::array<nda::matrix<double>, 2> dc_solver::get_density_matrix_from_gf(block_gf<imfreq, matrix_valued>
const &gimp) {
149 auto n_blocks = gimp.size() / n_sigma;
150 auto density_matrix = nda::array<nda::matrix<double>, 2>(n_blocks, n_sigma);
151 for (
auto bl : range(n_blocks))
152 for (auto sigma : range(n_sigma)) density_matrix(bl, sigma) = real(
density(gimp[bl + sigma * n_blocks]));
153 return density_matrix;
158 auto Sigma_DC = std::vector<nda::matrix<dcomplex>>(gimp.size());
159 auto density_matrix = get_density_matrix_from_gf(gimp);
160 auto n_blocks = density_matrix.extent(0);
162 for (
auto bl : range(n_blocks))
163 for (
auto sigma : range(n_sigma)) Sigma_DC[bl + sigma * n_blocks] = Sigma_dc_mat(bl, sigma);
dc_solver(long n_sigma, std::string method, double U_int, double J_hund)
Construct a double counting "solver".
std::vector< nda::matrix< dcomplex > > dc_self_energy(block_gf< imfreq, matrix_valued > const &gimp)
Compute the double-counting self-energy.
nda::matrix< double > dc_energy(block_gf< imfreq, matrix_valued > const &gimp)
Compute the double counting correction to the energy.
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.
nda::array< nda::matrix< double >, 2 > double_counting_sigma_dc(nda::array< nda::matrix< dcomplex >, 2 > const &density_matrix, double U_int, double J_hund, std::string const method)
std::pair< double, nda::vector< double > > get_total_density(nda::array< nda::matrix< dcomplex >, 2 > const &density_matrix)
std::pair< nda::array< nda::matrix< double >, 2 >, nda::matrix< double > > double_counting(nda::array< nda::matrix< dcomplex >, 2 > const &density_matrix, double U_int, double J_hund, std::string const method)
compute double counting correction for a dc_type (method) from the density matrix of a Green's functi...
nda::matrix< double > double_counting_energy_dc(nda::array< nda::matrix< dcomplex >, 2 > const &density_matrix, double U_int, double J_hund, std::string const method)
static constexpr auto r_all