TRIQS/triqs_modest 3.3.0
Brillouin zone summation
Loading...
Searching...
No Matches
double_counting.cpp
Go to the documentation of this file.
1// Copyright (c) 2025--present, The Simons Foundation
2// This file is part of TRIQS/modest and is licensed under the terms of GPLv3 or later.
3// SPDX-License-Identifier: GPL-3.0-or-later
4// See LICENSE in the root of this distribution for details.
5
6#include <utility>
9
10using nda::range;
11
12namespace triqs::modest {
13
14 //------------------------------------------------------------------------------------
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,
17 double const J) {
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);
27 return {
28 (U * N_tot - 0.5 * N_tot * C), // DC
29 (0.5 * U - 0.25 * C) * N_tot * N_tot //Energy
30 };
31 } else if (method == "sAMF") {
32 return {(U * N_tot - ((U + 2.0 * L_orbit * J) / (2.0 * L_orbit + 1.0)) * N_sigma), // DC
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 // Energy
34 - 0.25 * ((U + 2.0 * L_orbit * J) / (2.0 * L_orbit + 1.0)) * Mag * Mag};
35 } else if (method == "cHeld") {
36 // double C = double(n_orb) - 1.0;
37 // double Umean = (U + ((U - 2.0 * J) + (U - 3.0 * J)) * C) / (2.0 * double(n_orb) - 1);
38 double U_mean = (U + (n_orb - 1) * (U - 2 * J) + (n_orb - 1) * (U - 3 * J)) / (2 * n_orb - 1);
39 return {
40 (U_mean * (N_tot - 0.5)), //DC
41 0.5 * U_mean * N_tot * (N_tot - 1.0) //Energy
42 };
43 } else {
44 throw std::runtime_error("Not implemented! Complain to the developers");
45 }
46 }
47 //------------------------------------------------------------------------------------
48
49 std::pair<nda::array<nda::matrix<double>, 2>, nda::matrix<double>>
50 //double_counting_from_gf(block2_gf<imfreq, matrix_valued> const &GC, double U_int, double J_hund,
51 double_counting(nda::array<nda::matrix<dcomplex>, 2> const &density_matrix, double U_int, double J_hund, std::string const method) {
52
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);
56
57 //for (auto [atom, sigma] : indices(GC)) {
58 for (auto atom : nda::range(n_atoms))
59 for (auto sigma : nda::range(n_sigma)) {
60 //auto n_orb = GC(atom, sigma).target_shape()[0];
61 auto n_orb = density_matrix(atom, sigma).shape()[0];
62 Sigma_DC(atom, sigma) = nda::eye<double>(n_orb);
63 }
64
65 for (auto atom : range(n_atoms)) {
66 auto Nsigma = nda::zeros<double>(n_sigma);
67 //for (auto sigma : range(n_sigma)) { Nsigma(sigma) += real(trace(density(GC(atom, 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)) {
71 if (n_sigma == 2) {
72 Nsigma(sigma) = Ntot / n_sigma;
73 } else if (n_sigma == 1) {
74 Nsigma(sigma) = 0.5 * Ntot;
75 }
76 }
77
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;
84 }
85 }
86 return {Sigma_DC, E_DC};
87 }
88
89 //------------------------------------------------------------------------------------
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))); }
95 }
96 auto N_total = stdr::fold_left(N_per_sigma, 0, std::plus<>());
97 for (auto sigma : range(n_sigma)) {
98 if (n_sigma == 2) {
99 N_per_sigma(sigma) = N_total / n_sigma;
100 } else if (n_sigma == 1) {
101 N_per_sigma(sigma) = 0.5 * N_total;
102 }
103 }
104 return {N_total, N_per_sigma};
105 }
106 //------------------------------------------------------------------------------------
107
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) {
110
111 auto [N_total, N_per_sigma] = get_total_density(density_matrix);
112
113 auto [n_blocks, n_sigma] = density_matrix.shape();
114
115 auto n_orb =
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);
118
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]);
124 return Sigma_DC;
125 }
126 //------------------------------------------------------------------------------------
127
128 nda::matrix<double> double_counting_energy_dc(nda::array<nda::matrix<dcomplex>, 2> const &density_matrix, double U_int, double J_hund,
129 std::string const method) {
130
131 auto [N_total, N_per_sigma] = get_total_density(density_matrix);
132
133 auto [n_blocks, n_sigma] = density_matrix.shape();
134 auto n_orb =
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);
137
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));
141 return E_DC;
142 }
143
144 //------------------------------------------------------------------------------------
145 dc_solver::dc_solver(long n_sigma, std::string method, double U_int, double J_hund)
146 : n_sigma{n_sigma}, method{std::move(method)}, U_int{U_int}, J_hund{J_hund} {};
147
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;
154 }
155 //------------------------------------------------------------------------------------
156
157 std::vector<nda::matrix<dcomplex>> dc_solver::dc_self_energy(block_gf<imfreq, matrix_valued> const &gimp) {
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);
161 auto Sigma_dc_mat = double_counting_sigma_dc(density_matrix, U_int, J_hund, method);
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);
164 return Sigma_DC;
165 }
166
167 //------------------------------------------------------------------------------------
168 nda::matrix<double> dc_solver::dc_energy(block_gf<imfreq, matrix_valued> const &gimp) {
169 return double_counting_energy_dc(get_density_matrix_from_gf(gimp), U_int, J_hund, method);
170 }
171
172} // namespace triqs::modest
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.
Definition density.hpp:93
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
Definition defs.hpp:40