export - 赝势导出模块
本模块提供多种格式的赝势文件导出功能,支持 JSON(元数据)、NPZ(数值数组)和 UPF(Quantum ESPRESSO)格式。
赝势导出模块
提供多种格式的赝势文件导出功能: - JSON:结构化元数据(参数、验证结果) - NPZ:数值数据(径向网格、势能、波函数) - UPF:Quantum ESPRESSO 兼容格式(实验性,当前仅提供最小可解析结构)
主要函数
export_pseudopotential : 统一导出接口
- class atomppgen.export.PseudopotentialData(Z, symbol, spin_mode, xc_functional, generation_params, radial_grid, radial_weights, ae_eigenvalues_by_l, ae_wavefunctions_by_l, pseudo_wavefunctions_by_l, semilocal_potentials_by_l, validation_report, generation_date, kb_loc_channel=None, kb_V_loc=None, kb_beta_l=None, kb_D_l=None, code_version='0.1.0', git_commit=None)[源代码]
基类:
object完整赝势数据包
聚合全电子解、TM伪化、势反演、验证报告等所有数据源, 用于统一格式导出。
- 参数:
- generation_params
生成参数(TM参数、网格参数等)
- Type:
Dict
- radial_grid
径向网格,单位 Bohr
- Type:
np.ndarray
- radial_weights
积分权重
- Type:
np.ndarray
- kb_V_loc
KB 局域势 V_loc(r),单位 Hartree(可选)
- Type:
Optional[np.ndarray]
- validation_report
完整验证报告
- Type:
-
validation_report:
ValidationReport
- __init__(Z, symbol, spin_mode, xc_functional, generation_params, radial_grid, radial_weights, ae_eigenvalues_by_l, ae_wavefunctions_by_l, pseudo_wavefunctions_by_l, semilocal_potentials_by_l, validation_report, generation_date, kb_loc_channel=None, kb_V_loc=None, kb_beta_l=None, kb_D_l=None, code_version='0.1.0', git_commit=None)
- atomppgen.export.export_pseudopotential(ae_result, tm_dict, inv_dict, validation_report, output_prefix, kb_result=None, formats=['json', 'npz'], metadata=None)[源代码]
导出赝势到多种格式
- 参数:
ae_result (AEAtomResult) -- 全电子原子解
inv_dict (Dict[int, InvertResult]) -- 各通道势反演结果(按角动量 l 索引)
validation_report (ValidationReport) -- 完整验证报告
output_prefix (str) -- 输出文件名前缀(如 'outputs/al_lda')
formats (List[str], default=['json', 'npz']) -- 导出格式列表,支持 'json', 'npz', 'upf'
metadata (Optional[Dict], default=None) -- 额外元数据(如 git_commit, 备注)
kb_result (KBResult | None)
- 返回:
生成的文件路径列表
- 返回类型:
List[Path]
- 抛出:
ValueError -- 若 tm_dict 和 inv_dict 的 l 通道不一致
示例
>>> files = export_pseudopotential( ... ae, tm_dict, inv_dict, report, ... output_prefix='outputs/al_lda', ... formats=['json', 'npz'] ... ) >>> print(files) [PosixPath('outputs/al_lda.json'), PosixPath('outputs/al_lda.npz')]
备注
输出单位约定: - 能量:Hartree 原子单位 - 长度:Bohr
JSON格式包含元数据和验证报告,NPZ格式包含数值数组。 推荐同时导出JSON+NPZ以获得完整数据集。
- atomppgen.export.export_upf(data, output_path, metadata=None)[源代码]
导出 UPF v2(实验性)
当前目标是提供“最小可解析、字段可追溯”的 UPF 结构,便于后续逐步对齐 QE 的严格要求。 若要获得严格可用于 Quantum ESPRESSO 的 UPF,请关注后续版本更新。
- 参数:
data (PseudopotentialData) -- 完整赝势数据包
output_path (str | Path) -- 输出文件路径(建议后缀为 .upf)
metadata (dict, optional) -- 额外信息;UPF 需要的关键字段可在此给出: - z_valence : float(建议显式提供)
- 返回:
生成的 UPF 文件路径
- 返回类型:
Path
主要函数
- atomppgen.export.export_pseudopotential(ae_result, tm_dict, inv_dict, validation_report, output_prefix, kb_result=None, formats=['json', 'npz'], metadata=None)[源代码]
导出赝势到多种格式
- 参数:
ae_result (AEAtomResult) -- 全电子原子解
inv_dict (Dict[int, InvertResult]) -- 各通道势反演结果(按角动量 l 索引)
validation_report (ValidationReport) -- 完整验证报告
output_prefix (str) -- 输出文件名前缀(如 'outputs/al_lda')
formats (List[str], default=['json', 'npz']) -- 导出格式列表,支持 'json', 'npz', 'upf'
metadata (Optional[Dict], default=None) -- 额外元数据(如 git_commit, 备注)
kb_result (KBResult | None)
- 返回:
生成的文件路径列表
- 返回类型:
List[Path]
- 抛出:
ValueError -- 若 tm_dict 和 inv_dict 的 l 通道不一致
示例
>>> files = export_pseudopotential( ... ae, tm_dict, inv_dict, report, ... output_prefix='outputs/al_lda', ... formats=['json', 'npz'] ... ) >>> print(files) [PosixPath('outputs/al_lda.json'), PosixPath('outputs/al_lda.npz')]
备注
输出单位约定: - 能量:Hartree 原子单位 - 长度:Bohr
JSON格式包含元数据和验证报告,NPZ格式包含数值数组。 推荐同时导出JSON+NPZ以获得完整数据集。
数据类
- class atomppgen.export.PseudopotentialData(Z, symbol, spin_mode, xc_functional, generation_params, radial_grid, radial_weights, ae_eigenvalues_by_l, ae_wavefunctions_by_l, pseudo_wavefunctions_by_l, semilocal_potentials_by_l, validation_report, generation_date, kb_loc_channel=None, kb_V_loc=None, kb_beta_l=None, kb_D_l=None, code_version='0.1.0', git_commit=None)[源代码]
完整赝势数据包
聚合全电子解、TM伪化、势反演、验证报告等所有数据源, 用于统一格式导出。
- 参数:
- generation_params
生成参数(TM参数、网格参数等)
- Type:
Dict
- radial_grid
径向网格,单位 Bohr
- Type:
np.ndarray
- radial_weights
积分权重
- Type:
np.ndarray
- kb_V_loc
KB 局域势 V_loc(r),单位 Hartree(可选)
- Type:
Optional[np.ndarray]
- validation_report
完整验证报告
- Type:
-
validation_report:
ValidationReport
- __init__(Z, symbol, spin_mode, xc_functional, generation_params, radial_grid, radial_weights, ae_eigenvalues_by_l, ae_wavefunctions_by_l, pseudo_wavefunctions_by_l, semilocal_potentials_by_l, validation_report, generation_date, kb_loc_channel=None, kb_V_loc=None, kb_beta_l=None, kb_D_l=None, code_version='0.1.0', git_commit=None)
使用示例
完整工作流
from atomppgen import (
solve_ae_atom,
tm_pseudize,
invert_semilocal_potential,
export_pseudopotential,
)
from atomppgen.validate import run_full_validation
# 1. 全电子原子解
ae = solve_ae_atom(
Z=13, # Al
spin_mode='LDA',
lmax=0,
grid_type='exp_transformed',
grid_params={'n': 600}
)
# 2. TM 伪化
tm_s = tm_pseudize(
ae.r, ae.w,
ae.u_by_l[0][-1], # 3s 价电子
ae.eps_by_l[0][-1],
l=0,
rc=2.5
)
# 3. 势反演
inv_s = invert_semilocal_potential(tm_s, ae.r)
# 4. 验证
report = run_full_validation(
ae,
tm_dict={0: tm_s},
inv_dict={0: inv_s},
r_test=3.0,
E_range_Ry=(-0.5, 0.5),
E_step_Ry=0.05,
)
# 5. 导出到 JSON + NPZ 格式
files = export_pseudopotential(
ae_result=ae,
tm_dict={0: tm_s},
inv_dict={0: inv_s},
validation_report=report,
output_prefix='outputs/al_lda',
formats=['json', 'npz'],
)
print(f"已导出 {len(files)} 个文件:")
for f in files:
print(f" - {f.name} ({f.stat().st_size / 1024:.1f} KB)")
单一格式导出
# 仅导出 JSON(元数据 + 验证报告)
json_files = export_pseudopotential(
ae_result=ae,
tm_dict=tm_dict,
inv_dict=inv_dict,
validation_report=report,
output_prefix='outputs/al_lda',
formats=['json'],
)
# 仅导出 NPZ(数值数组)
npz_files = export_pseudopotential(
ae_result=ae,
tm_dict=tm_dict,
inv_dict=inv_dict,
validation_report=report,
output_prefix='outputs/al_lda',
formats=['npz'],
)
添加元数据
# 添加 Git 提交信息等元数据
files = export_pseudopotential(
ae_result=ae,
tm_dict=tm_dict,
inv_dict=inv_dict,
validation_report=report,
output_prefix='outputs/al_lda',
formats=['json', 'npz'],
metadata={
'git_commit': 'a1b2c3d',
'notes': 'Optimized rc parameter',
}
)
UPF 导出(实验性)
UPF writer 当前提供“最小可解析、字段可追溯”的结构,用于后续逐步对齐 QE 的严格要求。 建议仍以 JSON/NPZ 作为权威数据源,UPF 视为中间格式。
导出 UPF 时需要提供价电子数 ``z_valence``(教学示例可用 Na/Al/Si 的默认推断,但推荐显式指定):
files = export_pseudopotential(
ae_result=ae,
tm_dict=tm_dict,
inv_dict=inv_dict,
validation_report=report,
output_prefix='outputs/al_lda',
kb_result=kb, # 建议提供,以输出 PP_LOCAL/PP_NONLOCAL
formats=['upf'],
metadata={'z_valence': 3.0},
)
加载导出数据
import json
import numpy as np
# 加载 JSON 元数据
with open('outputs/al_lda.json', 'r') as f:
metadata = json.load(f)
print(f"元素: {metadata['metadata']['element']['symbol']}")
print(f"泛函: {metadata['metadata']['xc']['functional']}")
print(f"验证: {metadata['validation_report']['overall_passed']}")
# 加载 NPZ 数值数据
npz_data = np.load('outputs/al_lda.npz')
r = npz_data['radial_grid']
V_s = npz_data['semilocal_potential_l0']
psi_s = npz_data['ps_wavefunction_l0']
print(f"网格点数: {len(r)}")
print(f"s 通道势能形状: {V_s.shape}")
# 绘图
import matplotlib.pyplot as plt
plt.plot(r, V_s * r, label='$r V_s(r)$')
plt.xlabel('r (Bohr)')
plt.ylabel('$r V_s$ (Ha·Bohr)')
plt.legend()
plt.savefig('potential_s.png')
多通道导出
# Al 的 s, p, d 通道
ae = solve_ae_atom(Z=13, spin_mode='LDA', lmax=2)
# TM 伪化各通道
rc_by_l = {0: 2.1, 1: 2.2, 2: 2.4}
tm_dict = {}
inv_dict = {}
for l in range(3):
# 价层索引(Al: 3s, 3p, 3d)
n_valence = {0: 2, 1: 1, 2: 0}
u_ae = ae.u_by_l[l][n_valence[l]]
eps = ae.eps_by_l[l][n_valence[l]]
# TM 伪化
tm = tm_pseudize(ae.r, ae.w, u_ae, eps, l=l, rc=rc_by_l[l])
tm_dict[l] = tm
# 势反演
inv = invert_semilocal_potential(tm, ae.r)
inv_dict[l] = inv
# 验证
report = run_full_validation(
ae, tm_dict, inv_dict,
r_test=3.0,
E_range_Ry=(-0.5, 0.5),
E_step_Ry=0.05,
)
# 导出
files = export_pseudopotential(
ae_result=ae,
tm_dict=tm_dict,
inv_dict=inv_dict,
validation_report=report,
output_prefix='outputs/al_lda_spd',
formats=['json', 'npz'],
)
技术细节
JSON 格式说明
JSON 文件包含以下顶层字段:
字段 |
内容 |
|---|---|
metadata |
元素、泛函、生成日期、代码版本 |
generation_params |
TM 参数(rc_by_l)、网格参数 |
all_electron_reference |
全电子本征值(按角动量 l 索引) |
pseudopotential |
通道列表、数据文件引用 |
validation_report |
范数守恒、对数导数、幽灵态检测结果 |
radial_grid |
网格点数、范围(不包含数组数据) |
单位约定:
能量:Hartree 原子单位
长度:Bohr
在
metadata.units中明确标注为"Hartree_atomic"
NPZ 格式说明
NPZ 文件采用压缩格式(np.savez_compressed),包含以下数组:
网格数据:
radial_grid:径向网格 \(r\) (Bohr)radial_weights:积分权重 \(w\)
标量元数据:
Z:原子序数xc_code:泛函代码(1=PZ81, 2=VWN, 3=PW91, 4=PBE)
**全电子数据**(按角动量 l 索引):
ae_eigenvalues_l{l}:本征值数组 (Ha)ae_wavefunction_l{l}_n{n}:径向波函数 \(u(r)\)
**赝势数据**(按角动量 l 索引):
ps_wavefunction_l{l}:伪波函数 \(u_{\mathrm{PS}}(r)\)semilocal_potential_l{l}:半局域势 \(V_l(r)\) (Ha)
**KB 可分离形式数据**(可选):
如果在导出时传入 kb_result,NPZ 还会包含 KB 形式所需的关键数组:
kb_loc_channel:局域通道 \(l^*\)kb_V_loc:局域势 \(V_{\mathrm{loc}}(r)\) (Ha)kb_beta_l{l}:投影子 :math:`beta_l(r)`(仅对非局域通道存在)kb_D_l{l}:耦合系数 \(D_l\) (Ha)
命名约定示例:
# s 通道(l=0)
'ae_eigenvalues_l0' # [ε_1s, ε_2s, ε_3s]
'ae_wavefunction_l0_n3' # u_3s(r)(价电子)
'ps_wavefunction_l0' # u_PS,s(r)
'semilocal_potential_l0' # V_s(r)
# p 通道(l=1)
'ae_eigenvalues_l1' # [ε_2p, ε_3p]
'ae_wavefunction_l1_n2' # u_3p(r)
'ps_wavefunction_l1' # u_PS,p(r)
'semilocal_potential_l1' # V_p(r)
数据加载验证
import numpy as np
# 加载 NPZ 数据
npz_data = np.load('outputs/al_lda.npz')
# 验证数组形状一致性
n_grid = len(npz_data['radial_grid'])
assert npz_data['ps_wavefunction_l0'].shape == (n_grid,)
assert npz_data['semilocal_potential_l0'].shape == (n_grid,)
# 验证元数据
assert npz_data['Z'] == 13 # Al
assert npz_data['xc_code'] == 1 # PZ81
# 验证本征值数量
n_valence_states = len(npz_data['ae_eigenvalues_l0'])
print(f"s 通道价层态数: {n_valence_states}")
# 检查数组中无 NaN/Inf
for key in npz_data.keys():
arr = npz_data[key]
if isinstance(arr, np.ndarray):
assert np.all(np.isfinite(arr)), f"{key} 包含 NaN/Inf"
输出路径处理
from pathlib import Path
# 自动创建父目录
output_prefix = Path('outputs/subdir/test_al')
files = export_pseudopotential(
ae_result=ae,
tm_dict=tm_dict,
inv_dict=inv_dict,
validation_report=report,
output_prefix=str(output_prefix),
formats=['json', 'npz'],
)
# 输出文件:
# - outputs/subdir/test_al.json
# - outputs/subdir/test_al.npz
# 使用字符串路径
files = export_pseudopotential(
...,
output_prefix='outputs/al_lda',
...
)
# 使用 Path 对象
files = export_pseudopotential(
...,
output_prefix=Path.cwd() / 'outputs' / 'al_lda',
...
)
错误处理
# L-channel 一致性检查
tm_dict = {0: tm_s, 1: tm_p} # s, p 通道
inv_dict = {0: inv_s} # 仅 s 通道
try:
files = export_pseudopotential(
ae_result=ae,
tm_dict=tm_dict,
inv_dict=inv_dict,
validation_report=report,
output_prefix='outputs/test',
formats=['json'],
)
except ValueError as e:
print(f"错误: {e}")
# 输出: "TM和势反演的l通道不一致: tm={0, 1}, inv={0}"
文件大小估算
典型文件大小(Al, lmax=0, 600 网格点):
格式 |
文件大小 |
说明 |
|---|---|---|
JSON |
~3 KB |
元数据 + 验证报告(不含数组) |
NPZ |
~24 KB |
压缩数值数组 |
JSON (含数组) |
~1 MB |
include_arrays=True(不推荐) |
多通道情况(lmax=2):
JSON: ~5 KB
NPZ: ~60 KB
建议
推荐实践:
同时导出 JSON + NPZ:JSON 存储元数据和验证报告,NPZ 存储数值数据
JSON 不包含数组:默认
include_arrays=False,避免文件过大验证输出:导出后立即加载 NPZ,检查数组形状和数值范围
版本控制:在
metadata中添加git_commit字段
避免的做法:
不要在 JSON 中包含大数组(
include_arrays=True)不要混用不同版本的 AtomPPGen 导出的文件
不要手动编辑 NPZ 文件(使用 Python 重新导出)
参考示例
完整示例脚本:
examples/export_al_example.py:Al LDA 赝势生成与导出完整流程
相关模块
ae_atom - 全电子原子解:全电子原子解
tm - Troullier-Martins 伪化器:TM 伪化器
势反演模块 (invert):势反演
validate - 赝势可转移性验证:可转移性验证