32generate_potential_collinear_nonlocal(Simulation_context
const& ctx__,
const int index__,
33 sddk::mdarray<std::complex<double>, 3>
const& om__,
34 sddk::mdarray<std::complex<double>, 3>& um__)
36 auto nl = ctx__.cfg().hubbard().nonlocal(index__);
39 double v_ij = nl.V() /
ha2ev;
44 for (
int is = 0; is < ctx__.num_spins(); is++) {
45 for (
int m2 = 0; m2 < 2 * jl + 1; m2++) {
46 for (
int m1 = 0; m1 < 2 * il + 1; m1++) {
47 um__(m1, m2, is) = -v_ij * om__(m1, m2, is);
54generate_potential_collinear_local(Simulation_context
const& ctx__, Atom_type
const& atom_type__,
const int idx_hub_wf,
55 sddk::mdarray<std::complex<double>, 3>
const& om__, sddk::mdarray<std::complex<double>, 3>& um__)
58 if (!atom_type__.hubbard_correction()) {
65 auto& hub_wf = atom_type__.lo_descriptor_hub(idx_hub_wf);
67 if (!hub_wf.use_for_calculation()) {
71 int const lmax_at = 2 * hub_wf.l() + 1;
73 if (ctx__.cfg().hubbard().simplified()) {
75 if ((hub_wf.U() != 0.0) || (hub_wf.alpha() != 0.0)) {
77 double U_effective = hub_wf.U();
79 if (std::abs(hub_wf.J0()) > 1e-8) {
80 U_effective -= hub_wf.J0();
83 for (
int is = 0; is < ctx__.num_spins(); is++) {
91 for (
int m1 = 0; m1 < lmax_at; m1++) {
92 um__(m1, m1, is) = hub_wf.alpha() + 0.5 * U_effective;
94 for (
int m2 = 0; m2 < lmax_at; m2++) {
95 um__(m2, m1, is) -= U_effective * om__(m2, m1, is);
101 if (std::abs(hub_wf.J0()) > 1e-8 || std::abs(hub_wf.beta()) > 1e-8) {
102 for (
int is = 0; is < ctx__.num_spins(); is++) {
106 int const s_opposite = (is + 1) % 2;
108 double const sign = (is == 0) - (is == 1);
110 for (
int m1 = 0; m1 < lmax_at; m1++) {
112 um__(m1, m1, is) +=
sign * hub_wf.beta();
114 for (
int m2 = 0; m2 < lmax_at; m2++) {
115 um__(m1, m2, is) += hub_wf.J0() * om__(m2, m1, s_opposite);
127 double n_updown[2] = {0.0, 0.0};
129 for (
int s = 0; s < ctx__.num_spins(); s++) {
130 for (
int m = 0; m < lmax_at; m++) {
131 n_total += om__(m, m, s).real();
134 for (
int m = 0; m < lmax_at; m++) {
135 n_updown[s] += om__(m, m, s).real();
141 for (
int is = 0; is < ctx__.num_spins(); is++) {
142 for (
int m1 = 0; m1 < lmax_at; m1++) {
145 um__(m1, m1, is) += hub_wf.J() * n_updown[is] + 0.5 * (hub_wf.U() - hub_wf.J()) - hub_wf.U() * n_total;
148 for (
int m2 = 0; m2 < lmax_at; m2++) {
149 for (
int m3 = 0; m3 < lmax_at; m3++) {
150 for (
int m4 = 0; m4 < lmax_at; m4++) {
151 for (
int is2 = 0; is2 < ctx__.num_spins(); is2++) {
152 um__(m1, m2, is) += hub_wf.hubbard_matrix(m1, m3, m2, m4) * om__(m3, m4, is2);
155 um__(m1, m2, is) -= hub_wf.hubbard_matrix(m1, m3, m4, m2) * om__(m3, m4, is);
165calculate_energy_collinear_nonlocal(Simulation_context
const& ctx__,
const int index__,
166 sddk::mdarray<std::complex<double>, 3>
const& om__)
168 auto nl = ctx__.cfg().hubbard().nonlocal(index__);
169 double hubbard_energy{0.0};
170 double v_ij_ = nl.V() /
ha2ev;
175 for (
int is = 0; is < ctx__.num_spins(); is++) {
176 for (
int m1 = 0; m1 < 2 * jl + 1; m1++) {
177 for (
int m2 = 0; m2 < 2 * il + 1; m2++) {
178 hubbard_energy += v_ij_ * std::real(om__(m2, m1, is) *
conj(om__(m2, m1, is)));
184 if (ctx__.num_spins() == 1) {
185 hubbard_energy *= 2.0;
188 return -0.5 * hubbard_energy;
192calculate_energy_collinear_local(Simulation_context
const& ctx__, Atom_type
const& atom_type__,
const int idx_hub_wf,
193 sddk::mdarray<std::complex<double>, 3>
const& om__)
195 double hubbard_energy{0};
196 double hubbard_energy_u{0};
197 double hubbard_energy_dc_contribution{0};
200 if (!atom_type__.hubbard_correction()) {
205 auto& hub_wf = atom_type__.lo_descriptor_hub(idx_hub_wf);
207 if (!hub_wf.use_for_calculation())
210 int const lmax_at = 2 * hub_wf.l() + 1;
212 if (ctx__.cfg().hubbard().simplified()) {
213 if ((hub_wf.U() != 0.0) || (hub_wf.alpha() != 0.0)) {
215 double U_effective = hub_wf.U();
217 if (std::abs(hub_wf.J0()) > 1e-8) {
218 U_effective -= hub_wf.J0();
221 for (
int is = 0; is < ctx__.num_spins(); is++) {
226 for (
int m1 = 0; m1 < lmax_at; m1++) {
227 hubbard_energy += (hub_wf.alpha() + 0.5 * U_effective) * om__(m1, m1, is).real();
229 for (
int m2 = 0; m2 < lmax_at; m2++) {
230 hubbard_energy -= 0.5 * U_effective * (om__(m1, m2, is) * om__(m2, m1, is)).real();
235 if (std::abs(hub_wf.J0()) > 1e-8 || std::abs(hub_wf.beta()) > 1e-8) {
236 for (
int is = 0; is < ctx__.num_spins(); is++) {
239 const int s_opposite = (is + 1) % 2;
241 const double sign = (is == 0) - (is == 1);
243 for (
int m1 = 0; m1 < lmax_at; m1++) {
245 hubbard_energy +=
sign * hub_wf.beta() * om__(m1, m1, is).real();
247 for (
int m2 = 0; m2 < lmax_at; m2++) {
248 hubbard_energy += 0.5 * hub_wf.J0() * (om__(m2, m1, is) * om__(m1, m2, s_opposite)).real();
254 if (ctx__.num_spins() == 1) {
255 hubbard_energy *= 2.0;
265 double n_updown[2] = {0.0, 0.0};
267 for (
int s = 0; s < ctx__.num_spins(); s++) {
268 for (
int m = 0; m < lmax_at; m++) {
269 n_total += om__(m, m, s).real();
272 for (
int m = 0; m < lmax_at; m++) {
273 n_updown[s] += om__(m, m, s).real();
276 double magnetization{0};
278 if (ctx__.num_mag_dims() == 0) {
281 for (
int m = 0; m < lmax_at; m++) {
282 magnetization += (om__(m, m, 0) - om__(m, m, 1)).real();
284 magnetization *= magnetization;
287 hubbard_energy_dc_contribution +=
288 0.5 * (hub_wf.U() * n_total * (n_total - 1.0) - hub_wf.J() * n_total * (0.5 * n_total - 1.0) -
289 hub_wf.J() * magnetization * 0.5);
293 for (
int is = 0; is < ctx__.num_spins(); is++) {
294 for (
int m1 = 0; m1 < lmax_at; m1++) {
297 for (
int m2 = 0; m2 < lmax_at; m2++) {
298 for (
int m3 = 0; m3 < lmax_at; m3++) {
299 for (
int m4 = 0; m4 < lmax_at; m4++) {
302 0.5 * ((hub_wf.hubbard_matrix(m1, m2, m3, m4) - hub_wf.hubbard_matrix(m1, m2, m4, m3)) *
303 om__(m1, m3, is) * om__(m2, m4, is) +
304 hub_wf.hubbard_matrix(m1, m2, m3, m4) * om__(m1, m3, is) *
305 om__(m2, m4, (ctx__.num_mag_dims() == 1) ? ((is + 1) % 2) : (0)))
313 if (ctx__.num_mag_dims() == 0) {
314 hubbard_energy_u *= 2.0;
316 hubbard_energy = hubbard_energy_u - hubbard_energy_dc_contribution;
323 return hubbard_energy;
327generate_potential_non_collinear_local(Simulation_context
const& ctx__, Atom_type
const& atom_type__,
328 const int idx_hub_wf, sddk::mdarray<std::complex<double>, 3>
const& om__,
329 sddk::mdarray<std::complex<double>, 3>& um__)
332 if (!atom_type__.hubbard_correction()) {
339 auto& hub_wf = atom_type__.lo_descriptor_hub(idx_hub_wf);
341 if (!hub_wf.use_for_calculation())
344 int const lmax_at = 2 * hub_wf.l() + 1;
349 std::complex<double> n_total{0};
350 for (
int m = 0; m < lmax_at; m++) {
351 n_total += om__(m, m, 0) + om__(m, m, 1);
354 for (
int is = 0; is < 4; is++) {
375 for (
int m1 = 0; m1 < lmax_at; ++m1) {
376 for (
int m2 = 0; m2 < lmax_at; ++m2) {
377 for (
int m3 = 0; m3 < lmax_at; ++m3) {
378 for (
int m4 = 0; m4 < lmax_at; ++m4) {
380 hub_wf.hubbard_matrix(m1, m3, m2, m4) * (om__(m3, m4, 0) + om__(m3, m4, 1));
389 std::complex<double> n_aux{0};
390 for (
int m1 = 0; m1 < lmax_at; m1++) {
391 n_aux += om__(m1, m1, is1);
394 for (
int m1 = 0; m1 < lmax_at; m1++) {
398 um__(m1, m1, is) += hub_wf.J() * n_aux;
401 um__(m1, m1, is) += 0.5 * (hub_wf.U() - hub_wf.J()) - hub_wf.U() * n_total;
405 for (
int m2 = 0; m2 < lmax_at; m2++) {
406 for (
int m3 = 0; m3 < lmax_at; m3++) {
407 for (
int m4 = 0; m4 < lmax_at; m4++) {
408 um__(m1, m2, is) -= hub_wf.hubbard_matrix(m1, m3, m4, m2) * om__(m3, m4, is1);
417calculate_energy_non_collinear_local(Simulation_context
const& ctx__, Atom_type
const& atom_type__,
418 const int idx_hub_wf, sddk::mdarray<std::complex<double>, 3>
const& om__)
421 if (!atom_type__.hubbard_correction()) {
426 auto& hub_wf = atom_type__.lo_descriptor_hub(idx_hub_wf);
428 if (!hub_wf.use_for_calculation())
431 int const lmax_at = 2 * hub_wf.l() + 1;
433 double hubbard_energy_dc_contribution{0};
434 double hubbard_energy_noflip{0};
435 double hubbard_energy_flip{0};
436 double hubbard_energy{0};
446 for (
int m = 0; m < lmax_at; m++) {
447 n_total += (om__(m, m, 0) + om__(m, m, 1)).real();
448 mz += (om__(m, m, 0) - om__(m, m, 1)).real();
449 mx += (om__(m, m, 2) + om__(m, m, 3)).real();
450 my += (om__(m, m, 2) - om__(m, m, 3)).imag();
453 double magnetization = mz * mz + mx * mx + my * my;
455 hubbard_energy_dc_contribution +=
456 0.5 * (hub_wf.U() * n_total * (n_total - 1.0) - hub_wf.J() * n_total * (0.5 * n_total - 1.0) -
457 0.5 * hub_wf.J() * magnetization);
459 for (
int is = 0; is < 4; is++) {
479 for (
int m1 = 0; m1 < lmax_at; ++m1) {
480 for (
int m2 = 0; m2 < lmax_at; ++m2) {
481 for (
int m3 = 0; m3 < lmax_at; ++m3) {
482 for (
int m4 = 0; m4 < lmax_at; ++m4) {
486 hubbard_energy_noflip +=
488 ((hub_wf.hubbard_matrix(m1, m2, m3, m4) - hub_wf.hubbard_matrix(m1, m2, m4, m3)) *
489 om__(m1, m3, is) * om__(m2, m4, is) +
490 hub_wf.hubbard_matrix(m1, m2, m3, m4) * om__(m1, m3, is) * om__(m2, m4, (is + 1) % 2))
498 for (
int m1 = 0; m1 < lmax_at; ++m1) {
499 for (
int m2 = 0; m2 < lmax_at; ++m2) {
500 for (
int m3 = 0; m3 < lmax_at; ++m3) {
501 for (
int m4 = 0; m4 < lmax_at; ++m4) {
502 hubbard_energy_flip -=
504 (hub_wf.hubbard_matrix(m1, m2, m4, m3) * om__(m1, m3, is) * om__(m2, m4, is1)).real();
512 hubbard_energy = hubbard_energy_noflip + hubbard_energy_flip - hubbard_energy_dc_contribution;
519 return hubbard_energy;
523generate_potential(Hubbard_matrix
const& om__, Hubbard_matrix& um__)
525 auto& ctx = om__.ctx();
527 for (
int at_lvl = 0; at_lvl < static_cast<int>(om__.local().size()); at_lvl++) {
528 const int ia = om__.atomic_orbitals(at_lvl).first;
529 auto& atype = ctx.unit_cell().atom(ia).type();
530 int lo_ind = om__.atomic_orbitals(at_lvl).second;
532 if (ctx.num_mag_dims() != 3) {
533 ::sirius::generate_potential_collinear_local(ctx, atype, lo_ind, om__.local(at_lvl), um__.local(at_lvl));
535 ::sirius::generate_potential_non_collinear_local(ctx, atype, lo_ind, om__.local(at_lvl),
540 for (
int i = 0; i < static_cast<int>(ctx.cfg().hubbard().nonlocal().size()); i++) {
542 if (ctx.num_mag_dims() != 3) {
543 ::sirius::generate_potential_collinear_nonlocal(ctx, i, om__.nonlocal(i), um__.nonlocal(i));
551energy(Hubbard_matrix
const& om__)
555 auto& ctx = om__.ctx();
557 for (
int at_lvl = 0; at_lvl < static_cast<int>(om__.local().size()); at_lvl++) {
558 const int ia = om__.atomic_orbitals(at_lvl).first;
559 auto& atype = ctx.unit_cell().atom(ia).type();
560 int lo_ind = om__.atomic_orbitals(at_lvl).second;
561 if (ctx.num_mag_dims() != 3) {
562 energy += ::sirius::calculate_energy_collinear_local(ctx, atype, lo_ind, om__.local(at_lvl));
564 energy += ::sirius::calculate_energy_non_collinear_local(ctx, atype, lo_ind, om__.local(at_lvl));
568 for (
int i = 0; i < static_cast<int>(ctx.cfg().hubbard().nonlocal().size()); i++) {
569 if (ctx.num_mag_dims() != 3) {
570 energy += ::sirius::calculate_energy_collinear_nonlocal(ctx, i, om__.nonlocal(i));
593one_electron_energy_hubbard(Hubbard_matrix
const& om__, Hubbard_matrix
const& pm__)
595 auto& ctx = om__.ctx();
596 if (ctx.hubbard_correction()) {
597 std::complex<double> tmp{0.0, 0.0};
598 for (
int at_lvl = 0; at_lvl < static_cast<int>(om__.local().size()); at_lvl++) {
599 const int ia = om__.atomic_orbitals(at_lvl).first;
600 int lo_ind = om__.atomic_orbitals(at_lvl).second;
601 auto& atype = ctx.unit_cell().atom(ia).type();
602 auto& hub_wf = atype.lo_descriptor_hub(lo_ind);
604 if (hub_wf.use_for_calculation()) {
605 auto src1 = om__.local(at_lvl).at(sddk::memory_t::host);
606 auto src2 = pm__.local(at_lvl).at(sddk::memory_t::host);
608 for (
int i = 0; i < static_cast<int>(om__.local(at_lvl).size()); i++) {
614 for (
int i = 0; i < static_cast<int>(ctx.cfg().hubbard().nonlocal().size()); i++) {
615 auto nl = ctx.cfg().hubbard().nonlocal(i);
619 const auto& n1 = om__.nonlocal(i);
620 const auto& n2 = pm__.nonlocal(i);
622 for (
int is = 0; is < ctx.num_spins(); is++) {
623 for (
int m2 = 0; m2 < 2 * jl + 1; m2++) {
624 for (
int m1 = 0; m1 < 2 * il + 1; m1++) {
625 tmp +=
std::conj(n2(m1, m2, is)) * n1(m1, m2, is);
631 if (ctx.num_spins() == 1) {
634 return std::real(tmp);
Contains declaration and partial implementation of sirius::Hubbard class.
Namespace of the SIRIUS library.
const double ha2ev
Hartree in electron-volt units.
int sign(T val)
Sign of the variable.
auto conj(double x__)
Return complex conjugate of a number. For a real value this is the number itself.