PAOFLOW.ACBN0#

ACBN0 self-consistent Hubbard U driver.

This module implements the ACBN0 pseudo-hybrid self-consistent determination of on-site Hubbard U corrections from first principles, following

L. A. Agapito, S. Curtarolo and M. Buongiorno Nardelli, Reformulation of DFT+U as a pseudo-hybrid Hubbard density functional for accelerated materials discovery, Phys. Rev. X 5, 011006 (2015).

The driver is exposed through the ACBN0 class. An instance orchestrates the full self-consistent cycle:

  1. Parse a user-supplied Quantum ESPRESSO <prefix>.scf.in template (and the matching <prefix>.nscf.in / <prefix>.projwfc.in).

  2. Fit each pseudopotential’s atomic wavefunctions to a contracted Gaussian basis (PAOFLOW.projection.upf_gaussfit) so the Coulomb integrals required by the ACBN0 formula can be evaluated analytically.

  3. On every outer iteration, inject the current HUBBARD card into the SCF/NSCF templates and run pw.x (scf), pw.x (nscf), projwfc.x, PAOFLOW and finally ACBN0_Hartree (under MPI).

  4. Recompute U for every Hubbard-active orbital from the ACBN0 numerator (renormalized two-electron integrals) and denominator (occupation-matrix invariants).

  5. Iterate until max U| < convergence_threshold.

The class is also the base of eACBN0, which adds intersite Hubbard V to the same workflow.

Typical usage#

from PAOFLOW.ACBN0 import ACBN0

a = ACBN0('MgO', workdir='./',
          mpi_qe='mpirun -np 8',
          mpi_python='mpirun -np 1',
          mpi_hartree='mpirun -np 8',
          qe_path='/path/to/qe/bin',
          python_path='/path/to/python/bin',
          outputdir='./tmp/')

# Equivalent ways to declare Hubbard-active orbitals:
a.set_hubbard_parameters(['Mg-3s', 'O-2p'])             # default U
a.set_hubbard_parameters({'Mg-3s': 1.0, 'O-2p': 8.0})   # custom U
a.set_hubbard_parameters({'O-2p': (8.0, 4.0)})          # +occupation

a.optimize_hubbard_U(convergence_threshold=0.01)

print(a.uVals)   # {'Mg-3s': ..., 'O-2p': ...}

Public API#

Internal helpers (prefixed with an underscore convention via their naming) handle Gaussian basis assembly per atom (ACBN0.getbasis()), construction of the k-resolved density matrix (ACBN0.Dk()), the back-Fourier transform to real space (ACBN0.DR()) and the on-site occupation invariants used in the ACBN0 denominator (ACBN0.Nmm()).

External tools#

The driver shells out to several commands. The launchers are configured at construction time:

  • pw.x and projwfc.x from qe_path, optionally prefixed by mpi_qe (e.g. 'mpirun -np 8') with extra options in qe_options (e.g. '-npool 4').

  • PAOFLOW is launched as a separate Python process under mpi_python (typically 'mpirun -np 1' because PAOFLOW’s MPI scaling is workflow-dependent and the call here is short).

  • The Hartree integrals (ACBN0_Hartree) are launched as a separate Python process under mpi_hartree, which defaults to mpi_python but can be overridden — typically with a larger -np because the pure-Python four-centre Coulomb integrals dominate the wall time for heavy d/f shells.

Conventions#

  • Energies are in eV; the input celldm(1) / lattice quantities are read in their native QE units (Bohr / Å) and converted internally where required.

  • Atom indices follow the QE convention: 1-based, ordered as they appear in the ATOMIC_POSITIONS card.

  • Orbital labels are written as '<element>-<n><l>', e.g. 'Mn-3d', 'O-2p'. In magnetic AFM cells with distinct sublattices, the element symbol in the input may be tagged ('MnA', 'MnB') and the same tag must be used in the U keys.

  • The class respects an existing HUBBARD card in the template: any U/V entries already present are loaded into self.uVals and self.vVals at construction time.

