In this example we consider iron in the BCC phase. To show that this material is ferromagnetic we will model it once allowing collinear spin polarization and once without and compare the resulting SCF energies. In particular the ground state can only be found if collinear spins are allowed.
The bulk(:Fe)
function from AtomsBuilder
returns a BCC iron setup
with a single iron atom inside the unit cell.
using AtomsBuilder
using PseudoPotentialData
using DFTK
bulk(:Fe)
FlexibleSystem(Fe, periodicity = TTT): cell_vectors : [ -1.435 1.435 1.435; 1.435 -1.435 1.435; 1.435 1.435 -1.435]u"Å" Atom(Fe, [ 0, 0, 0]u"Å")
First we consider a setup without spin polarization. To get the ground-state energy of this system we use an LDA model and rather moderate discretisation parameters.
Ecut = 15 # kinetic energy cutoff in Hartree
kgrid = [3, 3, 3] # k-point grid (Regular Monkhorst-Pack grid)
pseudopotentials = PseudoFamily("cp2k.nc.sr.lda.v0_1.largecore.gth")
model_nospin = model_DFT(bulk(:Fe); pseudopotentials, functionals=LDA(), temperature=0.01)
basis_nospin = PlaneWaveBasis(model_nospin; kgrid, Ecut)
scfres_nospin = self_consistent_field(basis_nospin; tol=1e-4, mixing=KerkerDosMixing());
n Energy log10(ΔE) log10(Δρ) Diag Δtime --- --------------- --------- --------- ---- ------ 1 -16.64990766117 -0.48 6.0 106ms 2 -16.65069065739 -3.11 -1.02 1.0 987ms 3 -16.65082247135 -3.88 -2.29 1.8 15.6ms 4 -16.65083408029 -4.94 -2.82 1.8 35.2ms 5 -16.65083460178 -6.28 -3.39 1.8 15.8ms 6 -16.65083463547 -7.47 -3.97 1.8 16.3ms 7 -16.65083463698 -8.82 -4.40 1.2 14.1ms
scfres_nospin.energies
Energy breakdown (in Ha): Kinetic 15.9210257 AtomicLocal -5.0694048 AtomicNonlocal -5.2203365 Ewald -21.4723279 PspCorrection 1.8758893 Hartree 0.7793684 Xc -3.4467610 Entropy -0.0182879 total -16.650834636981
Since we did not specify any initial magnetic moment on the iron atom, DFTK will automatically assume that a calculation with only spin-paired electrons should be performed. As a result the obtained ground state features no spin-polarization.
Now we repeat the calculation, but give the iron atom an initial magnetic moment.
For specifying the magnetic moment pass the desired excess of spin-up over spin-down
electrons at each centre to the Model
and the guess density functions.
In this case we seek the state with as many spin-parallel
d-electrons as possible. In our pseudopotential model the 8 valence
electrons are 1 pair of s-electrons, 1 pair of d-electrons
and 4 unpaired d-electrons giving a desired magnetic moment of 4
at the iron centre.
The structure (i.e. pair mapping and order) of the magnetic_moments
array needs to agree
with the atoms
array and 0
magnetic moments need to be specified as well.
magnetic_moments = [4];
Units of the magnetisation and magnetic moments in DFTK
Unlike all other quantities magnetisation and magnetic moments in DFTK are given in units of the Bohr magneton μB, which in atomic units has the value 12. Since μB is (roughly) the magnetic moment of a single electron the advantage is that one can directly think of these quantities as the excess of spin-up electrons or spin-up electron density.
We repeat the calculation using the same model as before. DFTK now detects the non-zero moment and switches to a collinear calculation.
model = model_DFT(bulk(:Fe); pseudopotentials, functionals=LDA(),
temperature=0.01, magnetic_moments)
basis = PlaneWaveBasis(model; Ecut, kgrid)
ρ0 = guess_density(basis, magnetic_moments)
scfres = self_consistent_field(basis, tol=1e-6; ρ=ρ0, mixing=KerkerDosMixing());
n Energy log10(ΔE) log10(Δρ) Magnet Diag Δtime --- --------------- --------- --------- ------ ---- ------ 1 -16.66153297484 -0.51 2.617 5.8 52.5ms 2 -16.66821825534 -2.17 -1.10 2.442 1.5 542ms 3 -16.66906163239 -3.07 -2.08 2.340 2.1 33.3ms 4 -16.66910898959 -4.32 -2.59 2.304 1.2 38.8ms 5 -16.66911287671 -5.41 -2.92 2.296 1.6 29.5ms 6 -16.66911415962 -5.89 -3.52 2.287 1.6 38.4ms 7 -16.66911419901 -7.40 -3.88 2.286 2.0 33.2ms 8 -16.66911420292 -8.41 -4.38 2.286 1.4 31.0ms 9 -16.66911420356 -9.19 -4.92 2.286 2.0 33.7ms 10 -16.66911420356 -11.84 -5.36 2.286 1.9 35.7ms 11 -16.66911420359 -10.56 -5.68 2.286 1.5 41.6ms 12 -16.66911420357 + -10.76 -6.25 2.286 1.4 34.5ms
scfres.energies
Energy breakdown (in Ha): Kinetic 16.2947678 AtomicLocal -5.2227278 AtomicNonlocal -5.4100645 Ewald -21.4723279 PspCorrection 1.8758893 Hartree 0.8191974 Xc -3.5406874 Entropy -0.0131612 total -16.669114203573
Model and magnetic moments
DFTK does not store the
magnetic_moments
inside theModel
, but only uses them to determine the lattice symmetries. This step was taken to keepModel
(which contains the physical model) independent of the details of the numerical details such as the initial guess for the spin density.
In direct comparison we notice the first, spin-paired calculation to be a little higher in energy
println("No magnetization: ", scfres_nospin.energies.total)
println("Magnetic case: ", scfres.energies.total)
println("Difference: ", scfres.energies.total - scfres_nospin.energies.total);
No magnetization: -16.650834636980612 Magnetic case: -16.66911420357297 Difference: -0.01827956659235852
Notice that with the small cutoffs we use to generate the online documentation the calculation is far from converged. With more realistic parameters a larger energy difference of about 0.1 Hartree is obtained.
The spin polarization in the magnetic case is visible if we consider the occupation of the spin-up and spin-down Kohn-Sham orbitals. Especially for the d-orbitals these differ rather drastically. For example for the first k-point:
iup = 1
idown = iup + length(scfres.basis.kpoints) ÷ 2
@show scfres.occupation[iup][1:7]
@show scfres.occupation[idown][1:7];
(scfres.occupation[iup])[1:7] = [1.0, 0.9999987814893441, 0.9999987814893441, 0.9999987814893441, 0.9582259017977371, 0.9582259017977314, 1.1262950626068981e-29] (scfres.occupation[idown])[1:7] = [1.0, 0.8438955204083867, 0.8438955204082961, 0.8438955204082134, 8.140815021241912e-6, 8.140815021239569e-6, 1.6090720436130247e-32]
Similarly the eigenvalues differ
@show scfres.eigenvalues[iup][1:7]
@show scfres.eigenvalues[idown][1:7];
(scfres.eigenvalues[iup])[1:7] = [-0.0693578257610156, 0.3568864145673599, 0.3568864145673604, 0.35688641456736253, 0.4617371438838127, 0.4617371438838141, 1.1596255561345337] (scfres.eigenvalues[idown])[1:7] = [-0.03125673116770098, 0.4761901828505684, 0.4761901828505753, 0.47619018285058157, 0.6102513357361391, 0.610251335736142, 1.225135867903648]
k-points in collinear calculations
For collinear calculations the
kpoints
field of thePlaneWaveBasis
object contains each k-point coordinate twice, once associated with spin-up and once with down-down. The list first contains all spin-up k-points and then all spin-down k-points, such thatiup
andidown
index the same k-point, but differing spins.
We can observe the spin-polarization by looking at the density of states (DOS) around the Fermi level, where the spin-up and spin-down DOS differ.
using Plots
bands_666 = compute_bands(scfres, MonkhorstPack(6, 6, 6)) # Increase kgrid to get nicer DOS.
plot_dos(bands_666)
Note that if same k-grid as SCF should be employed, a simple plot_dos(scfres)
is sufficient.
Similarly the band structure shows clear differences between both spin components.
using Unitful
using UnitfulAtomic
bands_kpath = compute_bands(scfres; kline_density=6)
plot_bandstructure(bands_kpath)