This work builds off Structural spillage: an efficient method to identify non-crystalline topological materials (https://link.aps.org/doi/10.1103/PhysRevResearch.5.L042011) with a more efficient implementation of the structural spillage calculations.
Note, this is only an indicator of band inversion in the perturbative limit of a crystalline structure. Work is ongoing to quantify what this limit is (e.g. in terms of local atomic environments/orbitals).
The quasi-Bloch structural spillage at UC k-point k (paper eq. 2b):
where --xtal-sc) and --amor-sc), both expressed in the plane-wave basis and unfolded onto the UC k-mesh (--xtal-uc). This is implemented in compute_structural_spillage in structural_spillage.py: p4 is aa is p1/p2 are the two cross terms
Rather than the aggregate per_band_structural_spillage
resolves the spillage per individual band
where dominant_k, the UC k-point that band unfolds from most
strongly.
Three variants are available, differing in which reference bands and which comparison subspace are used:
| Flag | Reference bands ( |
Comparison subspace ( |
Requires | Corresponds to |
|---|---|---|---|---|
--out-per-band |
--xtal-sc (SOC) |
--amor-sc |
— | Per-band breakdown of the main --out-spillage
|
--out-per-band-nosoc |
--xtal-sc-nosoc, trivially embedded as |
--amor-sc |
--xtal-sc-nosoc |
Isolates the structure/disorder axis from SOC entirely — both sides noSOC |
--out-per-band-nosoc-soc |
--xtal-sc-nosoc, trivially embedded as |
--amor-soc |
--xtal-sc-nosoc, --amor-soc
|
Crystal noSOC vs. disordered+SOC — mixes the structure and SOC axes into one comparison |
A different quantity from --xtal-sc vs
--amor-sc) and restricts cross terms to plane waves mapping to the same UC k-point,
the spin-orbit plane-wave spillage compares SOC vs noSOC calculations of the same structure
(--amor-soc vs --amor-sc).
where --amor-soc and --amor-sc (noSOC) — both projectors on the same structure, differing only in whether SOC
was included. The total spin-orbit spillage is --out-sopw), normalized by --out-norm-sopw. compute_sopw runs automatically whenever --amor-soc is given (alongside
compute_structural_spillage), and additionally writes --out-per-band-sopw — rows are
--amor-soc bands, columns [energy_eV, gamma_sopw, w_k0, ..., dominant_k] — if that flag
is set, comparing individual --amor-soc bands against the --amor-sc subspace.
Python 3.9+ (uses the walrus operator). Install dependencies with:
pip install -r requirements.txt
We provide the commands to calculate structural spillage for Bismuthene bi-layer for example.
uc/2nd/WAVECAR— crystalline unit cell, 5×5×1 k-mesh, SOC (vasp_type=ncl)supercell/WAVECAR— crystalline 50-atom supercell, gamma-only, SOCdis/WAVECAR— the same supercell disordered (amorphized), gamma-only, noSOC
Run:
python structural_spillage.py \
--xtal-uc /global/cfs/cdirs/m4590/spillage_data/Bi_data/uc/2nd/WAVECAR \
--uc-soc \
--xtal-sc /global/cfs/cdirs/m4590/spillage_data/Bi_data/supercell/WAVECAR \
--amor-sc /global/cfs/cdirs/m4590/spillage_data/Bi_data/dis/WAVECAR \
--out-spillage tests/bi_smoke/spillage.txt
--uc-soc is required because the UC WAVECAR was written with LSORBIT=.TRUE..
We confirm that the value at the
Unlike the bismuthene case above, this compares the crystalline SOC supercell against
the same nominal structure without SOC — no actual disorder — so it isolates the
SOC-driven band inversion at
python structural_spillage.py \
--xtal-uc test_data/r2scan_uc_nosoc/WAVECAR \
--xtal-sc /global/cfs/cdirs/m4590/spillage_data/DOS_crys_supercell/soc/WAVECAR \
--amor-sc /global/cfs/cdirs/m4590/spillage_data/DOS_crys_supercell/noSOC/WAVECAR \
--out-spillage tests/bi2se3_smoke/spillage.txt
We confirm that the value at the
The bismuthene case above only exercises --out-spillage. With two more WAVECARs it also
covers all three per-band structural outputs, and — since --amor-soc is now present —
compute_sopw runs automatically too, covering the Appendix D outputs in the same command:
supercell_nosoc/WAVECAR— noSOC on the same crystallinesupercell/structure (generated viasubmit_bi_xtal_nosoc.shinAmorphousTDA)dis_soc/WAVECAR— SOC on the same disordereddis/structure (generated viasubmit_bi_dis_soc.sh)
python structural_spillage.py \
--xtal-uc test_data/Bi_data/uc/2nd/WAVECAR \
--uc-soc \
--xtal-sc test_data/Bi_data/supercell/WAVECAR \
--xtal-sc-nosoc test_data/Bi_data/supercell_nosoc/WAVECAR \
--amor-sc test_data/Bi_data/dis/WAVECAR \
--amor-soc test_data/Bi_data/dis_soc/WAVECAR \
--out-spillage tests/bi_smoke/spillage.txt \
--out-norm-spillage tests/bi_smoke/spillage_norm.txt \
--out-per-band tests/bi_smoke/per_band_struct_soc_nsoc.txt \
--out-per-band-nosoc tests/bi_smoke/per_band_struct_nosoc_nsoc.txt \
--out-per-band-nosoc-soc tests/bi_smoke/per_band_struct_nosoc_soc.txt \
--out-sopw tests/bi_smoke/sopw.txt \
--out-norm-sopw tests/bi_smoke/sopw_norm.txt \
--out-per-band-sopw tests/bi_smoke/per_band_sopw.txt
Deep valence bands score lowest (least impacted SOC/noSOC and crystal/disorder); states nearest
plot_per_band.py plots any of the per-band txt files above (energy vs gamma), one PNG per
input file, saved alongside each input by default:
python plot_per_band.py tests/bi_smoke/per_band_struct_soc_nsoc.txt tests/bi_smoke/per_band_sopw.txt
Pass --efermi <value> to draw a dashed reference line at --out-dir to write the
PNGs elsewhere. It only reads the energy_eV/gamma_* columns — the w_k*/dominant_k
unfolding detail in each file isn't plotted.