7#include <itertools/enumerate.hpp>
8#include <triqs/operators/many_body_operator.hpp>
16 auto n(
auto const &x) {
return operators::n(x.first, x.second); };
17 auto c_dag(
auto const &x) {
return operators::c_dag(x.first, x.second); };
18 auto c(
auto const &x) {
return operators::c(x.first, x.second); };
21 nda::array<std::pair<std::string, long>, 2> make_op_names(
auto const &tau_names,
auto const &dim_gamma) {
22 auto n_sigma = long(tau_names.size());
23 auto n_orb = stdr::fold_left(dim_gamma, 0, std::plus<>());
24 auto op_names = nda::array<std::pair<std::string, long>, 2>(n_orb, n_sigma);
25 for (
auto [itau, tau] : enumerate(tau_names)) {
27 for (
auto [igamma, gamma] : enumerate(dim_gamma)) {
28 for (
auto orb : range(gamma)) {
29 op_names(pl, itau) = {fmt::format(
"{}_{}", tau, igamma), orb};
40 std::pair<nda::matrix<double>, nda::matrix<double>> kanamori_umatrices(
long n_orb,
double U_int,
double U_prime,
double J_hund) {
41 auto Umat = nda::zeros<double>(n_orb, n_orb);
42 auto Upmat = nda::zeros<double>(n_orb, n_orb);
43 for (
auto &&[m, mp] : product(range(n_orb), range(n_orb))) {
47 Umat(m, mp) = U_prime - J_hund;
48 Upmat(m, mp) = U_prime;
54 double three_j_symbol(std::tuple<long, long, long, long, long, long> jms) {
55 auto [j1, m1, j2, m2, j3, m3] = jms;
56 auto fact = [](
auto x) {
return std::tgamma(x + 1); };
57 if ((m1 + m2 + m3 != 0) || (m1 < -j1) || (m1 > j1) || (m2 < -j2) || (m2 > j2) || (m3 < -j3) || (m3 > j3) || (j3 > j1 + j2)
58 || j3 < std::abs(j1 - j2)) {
61 auto three_j_sym = ((j1 - j2 - m3) % 2) ? -1.0 : 1.0;
62 three_j_sym *= sqrt((fact(j1 + j2 - j3) * fact(j1 - j2 + j3) * fact(-j1 + j2 + j3)) / fact(j1 + j2 + j3 + 1));
63 three_j_sym *= sqrt(fact(j1 - m1) * fact(j1 + m1) * fact(j2 - m2) * fact(j2 + m2) * fact(j3 - m3) * fact(j3 + m3));
65 auto t_min = std::max({j2 - j3 - m1, j1 - j3 + m2,
static_cast<long>(0)});
66 auto t_max = std::min({j1 - m1, j2 + m2, j1 + j2 - j3});
68 for (
auto t : range(t_min, t_max + 1)) {
69 t_sum += ((t % 2) ? -1.0 : 1.0)
70 / (fact(t) * fact(j3 - j2 + m1 + t) * fact(j3 - j1 - m2 + t) * fact(j1 + j2 - j3 - t) * fact(j1 - m1 - t) * fact(j2 + m2 - t));
77 double angular_matrix_element(
long l,
long k,
long m1,
long m2,
long m3,
long m4) {
78 auto squared = [](
auto x) {
return x * x; };
80 auto ang_mat_ele = 0.0;
81 for (
auto q : range(-k, k + 1)) {
82 ang_mat_ele += three_j_symbol({l, -m1, k, q, l, m3}) * three_j_symbol({l, -m2, k, -q, l, m4}) * (((m1 + q + m2) % 2) ? -1.0 : 1.0);
84 ang_mat_ele *= squared(2.0 *
static_cast<double>(l) + 1) * squared(three_j_symbol({l, 0, k, 0, l, 0}));
88 nda::array<double, 1> radial_integrals(
long l,
double U_int,
double J_hund) {
89 auto F = nda::zeros<double>(l + 1);
95 F(1) = 14.0 * J_hund / (1.0 + 0.63);
99 F(1) = (6435.0 * J_hund) / (286.0 + 195.0 * 451.0 / 675.0 + 250.0 * 1001.0 / 2025.0);
100 F(2) = 451.0 * F(1) / 675.0;
101 F(3) = 1001.0 * F(1) / 2025.0;
107 operators::many_body_operator
make_density_density(
const std::vector<std::string> &tau_names,
const std::vector<long> &dim_gamma,
double U_int,
108 double U_prime,
double J_hund) {
109 return make_kanamori(tau_names, dim_gamma, U_int, U_prime, J_hund,
false,
false);
113 operators::many_body_operator
make_kanamori(std::vector<std::string>
const &tau_names, std::vector<long>
const &dim_gamma,
double U_int,
114 double U_prime,
double J_hund,
bool spin_flip,
bool pair_hopping) {
115 auto n_sigma = long(tau_names.size());
116 auto n_orb = stdr::fold_left(dim_gamma, 0, std::plus<>());
118 auto op_names = detail::make_op_names(tau_names, dim_gamma);
121 auto [Umat, Upmat] = detail::kanamori_umatrices(n_orb, U_int, U_prime, J_hund);
124 auto h_int = operators::many_body_operator();
126 for (
auto &&[s1, s2] : product(range(n_sigma), range(n_sigma))) {
127 for (
auto &&[a1, a2] : product(range(n_orb), range(n_orb))) {
128 h_int += 0.5 * ((s1 == s2) ? Umat(a1, a2) : Upmat(a1, a2)) * detail::n(op_names(a1, s1)) * detail::n(op_names(a2, s2));
134 for (
auto &&[s1, s2] : product(range(n_sigma), range(n_sigma))) {
135 if (s1 == s2)
continue;
136 for (
auto &&[a1, a2] : product(range(n_orb), range(n_orb))) {
137 if (a1 == a2)
continue;
138 h_int += -0.5 * J_hund * detail::c_dag(op_names(a1, s1)) * detail::c(op_names(a1, s2)) * detail::c_dag(op_names(a2, s2))
139 * detail::c(op_names(a2, s1));
146 for (
auto &&[s1, s2] : product(range(n_sigma), range(n_sigma))) {
147 if (s1 == s2)
continue;
148 for (
auto &&[a1, a2] : product(range(n_orb), range(n_orb))) {
149 if (a1 == a2)
continue;
150 h_int += 0.5 * J_hund * detail::c_dag(op_names(a1, s1)) * detail::c_dag(op_names(a1, s2)) * detail::c(op_names(a2, s2))
151 * detail::c(op_names(a2, s1));
159 auto U_matrix = nda::zeros<double>(2 * l + 1, 2 * l + 1, 2 * l + 1, 2 * l + 1);
160 auto m_range = nda::range(-l, l + 1);
161 auto radial_integrals = detail::radial_integrals(l, U_int, J_hund);
162 for (
auto [n, F] : itertools::enumerate(radial_integrals)) {
164 for (
auto [m1, m2, m3, m4] : product(m_range, m_range, m_range, m_range)) {
165 U_matrix(m1 + l, m2 + l, m3 + l, m4 + l) += F * detail::angular_matrix_element(l, k, m1, m2, m3, m4);
172 auto s2lC = conj(s2l);
173 auto s2lT = transpose(s2l);
176 auto U_local = nda::zeros<dcomplex>(N, N, N, N);
179 for (
auto i : range(N))
180 for (
auto k : range(N))
181 for (
auto n : range(N))
182 for (
auto p : range(N))
183 for (
auto j : range(N))
184 for (
auto q : range(N))
185 for (
auto m : range(N))
186 for (
auto o : range(N)) {
187 auto left = s2lC(i, j) * s2lC(k, q);
188 auto right = (s2lT(m, n)) * s2lT(o, p);
189 U_local(i, k, n, p) += left * U_spherical(j, q, m, o) * right;
194 operators::many_body_operator
make_slater(std::vector<std::string>
const &tau_names, std::vector<long>
const &dim_gamma,
double U_int,
195 double J_hund, nda::matrix<dcomplex>
const &spherical_to_dft,
196 std::optional<nda::matrix<dcomplex>>
const &dft_to_local) {
197 auto n_sigma = long(tau_names.size());
198 auto n_orb = stdr::fold_left(dim_gamma, 0, std::plus<>());
200 auto op_names = detail::make_op_names(tau_names, dim_gamma);
203 long l = (n_orb - 1) / 2;
204 auto transform = (dft_to_local) ? spherical_to_dft * dft_to_local.value() : spherical_to_dft;
208 auto h_int = operators::many_body_operator();
209 for (
auto [s1, s2] : product(range(n_sigma), range(n_sigma))) {
210 for (
auto [m1, m2, m3, m4] : product(range(n_orb), range(n_orb), range(n_orb), range(n_orb))) {
211 h_int += 0.5 * real(U_matrix(m1, m2, m3, m4)) * detail::c_dag(op_names(m1, s1)) * detail::c_dag(op_names(m2, s2))
212 * detail::c(op_names(m4, s2)) * detail::c(op_names(m3, s1));
operators::many_body_operator make_density_density(const std::vector< std::string > &tau_names, const std::vector< long > &dim_gamma, double U_int, double U_prime, double J_hund)
Construct a density-density interation.
operators::many_body_operator make_slater(std::vector< std::string > const &tau_names, std::vector< long > const &dim_gamma, double U_int, double J_hund, nda::matrix< dcomplex > const &spherical_to_dft, std::optional< nda::matrix< dcomplex > > const &dft_to_local)
Construct a new operators::many body operator make slater object.
nda::array< dcomplex, 4 > U_matrix_in_local_basis(long l, nda::matrix< dcomplex > s2l, double U_int, double J_hund)
Construct a four-index Coulomb tensor in a specific orbital basis.
nda::array< double, 4 > U_matrix_in_spherical_basis(long l, double U_int, double J_hund)
Construct a four-index Coulomb tensor in the basis of spherical harmonics.
operators::many_body_operator make_kanamori(std::vector< std::string > const &tau_names, std::vector< long > const &dim_gamma, double U_int, double U_prime, double J_hund, bool spin_flip, bool pair_hopping)
Construct a Hubbard-Kanamori Hamiltonian.