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伪化、势反演、验证报告等所有数据源, 用于统一格式导出。

参数:
Z

原子序数

Type:

int

symbol

元素符号(如 'Al')

Type:

str

spin_mode

自旋模式('LDA' / 'GGA')

Type:

str

xc_functional

交换关联泛函('PZ81' / 'VWN')

Type:

str

generation_params

生成参数(TM参数、网格参数等)

Type:

Dict

radial_grid

径向网格,单位 Bohr

Type:

np.ndarray

radial_weights

积分权重

Type:

np.ndarray

ae_eigenvalues_by_l

全电子本征值(按角动量 l 索引),单位 Hartree

Type:

Dict[int, np.ndarray]

ae_wavefunctions_by_l

全电子径向波函数(u = r·R)

Type:

Dict[int, List[np.ndarray]]

pseudo_wavefunctions_by_l

赝波函数(伪化后的价电子态)

Type:

Dict[int, np.ndarray]

semilocal_potentials_by_l

半局域势 V_l(r),单位 Hartree

Type:

Dict[int, np.ndarray]

kb_loc_channel

KB 局域通道角动量量子数 l*(可选)

Type:

Optional[int]

kb_V_loc

KB 局域势 V_loc(r),单位 Hartree(可选)

Type:

Optional[np.ndarray]

kb_beta_l

KB 投影子 {l: β_l(r)}(可选,已归一化)

Type:

Optional[Dict[int, np.ndarray]]

kb_D_l

KB 耦合系数 {l: D_l}(可选,Hartree)

Type:

Optional[Dict[int, float]]

validation_report

完整验证报告

Type:

ValidationReport

generation_date

生成时间戳(ISO 8601格式)

Type:

str

code_version

代码版本号

Type:

str

git_commit

Git 提交哈希(可选)

Type:

Optional[str]

Z: int
symbol: str
spin_mode: str
xc_functional: str
generation_params: Dict
radial_grid: ndarray
radial_weights: ndarray
ae_eigenvalues_by_l: Dict[int, ndarray]
ae_wavefunctions_by_l: Dict[int, List[ndarray]]
pseudo_wavefunctions_by_l: Dict[int, ndarray]
semilocal_potentials_by_l: Dict[int, ndarray]
validation_report: ValidationReport
generation_date: str
kb_loc_channel: Optional[int] = None
kb_V_loc: Optional[ndarray] = None
kb_beta_l: Optional[Dict[int, ndarray]] = None
kb_D_l: Optional[Dict[int, float]] = None
code_version: str = '0.1.0'
git_commit: Optional[str] = None
__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)
参数:
返回类型:

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) -- 全电子原子解

  • tm_dict (Dict[int, TMResult]) -- 各通道TM伪化结果(按角动量 l 索引)

  • 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) -- 全电子原子解

  • tm_dict (Dict[int, TMResult]) -- 各通道TM伪化结果(按角动量 l 索引)

  • 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伪化、势反演、验证报告等所有数据源, 用于统一格式导出。

参数:
Z

原子序数

Type:

int

symbol

元素符号(如 'Al')

Type:

str

spin_mode

自旋模式('LDA' / 'GGA')

Type:

str

xc_functional

交换关联泛函('PZ81' / 'VWN')

Type:

str

generation_params

生成参数(TM参数、网格参数等)

Type:

Dict

radial_grid

径向网格,单位 Bohr

Type:

np.ndarray

radial_weights

积分权重

Type:

np.ndarray

ae_eigenvalues_by_l

全电子本征值(按角动量 l 索引),单位 Hartree

Type:

Dict[int, np.ndarray]

ae_wavefunctions_by_l

全电子径向波函数(u = r·R)

Type:

Dict[int, List[np.ndarray]]

pseudo_wavefunctions_by_l

赝波函数(伪化后的价电子态)

Type:

Dict[int, np.ndarray]

semilocal_potentials_by_l

半局域势 V_l(r),单位 Hartree

Type:

Dict[int, np.ndarray]

kb_loc_channel

KB 局域通道角动量量子数 l*(可选)

Type:

Optional[int]

kb_V_loc

KB 局域势 V_loc(r),单位 Hartree(可选)

Type:

Optional[np.ndarray]

kb_beta_l

KB 投影子 {l: β_l(r)}(可选,已归一化)

Type:

Optional[Dict[int, np.ndarray]]

kb_D_l

KB 耦合系数 {l: D_l}(可选,Hartree)

Type:

Optional[Dict[int, float]]

validation_report

完整验证报告

Type:

ValidationReport

generation_date

生成时间戳(ISO 8601格式)

Type:

str

code_version

代码版本号

Type:

str

git_commit

Git 提交哈希(可选)

Type:

Optional[str]

Z: int
symbol: str
spin_mode: str
xc_functional: str
generation_params: Dict
radial_grid: ndarray
radial_weights: ndarray
ae_eigenvalues_by_l: Dict[int, ndarray]
ae_wavefunctions_by_l: Dict[int, List[ndarray]]
pseudo_wavefunctions_by_l: Dict[int, ndarray]
semilocal_potentials_by_l: Dict[int, ndarray]
validation_report: ValidationReport
generation_date: str
kb_loc_channel: Optional[int] = None
kb_V_loc: Optional[ndarray] = None
kb_beta_l: Optional[Dict[int, ndarray]] = None
kb_D_l: Optional[Dict[int, float]] = None
code_version: str = '0.1.0'
git_commit: Optional[str] = None
__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)
参数:
返回类型:

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

建议

推荐实践

  1. 同时导出 JSON + NPZ:JSON 存储元数据和验证报告,NPZ 存储数值数据

  2. JSON 不包含数组:默认 include_arrays=False,避免文件过大

  3. 验证输出:导出后立即加载 NPZ,检查数组形状和数值范围

  4. 版本控制:在 metadata 中添加 git_commit 字段

避免的做法

  • 不要在 JSON 中包含大数组(include_arrays=True

  • 不要混用不同版本的 AtomPPGen 导出的文件

  • 不要手动编辑 NPZ 文件(使用 Python 重新导出)

参考示例

完整示例脚本:

  • examples/export_al_example.py:Al LDA 赝势生成与导出完整流程

相关模块