Wannier localizationĀ¶

InĀ [1]:
import glob

import numpy as np

from eminus import Atoms, read, SCF
from eminus.extras import view
from eminus.localizer import get_wannier, wannier_cost
from eminus.orbitals import FLO, SCDM, WO
from eminus.tools import orbital_center
InĀ [2]:
# Run an initial calculation for methane
atoms = Atoms(*read("CH4.xyz"), ecut=15, center=True)
scf = SCF(atoms)
scf.run();
XYZ file comment: "Experimental geometry from CCCBDB: https://cccbdb.nist.gov/exp2x.asp?casno=74828&charge=0"
Start auto minimization...
Method  Iteration  Etot [Eh]    dEtot [Eh]   |Gradient|   
pccg           1   +18.061427   
pccg           2   +7.881450    +1.0180e+01  [+1.05e+04]  
pccg           3   +0.099586    +7.7819e+00  [+1.87e+03]  
pccg           4   -4.096798    +4.1964e+00  [+3.10e+02]  
pccg           5   -6.145812    +2.0490e+00  [+5.75e+01]  
pccg           6   -6.874551    +7.2874e-01  [+1.02e+01]  
pccg           7   -7.285784    +4.1123e-01  [+2.95e+00]  
pccg           8   -7.577908    +2.9212e-01  [+3.02e+00]  
pccg           9   -7.787117    +2.0921e-01  [+1.35e+00]  
pccg          10   -7.857628    +7.0510e-02  [+2.89e-01]  
pccg          11   -7.875693    +1.8065e-02  [+6.94e-02]  
pccg          12   -7.879606    +3.9137e-03  [+1.64e-02]  
pccg          13   -7.880591    +9.8423e-04  [+4.26e-03]  
pccg          14   -7.880813    +2.2256e-04  [+9.53e-04]  
pccg          15   -7.880863    +4.9429e-05  [+2.08e-04]  
pccg          16   -7.880875    +1.2336e-05  [+5.59e-05]  
pccg          17   -7.880877    +2.2595e-06  [+1.01e-05]  
pccg          18   -7.880878    +5.3147e-07  [+2.19e-06]  
pccg          19   -7.880878    +1.4534e-07  [+6.02e-07]  
pccg          20   -7.880878    +3.6440e-08  [+1.55e-07]  
SCF converged after 20 iterations.
Total SCF time: 6.08420 s
Etot = -7.880877999 Eh
InĀ [3]:
# Calculate the SCDMs to have pre-localized orbitals
scdm = SCDM(scf)
InĀ [4]:
# Do the Wannier localization
# The resulting orbitals are equivalent to Foster-Boys orbitals, but with periodic boundary conditions
wannier = get_wannier(atoms, scdm)
Wannier localizer converged after 15 iterations.
InĀ [5]:
# Compare the initial SCDM spreads to the Wannier spreads
scdm_spreads = wannier_cost(atoms, scdm)
print(f"\nSCDM spreads = {scdm_spreads}")
print(f"SCDM spread = {np.sum(scdm_spreads)}")
Costs:
[2.60730048 2.66311286 2.71520219 2.76391029]

SCDM spreads = [[2.60730048 2.66311286 2.71520219 2.76391029]]
SCDM spread = 10.749525817042638
InĀ [6]:
# The Wannier orbitals are a bit more localized, and all orbitals are evenly localized
wannier_spreads = wannier_cost(atoms, wannier)
print(f"Wannier spreads = {wannier_spreads}")
print(f"Wannier spread = {np.sum(wannier_spreads)}")
Costs:
[2.6820577  2.68206874 2.68206274 2.68211308]
Wannier spreads = [[2.6820577  2.68206874 2.68206274 2.68211308]]
Wannier spread = 10.728302260347107
InĀ [7]:
# All of the above can be done with one function call, also save the orbitals
WO(scf, write_cubes=True);
Wannier localizer converged after 15 iterations.
Write CH4_WO_k0_0.cube...
Write CH4_WO_k0_1.cube...
Write CH4_WO_k0_2.cube...
Write CH4_WO_k0_3.cube...
InĀ [8]:
# Display the orbitals from the cube files
view(glob.glob("*.cube"));
interactive(children=(Dropdown(description='filename', options=('CH4_WO_k0_2.cube', 'CH4_WO_k0_1.cube', 'CH4_Wā€¦
InĀ [9]:
# One could calculate the center of masses from the Wannier orbitals...
coms = orbital_center(atoms, wannier[0])
atoms.view(coms)
InĀ [10]:
# ...and use them as an initial guess to create a set of FLOs
flo = FLO(scf, fods=coms)
flo_spreads = wannier_cost(atoms, flo)
print(f"FLO spreads = {flo_spreads}")
print(f"FLO spread = {np.sum(flo_spreads)}")
Costs:
[3.51558105 3.64121789 3.85319416 4.52338782]
FLO spreads = [[3.51558105 3.64121789 3.85319416 4.52338782]]
FLO spread = 15.533380918024193