Attributes set at construction#

  • uVals (dict[str, float]) — current U values, keyed by 'species-orbital'.

  • vVals (dict[tuple, float]) — current intersite V values (populated by eACBN0).

  • uspecies (list[str]) — atomic species discovered in the ATOMIC_SPECIES card.

  • basis (dict[str, list]) — per-species fitted Gaussian basis from PAOFLOW.projection.upf_gaussfit.gaussian_fit().

  • blocks / cards — parsed namelists / cards of the SCF input template, as returned by PAOFLOW.inputs.file_io.struct_from_inputfile_QE().

  • nspin — read from the &system block (defaults to 1).

  • hubbard_tag — header line of the HUBBARD card (e.g. 'HUBBARD (atomic)').

  • hubbard_occ — fixed hubbard_occ(i,j) entries to be written back into the &system namelist.

Notes

  • The first thing __init__() does after parsing the template is to write compute_hartree.py into the current directory; this small launcher is what gets executed under mpi_hartree for the Coulomb integrals.

  • The PAOFLOW step launched by run_paoflow() calls pao_hamiltonian(write_binary=True, expand_wedge=False): Hks is kept on whichever k-grid QE produced (IBZ when symmetries are on, full BZ when nosym = noinv = .true.) and is written to disk without any FFT to real space. The reshape to (nawf, nawf, nk1, nk2, nk3, nspin) in PAOFLOW.hamiltonian.do_build_pao_hamiltonian.do_build_pao_hamiltonian() is therefore skipped for ACBN0; both IBZ and full-BZ k-grids are accepted.

  • PAOFLOW.hamiltonian.do_build_pao_hamiltonian.build_Hks() now applies a per-k projectability filter (pthr_local, defaulting to 0.5 * pthr) in addition to the global pthr. Bands whose local PAO projection at a given k vanishes (typically one of a degenerate set at high-symmetry points such as Γ, where QE’s gauge choice can leave it with near-zero atomic-orbital content) are dropped from the construction at that k-point only. Without this guard the previous code renormalised the vanishing projection vector to unit norm, corrupting H(k) at high-symmetry points and, in turn, the occupations entering the ACBN0 numerator/denominator.

Attributes#

Classes#

ACBN0_Hartree

MPI worker for the ACBN0 on-site Hartree / exchange integrals.

eACBN0_Hartree

MPI-parallel evaluator of the intersite Hubbard V numerator.

ACBN0

eACBN0

Extended ACBN0 (DFT+U+V) driver.

Module Contents#

PAOFLOW.ACBN0.BOHR_RADIUS_ANGS = 0.529177210903[source]#
PAOFLOW.ACBN0.ANGS_TO_BOHR = 1.8897261246257702[source]#
PAOFLOW.ACBN0.HARTREE_TO_EV = 27.211396132[source]#
class PAOFLOW.ACBN0.ACBN0_Hartree(datafile)[source]#

Bases: _HartreeKernel

MPI worker for the ACBN0 on-site Hartree / exchange integrals.

Invoked by ACBN0 as a standalone MPI Python program (typically through the auto-generated compute_hartree.py launcher) to evaluate the four-centre Coulomb sums that make up the ACBN0 numerator for a single Hubbard site.

Given the renormalized real-space density matrix D(R=0) per spin channel (built by ACBN0.DR() from the PAOFLOW dump) and the contracted-Gaussian basis fitted to the pseudopotential atomic wavefunctions, the kernel accumulates

\[ \begin{align}\begin{aligned}U_{\text{num}} = \sum_{abcd} (ab|cd)\, D^{\text{tot}}_{ab}\, D^{\text{tot}}_{cd}, \qquad D^{\text{tot}} = D^{\uparrow} + D^{\downarrow}\\J_{\text{num}} = \sum_{abcd} (ac|bd)\, \bigl[ D^{\uparrow}_{ab}\, D^{\uparrow}_{cd} + D^{\downarrow}_{ab}\, D^{\downarrow}_{cd} \bigr]\end{aligned}\end{align} \]

where the four indices run over basis_2e (the Hubbard-active subshell), the two-electron integrals (ab|cd) = ∫∫ φ_a(r₁) φ_b(r₁) (1/r₁₂) φ_c(r₂) φ_d(r₂) dr₁ dr₂ are evaluated analytically by PAOFLOW.utils.pyints.contr_coulomb() over contracted Cartesian Gaussians, and the spin pre-factors follow the ACBN0 decomposition (Agapito et al., Phys. Rev. X 5, 011006 (2015)). The U sum factorises through D^{tot} = D↑ + D↓ (Hartree-like, full σσ’ sum); the J sum carries only the like-spin pieces under the (ac|bd) index permutation.

