GPAW meta-GGA与动能密度
用氢分子和铝晶体区分固定密度泛函评估、TPSS自洽及动能密度输出。
阅读本篇目录
用氢分子和铝晶体区分固定密度泛函评估、TPSS自洽及动能密度输出。
1 下载、提交与运行#
下载完整操作包,保存为gpaw-meta-gga.zip。在集群解压后,普通批作业可以执行sbatch job.slurm;下面的直接运行命令用于已经分配好的CPU资源内,不要在登录节点运行生产计算。
python3 -m zipfile -e gpaw-meta-gga.zip .
cd gpaw-meta-gga
bash setup.sh
bash run.sh
bash verify.sh
bash plot.sh
脚本按1个MPI进程、1个线程设置运行环境。先完成电子结构计算,再提取数据并画图;原始结果在results/,两张图片在plots/。verify.sh用于与附件的原样模型对照;改变体系后应自行检查科学收敛,不能继续沿用原模型数值作为目标。
2 两条不同流程,不要混用#
第一条是H₂:PBE、有限差分0.25 Å、键长0.75 Å、真空3.5 Å,先做PBE自洽,再在同一PBE密度与轨道上评估TPSS泛函能量。第二条是fcc Al:a=4.05 Å、原胞1原子、PW200 eV、4×4×4 k网格、8条带、0.2 eV展宽,先PBE自洽,再从PBE检查点启动真正的TPSS自洽。
H₂没有在本例中做TPSS自洽,固定密度评估不能标成“TPSS收敛态”。Al用GPAW(restart, xc='TPSS', ...)构造热启动计算器,保留电子态作为起点;不要把一个未带轨道的新计算器误当作检查点续算。
3 本次实际能量#
| 计算 | 能量/eV | 含义 |
|---|---|---|
| H₂ PBE | −6.6127307221 | PBE自洽 |
| H₂ 固定密度TPSS | −6.9591908578 | PBE态上的泛函评估 |
| Al PBE | −3.6995942036 | PBE自洽 |
| Al TPSS | −7.8349252066 | TPSS自洽 |
这些是对应模型和泛函的绝对总能量,没有孤立原子参照,不能直接当成结合能,也不能据两个泛函绝对能量的高低判断哪一个结构更稳定。

4 动能密度怎么读#
meta-GGA除密度与密度梯度外还使用轨道动能密度τ。附件用wfs.calculate_kinetic_energy_density()导出实际赝价电子τ,单位Bohr⁻⁵;它不是全电子电荷密度,也不是一个已经积分好的总动能数值。
H₂图同时给出实际PBE电荷密度与τ;Al图对比两种自洽态的τ切片。fcc原胞不是正交盒,所以Al切片坐标采用分数坐标v/w,不能当成笛卡尔Å坐标。

