AtomPPGen 教程 07:完整端到端示例(以 Al 为例)
本 notebook 以 Al(Z=13) 为例,把赝势生成流程从头到尾串联成一个“可一键 Run All”的最小闭环:
全电子原子解(AE)
TM 伪化(构造平滑伪轨道)
半局域势反演(得到 \(V_l(r)\))
KB 可分离形式(得到 \(V_{\mathrm{loc}}\), \(\beta_l\), \(D_l\))
可转移性验证(范数守恒 / 对数导数 / 幽灵态)
导出(JSON+NPZ)
如果你已经理解 00-05 的每个环节,这个 notebook 可以作为“把知识变成产物”的工作模板。
[1]:
from pathlib import Path
import platform
import numpy as np
import matplotlib.pyplot as plt
from atomppgen import (
solve_ae_atom,
tm_pseudize,
invert_semilocal_potential,
kb_transform,
export_pseudopotential,
)
from atomppgen.validate import run_full_validation
# 中文字体配置(兼容多平台)
if platform.system() == 'Darwin':
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS', 'Heiti TC', 'STHeiti']
elif platform.system() == 'Windows':
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei', 'SimHei']
else:
plt.rcParams['font.sans-serif'] = ['DejaVu Sans', 'WenQuanYi Micro Hei']
plt.rcParams['axes.unicode_minus'] = False
print('Ready')
Ready
Step 1:全电子原子解(AE)
AE 解提供参考能级与波函数,它决定了后续伪化的目标:
外区(\(r>r_c\))必须与 AE 波函数一致
内区(\(r\le r_c\))可以重写,但要满足模守恒与光滑性
[2]:
Z = 13
xc = 'PZ81'
lmax = 2
ae = solve_ae_atom(
Z=Z,
spin_mode='LDA',
xc=xc,
lmax=lmax,
grid_type='exp_transformed',
grid_params={'n': 800, 'rmax': 100.0},
scf_params={'tol': 1e-6, 'maxiter': 150},
)
print('AE eigenvalues (Ha):')
for l in range(lmax + 1):
print('l=', l, 'eps=', ae.eps_by_l[l][-1])
AE eigenvalues (Ha):
l= 0 eps= -0.2469907526930879
l= 1 eps= 0.0009146350242940937
l= 2 eps= 0.00718614024367731
Step 2:TM 伪化(构造平滑伪轨道)
TM 伪化的关键是“在内区抹平节点/尖峰,同时保持外区完全一致”,并用模守恒锁定散射性质。
[3]:
rc_by_l = {0: 2.1, 1: 2.2, 2: 2.4}
tm_dict = {}
for l in range(lmax + 1):
tm_dict[l] = tm_pseudize(
ae.r, ae.w,
ae.u_by_l[l][-1],
ae.eps_by_l[l][-1],
l=l,
rc=rc_by_l[l],
)
for l, tm in tm_dict.items():
print('l=', l, 'rc=', tm.rc, 'norm_error=', tm.norm_error)
l= 0 rc= 2.1 norm_error= 4.721090412432319e-16
l= 1 rc= 2.2 norm_error= 5.935084483710011e-16
l= 2 rc= 2.4 norm_error= 2.9757430941508053e-16
Step 3:势反演(得到半局域势 \(V_l(r)\))
直觉上:当我们“换了波函数”,就必须同步“换一个势”,使它仍是同一能量下的解; 反演公式把这个要求变成逐点代数计算。
[4]:
inv_dict = {l: invert_semilocal_potential(tm_dict[l], ae.r) for l in tm_dict}
print('Inversion done:', list(inv_dict.keys()))
Inversion done: [0, 1, 2]
Step 4:KB 可分离形式(得到 \(V_{\mathrm{loc}}\), \(\beta_l\), \(D_l\))
半局域势在平面波里昂贵,KB 通过秩-1 投影把非局域部分写成少量标量积,从而显著加速。
[5]:
kb = kb_transform(inv_dict, {l: ae.u_by_l[l][-1] for l in tm_dict}, ae.r, ae.w, loc_channel=2)
print('KB loc_channel =', kb.loc_channel)
print('KB nonlocal channels =', sorted(kb.beta_l.keys()))
print('KB D_l =', kb.D_l)
KB loc_channel = 2
KB nonlocal channels = [0, 1]
KB D_l = {0: np.float64(4.425529213473979), 1: np.float64(2.6664472703540274)}
Step 5:可转移性验证
验证不是“锦上添花”,而是赝势可用性的底线:
范数守恒:锁定核内电荷与散射信息
对数导数:在能量窗口内比较散射性质(相移)
幽灵态:排除非物理的深束缚态
[6]:
report = run_full_validation(
ae,
tm_dict=tm_dict,
inv_dict=inv_dict,
r_test=3.0,
E_range_Ry=(-0.5, 0.5),
E_step_Ry=0.05,
)
print('overall_passed =', report.overall_passed)
print('norm pass =', all(r.passed for r in report.norm_results.values()))
print('log-derivative pass =', all(r.passed for r in report.log_deriv_results.values()))
print('ghost pass =', report.ghost_result.passed)
overall_passed = True
norm pass = True
log-derivative pass = True
ghost pass = True
Step 6:导出(JSON+NPZ)
导出后你将得到两类文件:
*.json:面向阅读/审计(参数、单位、验证报告、以及 NPZ 文件索引)*.npz:面向数值计算(网格、半局域势、KB 投影子等数组)
[7]:
cwd = Path.cwd().resolve()
repo_root = next(p for p in [cwd, *cwd.parents] if (p / 'AtomPPGen' / 'pyproject.toml').is_file())
out_dir = repo_root / 'AtomPPGen' / 'outputs' / 'tutorial_07'
out_dir.mkdir(parents=True, exist_ok=True)
output_prefix = out_dir / 'al_lda_complete'
files = export_pseudopotential(
ae_result=ae,
tm_dict=tm_dict,
inv_dict=inv_dict,
validation_report=report,
kb_result=kb,
output_prefix=str(output_prefix),
formats=['json', 'npz'],
)
files
[7]:
[PosixPath('/Users/gilbert/Downloads/同步空间/Work/Courses/大四上/电子结构理论与计算/代码作业/2-3/AtomPPGen/outputs/tutorial_07/al_lda_complete.json'),
PosixPath('/Users/gilbert/Downloads/同步空间/Work/Courses/大四上/电子结构理论与计算/代码作业/2-3/AtomPPGen/outputs/tutorial_07/al_lda_complete.npz')]