No self-exchange exclusion is applied to the J sum: empirically the no-exclusion form reproduces the published ACBN0 / Lee – Son benchmark U values (e.g. ZnO Zn-3d ≈ 15.47 eV, O-2p ≈ 7.33 eV with ortho-atomic projection), whereas the strict Eq. (11) form with the (m,n) = (k,l) term removed does not.

Parallelization#

Only the unique 4-tuples (a, b, c, d) under the 8-fold permutation symmetry (ab|cd) = (ba|cd) = (ab|dc) = (cd|ab) of real Cartesian Gaussians are enumerated (canonical form: a b, c d, (a, b) (c, d)). These are split into self.size chunks with numpy.array_split(), scattered with comm.scatter, evaluated locally and allgather-ed so every rank holds the full eri_dict. Each rank unfolds the dict into the full (n_2e)^4 ERI tensor and contracts it with the density-matrix sub-blocks via numpy.einsum(). The result is replicated on every rank, so no ``MPI.SUM`` reduce is performed — the pickle <outputdir>/tmp_uj.pkl is written from rank 0 only.

Cost scales as len(basis_2e) ** 4 times the (primitive count) ** 4 inside contr_coulomb(). For light p-shells (e.g. O-2p, len(basis_2e) = 3) the kernel finishes in milliseconds even at -np 1; for heavy d-shells (e.g. Mn-3d, len(basis_2e) = 5 with up to 15 primitives per basis function) the cost runs into tens of millions of Boys-function evaluations and benefits substantially from running under mpirun -np N with N matching the number of physical cores — hence the dedicated mpi_hartree knob in ACBN0.

Input format#

The driver writes a pickle file at datafile (broadcast to all ranks in __init__()) containing:

  • 'DR_up', 'DR_dn'(nbasis, nbasis) complex arrays, the renormalized real-space density matrices (R=0) per spin channel.

  • 'basis' — list of PAOFLOW.utils.pyints.CGBF contracted Gaussian basis functions covering the entire site.

  • 'basis_2e' — list of integer indices into basis selecting the Hubbard-active subshell over which the four-index sum is taken (e.g. the 5 d-orbitals of a transition-metal site).

Output#

<outputdir>/tmp_uj.pkl (rank 0 only): a dictionary {'U': float, 'J': float} holding the unnormalized numerator sums as real Python floats. The driver divides these by the denominator (ACBN0.Nmm()) to obtain the final U and J in eV.

The real-valued type is load-bearing: QE’s card_hubbard parser rejects complex-formatted Hubbard values, so the ERI tensor is allocated dtype=float, the density-matrix sub-blocks are .real-coerced, and the einsum results are wrapped in float(…) before pickling.

Notes

The class imports mpi4py at module level, so simply importing it in a non-MPI Python process is harmless (it initialises a singleton communicator with size 1). In that mode the kernel runs serially and takes the full basis_2e ** 4 cost on a single core.

hartree_energy(outputdir)[source]#
class PAOFLOW.ACBN0.eACBN0_Hartree(datafile)[source]#

Bases: _HartreeKernel

MPI-parallel evaluator of the intersite Hubbard V numerator.

Companion class to eACBN0. Implements the spin-summed Coulomb sum that appears in the numerator of Eq. (8) of

S.-H. Lee and Y.-W. Son, First-principles approach with a pseudo-hybrid density functional for extended Hubbard interactions, Phys. Rev. Research 2, 043410 (2020),

\[V^{IJ}(R) = \tfrac{1}{2}\,\frac{\text{num}}{\text{den}}\]

with the numerator