普通能量/密度/本征态收敛条件为1E−6/1E−5/1E−7。换成分子、表面或其他meta-GGA时,要重新检查网格、真空和SCF稳定性;这里的短小输入用于理解流程,不是泛函性能或晶格常数的收敛比较。
完整计算输入#
以下是附件实际执行的run.py,含结构、计算器、提取流程与输出定义。先原样运行,再按上文说明更改模型;inputs.json同时记录示例条件与旧曲线/目标轨道信息。
展开完整Python输入
from pathlib import Path
import json, numpy as np
from ase import Atoms
from ase.build import bulk
from gpaw import GPAW, PW, Mixer, Davidson
R = Path(__file__).resolve().parent / 'results'
R.mkdir()
rows = []
checks = []
def ck(n, b, **kw):
checks.append(dict(name=n, passed=bool(b), **kw))
for name in ['H2-PBE', 'Al-PBE', 'Al-TPSS']:
D = R / name
D.mkdir()
if name == 'H2-PBE':
a = Atoms('H2', [[0, 0, 0], [0, 0, 0.75]])
a.center(vacuum=3.5)
a.pbc = False
c = GPAW(legacy_gpaw=True, mode='fd', xc='PBE', h=0.25, nbands=2, spinpol=False, eigensolver=Davidson(3), mixer=Mixer(0.2, 5, 1), convergence=dict(energy=1e-06, density=1e-05, eigenstates=1e-07), maxiter=250, txt=str(D / 'native.txt'))
elif name == 'Al-PBE':
a = bulk('Al', 'fcc', a=4.05)
c = GPAW(legacy_gpaw=True, mode=PW(200), xc='PBE', kpts=(4, 4, 4), nbands=8, spinpol=False, occupations={'name': 'fermi-dirac', 'width': 0.2}, mixer=Mixer(0.2, 5, 50), convergence=dict(energy=1e-06, density=1e-05, eigenstates=1e-07), maxiter=200, txt=str(D / 'native.txt'))
else:
c = GPAW(str(R / 'Al-PBE/state.gpw'), legacy_gpaw=True, xc='TPSS', eigensolver=Davidson(5), mixer=Mixer(0.05, 5, 50), convergence=dict(energy=1e-06, density=1e-05, eigenstates=1e-07), maxiter=240, txt=str(D / 'native.txt'))
a = c.get_atoms()
a.calc = c
e = float(a.get_potential_energy())
c.write(str(D / 'state.gpw'), mode='all')
force = a.get_forces()
rho = c.get_all_electron_density(gridrefinement=1)
tau = c.wfs.calculate_kinetic_energy_density()
occs = np.array([c.get_occupation_numbers(kpt=k) for k in range(c.wfs.kd.nibzkpts)])
eigs = np.array([c.get_eigenvalues(kpt=k) for k in range(c.wfs.kd.nibzkpts)])
ne = float(rho.sum() * a.get_volume() / rho.size)
val = 2 if name.startswith('H2') else 3
Z = 2 if name.startswith('H2') else 13
typ = 'MGGA' if name == 'Al-TPSS' else 'GGA'
ck(name + ':AE', abs(ne - Z) < 0.02)
ck(name + ':valence', abs(occs.sum() - val) < 1e-08)
ck(name + ':actual_functional', c.hamiltonian.xc.type == typ)
ck(name + ':nonnegative_tau', np.isfinite(tau).all() and tau.min() > -1e-12 and (tau.max() > 0))
ck(name + ':finite', np.isfinite([e, *force.ravel()]).all() and np.isfinite(rho).all())
np.savez_compressed(D / 'fields.npz', AE_total_density_e_A3=rho, pseudo_valence_kinetic_density_Bohr_minus5=tau, weighted_occupations=occs, eigenvalues_eV=eigs, IBZ_weights=c.get_k_point_weights(), cell_A=a.cell.array, positions_A=a.positions, forces_eV_A=force)
row = dict(name=name, energy_eV=e, AE_electrons=ne, valence=float(occs.sum()), XC_type=typ)
if name == 'H2-PBE':
row['TPSS_fixed_density_energy_eV'] = e + float(c.get_xc_difference('TPSS'))
ck('H2_fixed_density_TPSS_finite', np.isfinite(row['TPSS_fixed_density_energy_eV']))
rows.append(row)
print(name, e, flush=True)
v = dict(passed=all((c['passed'] for c in checks)), checks=len(checks), items=checks, results=rows, H2_TPSS_only_fixed_density=True, Al_TPSS_actual_SCF=True, whole_group_complete=False)
(R / 'VALIDATION.json').write_text(json.dumps(v, indent=2) + '\n')
assert v['passed']
终端查看结果#
计算后先查看逐项结果,再打开图。下面只读取输出,不会启动新的自洽:
python3 -c "import json; v=json.load(open('results/VALIDATION.json')); print(v.get('results')); print(v.get('summary', {}))"
source env.sh
python3 -c "import numpy as np; d=np.load('results/Al-PBE/fields.npz'); print([(k, d[k].shape) for k in d.files])"
ls -lh plots/*.png
环境:GPAW26.7.0、GCC13.3、OpenMPI5.0.10rc2、MKL2023.2、Libxc7.0、Python3.11.16。模块为gpaw/26.7.0-8173m;实际输入由Python/ASE组织,使用附件的env.sh加载一致环境。附件不打包PAW数据集或二进制检查点,运行时使用集群已安装数据集。