ASE 电子态密度与谱线展宽
用真实Cu本征值演示RawDOSData、GridDOSData、DOSCollection和dft.DOS,解释宽度与归一化。
阅读本篇目录
本例使用集群现有 ASE 3.29.0、Python 3.11、NumPy 2.3.5 与 Matplotlib 3.11.2,处理已有真实 GPUMD/VASP 输出,不需要新提交 GPU 或 DFT 任务。下载完整结构、原始结果和可运行脚本,在新解压目录执行:
bash run.sh
analysis/ 保存 CSV、结果汇总和可继续使用的数据,figures/ 保存三张高清图。脚本只用一个 CPU 线程;重复运行请另解压一份,以免混入旧输出。
1. 读取原生VASP本征值#
本篇数据来自已经完成的非自旋极化 Cu4 VASP 计算,84 个不可约 k 点、48 条带,费米能 7.40294421 eV。本篇不重新调用 VASP,也不需要 POTCAR 或波函数。
ls data/cu-vasprun.xml
head analysis/cu-spectra.csv
cat analysis/RESULTS.json
ASE 从 XML 读取实际能级和 k 权重:
from ase.io import read
import numpy as np
a = read('data/cu-vasprun.xml', format='vasp-xml', index=-1)
calc = a.calc
wk = calc.get_k_point_weights()
ef = calc.get_fermi_level()
e = np.array([calc.get_eigenvalues(kpt=k, spin=0)
for k in range(len(wk))]) - ef
weights = np.repeat(2 * wk, e.shape[1])
这里能级按 k 点、带编号顺序排平;非自旋极化总 DOS 的权重为 2×wk。若已有两个显式自旋通道,不能再盲目乘 2。能量轴相对同一个费米能平移一次,不能在每个原子或每条曲线相加时重复平移。
2. 将离散态展宽为曲线#
from ase.spectrum.dosdata import RawDOSData
raw = RawDOSData(e.ravel(), weights,
info={'material': 'Cu4'})
grid = raw.sample_grid(3001, xmin=-15, xmax=40, width=0.15)
energy = grid.get_energies()
dos = grid.get_weights()
这里 RawDOSData 的每个权重是一个离散态的积分面积,不是某个网格点的态密度。width=0.15 是 Gaussian 的标准差 σ,脚本实际比较 σ=0.05、0.15、0.30 eV。增大 σ 会让峰变平滑,不代表 k 点采样变密或原计算精度提高。
配套脚本根据全部真实能级加宽输出窗口,核对 ∫DOS dE 与总离散态权重。48 条非自旋极化带对应约 96 个态/晶胞,这不是占据电子数。保留 XML 打印的有限位数 k 权重时,实际和为 96.00000384;这是权重小数精度的尾差,脚本不改写原始数据。
3. 对照ase.dft.DOS时先对齐展宽定义#
from ase.dft.dos import DOS
other = DOS(calc, width=np.sqrt(2) * 0.15,
window=(energy[0], energy[-1]), npts=len(energy))
RawDOSData 用 exp[-(E-En)²/(2σ²)],ase.dft.DOS 用 exp[-(E-En)²/width²],所以相同物理展宽需要 width_dft = √2 × sigma_raw。直接给两个接口相同的 0.15,会得到不同的峰宽,并不表示读到的本征值不同。
这里是对已有能级重新做 Gaussian 展宽,不是逐点复现 VASP 原有四面体 DOS 算法。原始 DOS、轨道投影和 VASPKIT 提取继续参考VASP DOS实操。
4. 使用DOSCollection合并真正的分量#
脚本把真实带编号 1–24 与 25–48 分开,用相同能量轴和 σ 分别取样,再用 DOSCollection(...).sum_all() 恢复总曲线。这是按带编号分组,不是 s/p/d 轨道投影。
head analysis/cu-bandpartitions.csv
不同 σ 的三条曲线是同一组态的三种画法,不能把它们相加就当作材料有三倍的电子态。
5. 已经是网格态密度时用GridDOSData#
grid 已是 GridDOSData。再展宽时,卷积必须带上原能量网格间隔 ΔE:
smoothed = grid.sample_grid(3001,
xmin=energy[0], xmax=energy[-1],
width=0.12)
这个接口会将原网格密度按 ΔE 积分。若把一份已经采样的 DOS 数组直接丢进 RawDOSData、把每个点当独立的态面积,总态数会随网格点数量变化,归一化就错了。

head analysis/cu-spectra.csv
ls figures/ase-cu-dos-spectrum.png
进一步可把相同接口用于真正定义了权重的振动谱或其他谱线,但必须先说明能量/频率单位和强度含义。参考:ASE Raw/Grid DOS、DOSCollection、dft.DOS。