\[\text{num} = \sum_{\sigma\sigma'}\sum_{ikjl} \Bigl[ P^{II\sigma}_{ik}\, P^{JJ\sigma'}_{jl} - \delta_{\sigma\sigma'}\, P^{IJ\sigma}_{il}\, P^{JI\sigma}_{jk} \Bigr]\,(ik|jl).\]

The renormalized pair density matrices P^{II}, P^{JJ}, P^{IJ}(R), P^{JI}(-R) are built by eACBN0._pair_density_matrices() from the PAOFLOW Hamiltonian/overlap dump (Eqs. (4)–(5) of the reference); the two-electron integral (ik|jl) = ∫∫ φ_i^I(r₁) φ_k^I(r₁) (1/r₁₂) φ_j^J(r₂) φ_l^J(r₂) dr₁ dr₂ is evaluated analytically over contracted Cartesian Gaussians by PAOFLOW.utils.pyints.contr_coulomb().

The denominator of Eq. (8) is built directly on the driver side in eACBN0.run_eacbn0_V() from the bare occupation matrices n^{II}, n^{JJ}, n^{IJ}, n^{JI} and combined with the numerator returned by this kernel to obtain V in eV.

Geometry convention#

The basis functions gauss_I are centred at the home-cell position of atom I, while gauss_J are centred at r_J + R*, where R* is the minimum-image lattice translation selected by eACBN0.run_eacbn0_V(). As a result, indices i, k run over the Gaussians on atom I and j, l over the translated Gaussians on atom J; no further phase factors are required inside the kernel.

Parallelization#

Only the unique 4-tuples (i, k, j, l) under the 4-fold permutation symmetry (ik|jl) = (ki|jl) = (ik|lj) are enumerated (canonical form: i k, j l). Because atoms I and J are distinct, the electron-swap symmetry (ik|jl) = (jl|ik) does not apply — only 4-fold (not 8-fold) reduction is available. The unique keys are split into self.size chunks with numpy.array_split(), scattered with comm.scatter, evaluated locally and allgather-ed so every rank holds the full eri_dict. Each rank unfolds it into the (n_I, n_I, n_J, n_J) ERI tensor and contracts via numpy.einsum() (direct via PII_sum/PJJ_sum; same-spin exchange via P_IJ/P_JI). The result is replicated on every rank, so no ``MPI.SUM`` reduce is performed — the pickle <outputdir>/tmp_v.pkl is written from rank 0 only.

Cost scales as n_I² × n_J² × (primitive count)⁴ inside contr_coulomb(). For two p-shells (n_I = n_J = 3) the kernel finishes in a few seconds even at -np 1; for a d–p pair (e.g. Mn-3d to O-2p, n_I = 5, n_J = 3) with the full multi-zeta Gaussian fits the cost runs into tens of millions of Boys-function evaluations and benefits substantially from running under mpirun -np N with N matching the number of physical cores — hence the dedicated mpi_hartree knob in ACBN0, which is reused here.

Input format#

The driver writes a pickle file at datafile (broadcast to all ranks in __init__()) containing one entry per pair:

  • 'gauss_I', 'gauss_J' — lists of PAOFLOW.utils.pyints.CGBF contracted Gaussian basis functions covering the Hubbard-active shells on atoms I and J, with origins in Bohr (J already translated by R*).

  • 'P_II_up', 'P_II_dn'(n_I, n_I) complex on-site renormalized DMs on atom I, per spin channel.

  • 'P_JJ_up', 'P_JJ_dn'(n_J, n_J) complex on-site renormalized DMs on atom J, per spin channel.

  • 'P_IJ_up', 'P_IJ_dn'(n_I, n_J) complex intersite renormalized DMs at displacement +R*.

  • 'P_JI_up', 'P_JI_dn'(n_J, n_I) complex intersite renormalized DMs at displacement -R*.

For spin-restricted runs (nspin == 1) the driver passes identical up/down halves so that the spin pre-factors below reduce to the spin-restricted form automatically.

Output#

<outputdir>/tmp_v.pkl (rank 0 only): a dictionary {'num': complex} holding the unnormalized numerator sum (no 1/2 prefactor — that factor is applied on the driver side together with the denominator).

Spin structure#

The bracket [direct exchange] inside the four-index sum factorises into two pieces:

  • Direct (Hartree) — full σ × σ' double sum, equal to (P^{II}_up + P^{II}_dn)_{ik} × (P^{JJ}_up + P^{JJ}_dn)_{jl}. Pre-computed once outside the inner loop as PII_sum / PJJ_sum.

  • Exchange — same-spin only (δ_{σσ'}), summing P^{IJ}_{σ}_{il} × P^{JI}_{σ}_{jk} over σ {up, dn}.

Notes

The class imports mpi4py at module level, so simply importing it in a non-MPI Python process is harmless (it initialises a singleton communicator with size 1). In that mode the kernel runs serially and takes the full n_I² × n_J² cost on a single core.

intersite_energy(outputdir)[source]#

Evaluate the numerator of Eq. (8) and pickle the result to <outputdir>/tmp_v.pkl.

class PAOFLOW.ACBN0.ACBN0(prefix, pthr=0.95, workdir='./', mpi_qe='', nproc=1, qe_path='', qe_options='', mpi_python='', python_path='', outputdir='./output/', projection='ortho-atomic', mpi_hartree=None, use_local_basis=False, basispath=None, configuration='standard', gaussian_threshold=0.01)[source]#
prefix[source]#
pthr = 0.95[source]#
workdir = './'[source]#
mpi_qe = ''[source]#
nproc = 1[source]#
qpath = ''[source]#
mpi_python = ''[source]#
mpi_hartree[source]#
ppath = ''[source]#
qoption = ''[source]#
projection = 'ortho-atomic'[source]#
outputdir = './output/'[source]#
use_local_basis = False[source]#
basispath = None[source]#
configuration = 'standard'[source]#
gaussian_threshold[source]#
uVals[source]#
vVals[source]#
occ_states[source]#
occ_values[source]#
hubbard_occ[source]#
hubbard_tag = 'HUBBARD (ortho-atomic)'[source]#
expand_wedge = True[source]#
basis[source]#
basis_labels[source]#
uspecies = [][source]#
set_hubbard_parameters(hubbard)[source]#
set_intersite_V_parameters(vpairs)[source]#

Register intersite Hubbard V pairs and their initial values.

Parameters:

vpairs (list, tuple, or dict) – Either an iterable of (label1, label2, atom_idx1, atom_idx2, V_init) tuples, or a dict mapping (label1, label2, atom_idx1, atom_idx2) to V_init. label* follow the QE species-orbital convention (e.g. 'Ni-3d'); atom_idx* are 1-based atom indices as used in the QE HUBBARD card. V_init may be None, in which case 0.01 eV is used as a seed.

optimize_hubbard_U(convergence_threshold=0.01)[source]#
exec_QE(executable, fname)[source]#
exec_PAOFLOW()[source]#
hubbard_card()[source]#
run_dft(prefix, species, uVals)[source]#
run_paoflow(prefix, save_prefix)[source]#
read_cell_atoms(fname)[source]#
hubbard_orbital(ele)[source]#
run_acbn0(prefix)[source]#
getbasis(basis, species, lattice, coords)[source]#
Dk(basis_dm, basis_2e, Hks, Sks, eigvec_cache=None)[source]#

Build the per-k density matrix D(k) and the per-k Mulliken projection n_{lm}(k) on basis_2e for the occupied manifold.

Parameters:
  • basis_dm (1D int ndarray) – PAO indices defining the density-matrix block and the two-electron-integral block, respectively.

  • basis_2e (1D int ndarray) – PAO indices defining the density-matrix block and the two-electron-integral block, respectively.

  • Hks ((nbasis, nbasis, nkpnts) complex ndarray)

  • Sks ((nbasis, nbasis, nkpnts) complex ndarray)

  • eigvec_cache (list of (eig, vec) or None, optional) – If provided, the per-k generalized eigenproblem is not re-solved; values from the cache are used instead. Produced by _eigh_all_k().

Nmm(nlm, Hks, kwght)[source]#
DR(Dk, kwght)[source]#
read_ham_data(nspin)[source]#
class PAOFLOW.ACBN0.eACBN0(*args, **kwargs)[source]#

Bases: ACBN0

Extended ACBN0 (DFT+U+V) driver.

This class implements the extended ACBN0 self-consistent scheme that augments the standard on-site Hubbard U calculation with the intersite Hubbard V correction, following the formulation of

S.-H. Lee and Y.-W. Son, First-principles approach with a pseudo-hybrid density functional for extended Hubbard interactions, Phys. Rev. Research 2, 043410 (2020).

Subclass of ACBN0. eACBN0 reuses the entire on-site U machinery (template parsing, pw.x / projwfc.x / PAOFLOW launches, ACBN0 Hartree integrals, HUBBARD card emission) and adds the bookkeeping and numerics required to evaluate V for an arbitrary set of atomic pairs — including their periodic images.

Theoretical background#

Given a pair of Hubbard-active sites (I, J) separated by a Bravais lattice translation R, the intersite Hubbard parameter is defined as (Eq. 8 of the reference)

\[V^{IJ}(R) = \frac{ \frac{1}{2}\sum_{ijkl, \sigma\sigma'} P^{IJ\sigma}_{ij}(R)\, P^{JI\sigma'}_{kl}(-R)\, (ij|kl) }{ \sum_{ij, \sigma\sigma'} n^{II\sigma}_{ii} n^{JJ\sigma'}_{jj} - \sum_{ij, \sigma} n^{IJ\sigma}_{ij}(R) n^{JI\sigma}_{ji}(-R) }\]

with the bare on-site / intersite occupation matrices n defined by Eq. (2) and their renormalized counterparts P defined by Eqs. (4) and (5). The four-centre electron-repulsion integrals (ij|kl) are evaluated in the auxiliary Gaussian basis fitted to the PAO numerical wavefunctions (the same basis used by ACBN0_Hartree).

Workflow#

The typical usage mirrors ACBN0 but adds a pair-selection step and uses optimize_hubbard_UV() instead of optimize_hubbard_U:

from PAOFLOW.ACBN0 import eACBN0

e = eACBN0('MnO', workdir='./',
           mpi_qe='mpirun -np 8',
           mpi_python='mpirun -np 1',
           mpi_hartree='mpirun -np 8',
           qe_path='/path/to/qe/bin',
           python_path='/path/to/python/bin',
           outputdir='./tmp/')

e.set_hubbard_parameters({'Mn-3d': 5.0, 'O-2p': 1.0})
e.set_intersite_pairs(cutoff=2.5, V_init=0.5)
e.optimize_hubbard_UV(convergence_threshold=0.05, max_iter=25,
                      mixing=0.7)

Each outer iteration of eACBN0.optimize_hubbard_UV():

  1. Writes the current HUBBARD card (U on every declared orbital, V on every registered pair) into the SCF/NSCF templates and runs pw.x (scf), pw.x (nscf) and projwfc.x.

  2. Runs PAOFLOW to produce the PAO Hamiltonian/overlap and the reduced-zone k-grid dumps.

  3. Calls eACBN0.run_acbn0() for the on-site U values.

  4. Calls eACBN0.run_eacbn0_V() which, for every registered pair, builds the pair density matrices and dispatches the four-centre integral evaluation to compute_hartree_v.py under mpi_hartree.

  5. Applies linear mixing to both U and V and checks for convergence (max |Δ| < convergence_threshold across all parameters).

Public API#

Class eACBN0 adds the following methods on top of ACBN0:

  • eACBN0.set_intersite_pairs() — register V pairs either from an explicit list (with optional (n_a, n_b, n_c) image labels) or via a real-space cutoff search restricted to user-selected species pairs.

  • eACBN0.print_intersite_pairs() — print a human-readable summary of every registered pair (atom indices, image, distance, seed V).

  • eACBN0.run_eacbn0_V() — evaluate Eq. (8) for every registered pair using the current PAOFLOW dump and projwfc.out. Collapses multiple images of the same (label1, label2, i1, i2) key to the minimum-image representative.

  • eACBN0.optimize_hubbard_UV() — joint U+V self-consistent loop with linear mixing.

Internal helpers (prefixed with an underscore) implement geometry parsing from the QE input cards (eACBN0._geometry_from_cards()), periodic neighbour enumeration with cell-shape-aware image windows (eACBN0._image_window(), eACBN0._enumerate_pairs()), construction of per-site contracted-Gaussian basis functions (eACBN0._atom_shell_gaussians()), pair density-matrix assembly (eACBN0._pair_density_matrices()) and the MPI launcher for the four-centre integrals (eACBN0._launch_compute_hartree_v()).

Conventions#

  • Energies are in eV; lengths are in Ångström in the public API and in Bohr internally where the Gaussian integrals require it.

  • Atom indices follow the QE convention: 1-based, ordered as listed in the ATOMIC_POSITIONS card.

  • Periodic images are labelled by integer triples (n_a, n_b, n_c) applied to atom i2 of a pair: R = n_a a_1 + n_b a_2 + n_c a_3.

  • k-points returned by PAOFLOW are in crystal coordinates by default; pass kpnts_are_cartesian=True to eACBN0.run_eacbn0_V() (and hence to eACBN0.optimize_hubbard_UV()) if your PAOFLOW dump uses Cartesian Bohr-1 instead.

  • mpi_hartree (kwarg of the underlying ACBN0) controls the MPI launcher for the pure-Python Coulomb integrals; it can — and usually should — differ from mpi_python, which controls the PAOFLOW step.

param *args:

Forwarded verbatim to ACBN0.

param **kwargs:

Forwarded verbatim to ACBN0.

Notes

  • Spin-restricted runs (nspin = 1) reuse a single density matrix for both spin channels by halving the doubly-occupied DM, so that the on-site limit (I = J, R = 0) reproduces the standard ACBN0 result exactly.

  • The underlying PAOFLOW call uses pao_hamiltonian(write_binary=True, expand_wedge=True). The resulting Hks is on the full BZ produced by QE The reshape to (nawf, nawf, nk1, nk2, nk3, nspin) in PAOFLOW.hamiltonian.do_build_pao_hamiltonian.do_build_pao_hamiltonian() is now guarded by an array-size check, so the same code path also handles the IBZ k-grid that arises from the bare ACBN0 (U-only) stage when run without nosym/noinv.

  • PAOFLOW.hamiltonian.do_build_pao_hamiltonian.build_Hks() now applies a per-k projectability filter (pthr_local, defaulting to 0.5 * pthr) in addition to the global pthr. Bands whose local PAO projection at a given k vanishes (typically one of a degenerate set at high-symmetry points such as Γ, where QE’s gauge choice can leave it with near-zero atomic-orbital content) are dropped from the construction at that k-point only. Without this guard the previous code renormalised the vanishing projection vector to unit norm, corrupting H(k) at high-symmetry points and, in turn, the occupations entering the ACBN0 / eACBN0 numerators and denominators.

vPairs[source]#
set_intersite_pairs(pairs=None, cutoff=None, include_onsite=False, species_pairs=None, V_init=0.01)[source]#

Register intersite Hubbard V pairs.

Exactly one of pairs or cutoff must be given (or both — in which case the explicit list is registered first, then the cutoff search augments it).

Parameters:
  • pairs (list of tuple, optional) – Explicit pair list. Each entry is either (label1, label2, atom_idx1, atom_idx2, V_init) (home cell, image = (0,0,0)) or (label1, label2, atom_idx1, atom_idx2, n_a, n_b, n_c, V_init). Atom indices are 1-based. V_init may be None to use the V_init keyword default.

  • cutoff (float, optional) – Real-space cutoff in Ångström. All ordered (i, j, R) atom pairs whose separation lies within cutoff are enumerated for every label pair selected by species_pairs.

  • include_onsite (bool, default False) – When True the cutoff search also includes the trivial (i, i, R = 0) pairs.

  • species_pairs (list of (str, str), optional) – Restrict the cutoff search to these (label1, label2) pairs. Defaults to every unordered pair of currently declared Hubbard orbitals (both directions stored).

  • V_init (float, default 0.01) – Seed V value (eV) used when an entry’s V_init is None and for cutoff-enumerated pairs.

print_intersite_pairs()[source]#

Print a human-readable summary of the registered V pairs.

run_eacbn0_V(kpnts_are_cartesian=False)[source]#

Compute intersite Hubbard V for every pair registered in self.vPairs and return the updated mapping.

Assumes that run_dft + run_paoflow have already produced projwfc.out and the PAOFLOW Hamiltonian/overlap dumps in self.outputdir.

Parameters:

kpnts_are_cartesian (bool, default False) – By default PAOFLOW writes k.txt in crystal coordinates (units of the reciprocal lattice vectors). Set this to True if the k-points are already in Cartesian Bohr$^{-1}$ (in which case R_bohr is used directly).

Returns:

new_V{(label1, label2, atom_idx1, atom_idx2): V_eV} — one entry per image-collapsed pair. When several images of the same pair are registered the values reported here are those of the closest (minimum-image) image.

Return type:

dict

optimize_hubbard_UV(convergence_threshold=0.01, max_iter=50, mixing=1.0, kpnts_are_cartesian=False)[source]#

Joint ACBN0 + eACBN0 self-consistent loop.

Each outer iteration runs pw.x (scf+nscf), projwfc.x, PAOFLOW and then both run_acbn0() and run_eacbn0_V(). Convergence is declared when all U and V parameters change by less than convergence_threshold between consecutive iterations.

Parameters:
  • convergence_threshold (float, default 0.01) – Maximum allowed absolute change (in eV) of any U or V value between iterations.

  • max_iter (int, default 50) – Hard cap on the number of outer iterations.

  • mixing (float, default 1.0) – Linear-mixing factor applied to both U and V: 1.0 fully replaces the previous parameters with the freshly-computed ones; smaller values dampen oscillations (e.g. mixing=0.5 uses new = 0.5*old + 0.5*computed).

  • kpnts_are_cartesian (bool, default False) – Forwarded to run_eacbn0_V().

Raises:

RuntimeError – If convergence is not achieved within max_iter iterations.