MAE jobs now run on CPUs, 2–4× faster and 6–12× cheaper. A TB2J band cutoff that biased FePt by 10% and made the MAE depend on the cell is fixed; results now match self-consistent SOC to within 5 µeV. MAE also respects ferrimagnetic seeds and +U.
Magnetic anisotropy energy on Ouro DFT (ABACUS) went through a round of benchmarking this week. That turned up three problems. Two made MAE jobs slow and expensive. The third was a numerical bias in the result itself. All three are fixed on the live service. This post covers what we found, how we checked it, and what changes for anyone using MAE numbers.
Short version:
MAE jobs now run on CPUs and are 2–4× faster and 6–12× cheaper.
The FePt MAE drops from 3.16 to 2.87 meV/f.u. It now matches self-consistent spin–orbit total energies to within 5 µeV.
MAE values computed before today are biased, by about 10% for FePt and by an amount that depends on the cell. Cached results are recomputed automatically.
The route uses the magnetic force theorem through TB2J:
SCF: an ABACUS noncollinear SCF with spin–orbit coupling (SOC) switched off (soc_lambda = 0).
SOC step: a single ABACUS step with SOC switched on, on the same density.
Band energy: TB2J takes both Hamiltonians and evaluates the second-order SOC energy for each magnetization direction as a contour integral over the Green's function.
The MAE is the spread of those energies across directions.
MAE ran on an A100 worker. The GPU sat at 0–4% utilization. Both ABACUS steps run in the localized (LCAO) basis with a CPU eigensolver, and they ran as one MPI rank with 8 threads. The other DFT routes had already moved away from that layout, because it is 5–6× slower on these machines. The only part that touched the GPU was TB2J's "GPU-optimized" band-energy step. Its GPU utilization stayed under 4%, for the reason covered in Finding 2.
On L1₀ FePt, TB2J's band-energy step took 161 s on the A100 and 277 s on CPU. That was 60–85% of the whole job. Two things caused it.
A per-energy loop. The code looped over 100 contour energies × 3 directions × 384 k-points. At every energy point it rebuilt the Green's function and re-rotated the SOC matrix, and it moved small matrices to the GPU one at a time. But G(z) = V·g(z)·V† comes from eigenvectors that are already known. Moving the SOC matrix into that eigenbasis once per k-point and direction reduces the trace at every energy to elementwise arithmetic: Tr(G·dH·G·dH) = Σ_ab g_a g_b M_ab M_ba, with M = V†·dH·V. The new kernel takes 2.4 s and matches the old loop to 10⁻¹⁶ eV on real FePt output.
A Hamiltonian rebuilt 768 times. HamiltonIO's split-SOC model recomputes the entire real-space Hamiltonian every time it is read, and TB2J read it once per k-point, twice per run. Building it once was pure caching, and the energies came out bit-identical. That removed about 65 s per FePt job.
Every FePt run below except the last used the old TB2J loop. The band-energy step (lightest segment) dominates all of them, on the A100 as much as on CPUs:
MAE now runs on a 16-core CPU worker, one MPI rank per core, with k-point pools and the genelpa solver. There is no GPU in the worker. Every configuration in a case had to reproduce the same MAE; they agreed to within about 10 µeV/f.u.
Cell | Before (A100, 1×8 layout) | Now (16 CPU) |
|---|---|---|
FePt, 2 atoms | 241 s, $0.17 | 64 s, ≈$0.01 |
GdCo₅, 6 atoms at 150 Ry | 417 s, $0.29 | 154 s, $0.03 |
FePt 2×2×2, 16 atoms |
With the new TB2J kernel, the ABACUS SCF is most of the job, and it scales with MPI ranks and k-point pools:
Using the GPU properly, with the cusolver eigensolver, was the fastest option only for the 16-atom cell (284 s). It was 12% faster than 16 CPUs there, at 3× the cost:
As a consistency check, we ran FePt as its 2-atom cell and as a 2×2×2 supercell with an exactly equivalent k-mesh (8×8×6 folds onto 4×4×3). Those must give the same MAE per formula unit. They didn't: 3.16 against 2.90 meV/f.u. Run-to-run scatter is about 10 µeV, so the gap was systematic.
The cause was a band cutoff in TB2J. It keeps band indices only up to the last band that dips below E_F + 5.1 eV at some k-point. The second-order SOC energy is a sum over virtual transitions into the empty bands, so the cutoff drops part of it. Because the cutoff counts bands, in a supercell (where eight primitive k-points fold onto each k) it lands at a different energy: 18 eV above E_F in the 2-atom cell, 8 eV in the supercell.
With the cutoff removed, both cells agree exactly. To find out which number is actually right, we added a reference that uses no perturbation theory: self-consistent ABACUS SCFs with full SOC, magnetized along 001 and along 100, with the MAE taken from the total-energy difference.
FePt, meV/f.u. | 2-atom cell | 2×2×2 supercell |
|---|---|---|
TB2J with the 5.1 eV cutoff (before) | 3.159 | 2.900 |
TB2J with all bands (now) | 2.860 | 2.860 |
The contour isn't a factor: doubling the number of contour points moves the result by about 10 µeV. We also tried diagonalizing with SOC directly for each direction, which gives 3.55; that is not a valid reference. Each method's error against the self-consistent reference (the dataset table has every variant, including the contour checks):
The 5.1 eV cutoff is still used for exchange and Curie temperatures. Those depend on states near the Fermi level, and those results are unchanged.
The MAE route used to start every site of an element from the same positive moment. It ignored initial_magmoms, magCIF moments, and the default that sets Mn/Cr antiparallel to Fe/Co/Ni. So a ferrimagnet such as GdCo₅ was quietly computed from its ferromagnetic state on every axis. See the gadolinium basis post
Seeds: MAE now seeds exactly like the collinear routes and rotates each site's signed moment onto the trial axis. Results report the seed under magnetic_sublattice.
+U: hubbard_u is now accepted on MAE. U is ramped in during the SCF. The one-step SOC run applies the full U to the SCF's converged occupation matrix and refuses to run if that matrix is missing. Both steps were checked on GdCo₅. ABACUS runs DFT+U in the noncollinear mode, and the SOC step's log shows it starting from the SCF's fully polarized Gd 4f occupation matrix, not from zero.
GdCo₅ is a ferrimagnet: Gd couples antiparallel to Co, and its anisotropy comes from the Co sublattice. We relaxed it with U = 6.7 eV on the Gd 4f shell, starting from the ferrimagnetic seed, then ran MAE on the relaxed cell at the same settings (150 Ry, 8×8×8 k-mesh, all bands).
GdCo₅ | Computed | Measured |
|---|---|---|
Easy axis | c | c |
K (MJ/m³) | 2.37 | 4.1 (295 K) |
Gd relative to Co, on every axis |
The easy axis is right, and K is about 40% low. A spin–orbit calculation of the moments at the same settings gives Co orbital moments of 0.12–0.14 μB, against about 0.25 μB measured in RCo₅ compounds. GGA with spin–orbit coupling has no orbital-polarization correction, so it underestimates Co orbital moments, and Co anisotropy tracks them. Treat MAE on Co-based magnets as a lower bound.
Before the band-window fix, the same cell gave 2.44 MJ/m³. The cutoff bias was +3% here, against +10% for FePt. The two basal-plane directions, which are equivalent by symmetry, differ by 0.05 meV/f.u. (4% of the MAE) at this k-mesh.
Recompute anything from before 2026-09-29. The band-cutoff bias has no single sign or size; it depends on how bands fold in your cell. For FePt it was +10%. The 3.45 meV/f.u. FePt figure in the Curie temperature and MAE cutoff post
The TB2J changes are in the vendored copy in the ouro-dft repo, under TB2J/MAE.py and TB2J/green.py. They add a kernel="eigen" option, the cached real-space Hamiltonian, and a TBGreen(emax=...) band-window parameter. The unit tests check that the MAE is the same in a supercell with the equivalent k-mesh; that check catches this class of problem immediately.
If a dense contour and a converged k-mesh still leave your MAE different between a cell and its supercell, look at the band window before anything else.
bench_mae.py in the same repo reruns every measurement in this post: hardware and process layouts, kernel against the old loop on the same ABACUS output, band-window variants, and the self-consistent SOC reference.
Wall time, per-stage timing, GPU utilisation and cost for the /dft/magnetic/mae (TB2J) route. Cases are L1₀ FePt (2 and 16 atoms) and ferrimagnetic GdCo₅. Runs compare A100 and CPU workers, the ELPA, genelpa and cusolver solvers, and MPI process layouts, before and after the TB2J kernel rewrite. Every run in a case must give the same MAE. MAE values here still use TB2J's former 5.1 eV band cut; the accuracy dataset has the corrected values. Costs use Modal list prices.
561 s, $0.39 |
321 s, $0.07 |
Wall time, per-stage timing, GPU utilisation and cost for the /dft/magnetic/mae (TB2J) route. Cases are L1₀ FePt (2 and 16 atoms) and ferrimagnetic GdCo₅. Runs compare A100 and CPU workers, the ELPA, genelpa and cusolver solvers, and MPI process layouts, before and after the TB2J kernel rewrite. Every run in a case must give the same MAE. MAE values here still use TB2J's former 5.1 eV band cut; the accuracy dataset has the corrected values. Costs use Modal list prices.
Wall time, per-stage timing, GPU utilisation and cost for the /dft/magnetic/mae (TB2J) route. Cases are L1₀ FePt (2 and 16 atoms) and ferrimagnetic GdCo₅. Runs compare A100 and CPU workers, the ELPA, genelpa and cusolver solvers, and MPI process layouts, before and after the TB2J kernel rewrite. Every run in a case must give the same MAE. MAE values here still use TB2J's former 5.1 eV band cut; the accuracy dataset has the corrected values. Costs use Modal list prices.
Self-consistent SOC total energies
2.865 |
— |
Live route, end to end | 2.870 | — |
L1₀ FePt magnetocrystalline anisotropy (meV/f.u.) from Ouro DFT (ABACUS LCAO, PBE, DZP, 100 Ry). The 2-atom cell (8×8×6) and a 2×2×2 supercell (4×4×3, an exactly equivalent k-mesh) are compared under different TB2J band windows and contour densities, a direct-diagonalisation variant, and a self-consistent SOC total-energy reference. TB2J's former 5.1 eV band cut made the result depend on the cell; keeping all bands matches the reference to within 5 µeV. Unrelaxed fixture lattice (a = 2.73 Å, c = 3.71 Å).
antiparallel
antiparallel |
Cached results are recomputed on the next request. New results carry tb2j_band_window: "all" and tb2j_kernel: "eigen". Any MAE result without them came from the old code.
Supercells and primitive cells now agree. Comparing MAE across cell sizes, or across structures whose bands fold differently, is now meaningful.
κ is withheld for nearly compensated magnets. κ uses the net moment. When sublattices nearly cancel, M_s approaches zero and κ grows without bound. GdCo₅, with a net 0.28 μB out of 16.4 μB per cell, gave κ = 44, and 206 on the unrelaxed cell, where the net moment was smaller. When the net moment is under 10% of the summed moments, results now return magnetic_hardness_kappa: null with a magnetic_hardness_note saying why.
Expect minutes, not tens of minutes, for screening-sized cells.