pymatgen 实战教程:材料建模、DFT 前后处理与高通量计算
环境:Windows + Miniconda,Python 3.14.4,VS Code,纯
.py脚本
基准版本:pymatgen 2025.x(当前最新稳定版)
本文所有 API 均基于 2025.x 真实用法编写;凡涉及联网/API key、或不同版本间易变的接口,都会明确标注。建议写作时对照官方文档pymatgen.org核对版本差异。
目录
- 简介与定位
- 安装与版本检查
- 核心对象:Element / Composition / Lattice / Structure / Molecule
- 读写结构:CIF、POSCAR、多格式互转
- 构建与修改结构
- 表面与 Slab:催化吸附建模
- Materials Project 数据获取:MPRester
- PhaseDiagram:相图与凸包稳定性
- 与 VASP 对接:Vasprun / Poscar 后处理
- 分析工具:对称性、近邻、键长
- 科研实战示例
- 常见坑
- 延伸资源
1. 简介与定位
pymatgen(Python Materials Genomics)是材料科学计算领域事实上的标准 Python 库,由 Materials Project 团队维护。在 DFT 工作流中,它通常扮演三类角色:
- 结构建模与操纵:构建、读写、变换晶体结构(POSCAR/CIF),切表面、建超胞、掺杂、构建吸附构型。
- DFT 前后处理:解析 VASP 输出(
vasprun.xml、OUTCAR、OSZICAR),提取能量、能带、态密度,生成 VASP 输入。 - 高通量与数据库:对接 Materials Project 数据库,用
PhaseDiagram做相图/凸包稳定性分析,批量筛选候选材料。
在科研场景里,pymatgen 最常用的部分是:
- 用
Structure/SlabGenerator搭催化剂表面与吸附构型; - 用
Vasprun读能量算吸附能/形成能; - 用
PhaseDiagram筛稳定相; - 用
MPRester从 Materials Project 拉结构、批量拿形成能数据。
pymatgen 底层依赖 numpy / scipy / spglib(对称性)/ matplotlib(绘图,可选)。核心对象大多在
pymatgen.core,IO 在pymatgen.io.*,分析在pymatgen.analysis.*。
2. 安装与版本检查
2.1 安装
推荐用 conda(conda-forge 会一并解决 numpy/scipy/spglib 等编译依赖):
# 新建环境(若 Python 3.14 下 spglib/numpy 尚无预编译 wheel,可退回 3.12/3.13)
conda create -n mat python=3.12 -y
conda activate mat
conda install -c conda-forge pymatgen -y
或用 pip:
pip install pymatgen
提示:Python 3.14 较新,某些二进制依赖(spglib、scipy)可能暂时没有对应 wheel。若
pip install pymatgen报编译错误,优先用 conda-forge,或改用 3.12/3.13 环境。这属于生态兼容问题,与 pymatgen 本身无关。
2.2 版本检查
# version_check.py
from importlib.metadata import version
print("pymatgen version:", version("pymatgen"))
# pymatgen.core 内也暴露版本号
import pymatgen.core
print("core.__version__:", pymatgen.core.__version__)
建议脚本里对关键版本做一次断言,避免团队环境不一致导致 API 差异:
from importlib.metadata import version
assert version("pymatgen") >= "2024.0", "pymatgen 版本过旧"
2.3 可选:配置 POTCAR 库(仅当你需要让 pymatgen 自动写 POTCAR)
pymatgen 写 VASP 输入集、生成 POTCAR 时,需要知道赝势库路径。可用 PMG_VASP_PSP_DIR 环境变量,或写 ~/.pmgrc.yaml。若只做后处理(读 vasprun.xml),无需配置。
# 以环境变量为例
export PMG_VASP_PSP_DIR="D:/vasp_pot/potpaw_PBE.54"
3. 核心对象
pymatgen 的核心对象都从 pymatgen.core 导入。最常用:Element、Species、Composition、Lattice、Structure、Molecule。
3.1 Element(元素)
from pymatgen.core import Element
fe = Element("Fe")
print(fe.Z) # 原子序数 26
print(fe.symbol) # 'Fe'
print(fe.X) # 电负性(Pauling)
print(fe.atomic_mass) # 相对原子质量
print(fe.group, fe.row) # 族 / 周期
print(fe.is_transition_metal) # 过渡金属判断(催化里常用)
Element 也可带自旋极化相关属性(如 Element("Fe").spin 缺省未定)。单原子催化筛选中,常用 is_transition_metal / 电负性做初筛。
3.2 Species(带氧化态的元素)
当需要区分价态(如 Fe2+ vs Fe3+)时用 Species:
from pymatgen.core import Species
fe3 = Species("Fe", 3) # Fe3+
fe2 = Species("Fe", 2) # Fe2+
print(fe3.oxi_state) # 3
print(str(fe3)) # 'Fe3+'
结构里通常用 Element 即可;需要价态相关分析(如键价和、氧化态标记)时才用 Species。
3.3 Composition(化学式/组分)
from pymatgen.core import Composition
c = Composition("LiFePO4")
print(c.reduced_formula) # 'LiFe(PO4)1' 或类似的最简式
print(c.weight) # 分子量(相对)
print(c.num_atoms) # 总原子数 = 7
# 从字典构造
c2 = Composition({"Fe": 2, "O": 3})
print(c2.formula) # 'Fe2 O3'
print(c2.get_atomic_fraction("Fe")) # 0.4
print(c2.get_wt_fraction("Fe")) # 质量分数
# 元素计数
print(c.get_el_amt_dict()) # {Element('Li'): 1.0, ...}
Composition 是相图、形成能、MPRester 搜索里的核心类型,也支持直接加减、比较。
3.4 Lattice(晶格)
from pymatgen.core import Lattice
# 立方晶格
l = Lattice.cubic(3.615) # 面心 Cu 的晶格常数
print(l.volume) # 体积(Å^3)
print(l.a, l.b, l.c) # 晶格常数
print(l.alpha, l.beta, l.gamma) # 角度(度)
# 通用三斜参数
l2 = Lattice.from_parameters(4.0, 4.0, 4.0, 90, 90, 90)
# 直接从 3x3 矩阵(行向量为晶格基矢)
l3 = Lattice([[3.5, 0, 0], [0, 3.5, 0], [0, 0, 3.5]])
print(l3.matrix) # 基矢矩阵
3.5 Structure(晶体结构)—— 重中之重
Structure 是最核心的对象。构造方式很多,最常用三种:
from pymatgen.core import Structure, Lattice
# 方式 1:晶格 + 元素列表 + 坐标列表(默认分数坐标)
lattice = Lattice.cubic(3.615)
s = Structure(lattice, ["Cu", "Cu"], [[0, 0, 0], [0.5, 0.5, 0.5]])
# 方式 2:每个原子写成 [元素, 坐标] 的联合列表
s2 = Structure(lattice, ["Cu", [0, 0, 0]], ["Cu", [0.5, 0.5, 0.5]])
# 方式 3:用空间群 + 不等价位置自动展开(推荐用于高对称结构)
s3 = Structure.from_spacegroup(
"Fm-3m", # 空间群符号或编号
Lattice.cubic(3.615),
["Cu"],
[[0, 0, 0]], # 不等价 Wyckoff 位置的分数坐标
)
print(s3.num_sites) # 4 —— Fm-3m 自动生成 4 个 Cu
访问结构信息:
print(s.num_sites) # 原子数
print(s.formula) # 化学式
print(s.composition) # Composition 对象
print(s.lattice) # Lattice 对象
print(s.volume) # 体积
print(s.density) # 密度 g/cm^3
print(s.cart_coords) # 笛卡尔坐标数组 (N,3)
print(s.frac_coords) # 分数坐标数组 (N,3)
# 遍历原子(site)
for site in s:
print(site.index, site.specie, site.frac_coords, site.coords)
# 按索引取 site
site0 = s[0]
print(site0.specie) # Element('Cu')
print(site0.coords) # 笛卡尔坐标
print(site0.frac_coords) # 分数坐标
不可变版本 IStructure:如果只读、不想被意外修改,可用 pymatgen.core.IStructure(构造方式相同,但不支持增删改)。用于缓存/字典 key 时更安全。
3.6 Molecule(分子)
from pymatgen.core import Molecule
co2 = Molecule(["C", "O", "O"],
[[0, 0, 0], [-1.16, 0, 0], [1.16, 0, 0]])
print(co2.formula)
print(co2.composition)
co2.center() # 平移到质心为原点
print(co2.get_centroid())
Molecule 用于吸附质(CO、CO2、H2O 等)建模、分子筛/MOF 中的客体分子等。与 Structure 共享很多接口。
4. 读写结构
pymatgen 的 IO 分散在 pymatgen.io.* 子包:CIF 在 pymatgen.io.cif,VASP 在 pymatgen.io.vasp。
4.1 通用读取器 Structure.from_file
Structure.from_file 会根据扩展名自动识别格式,是最省心的入口:
from pymatgen.core import Structure
# 读 CIF
s1 = Structure.from_file("input.cif")
# 读 POSCAR
s2 = Structure.from_file("POSCAR")
# 读 CONTCAR
s3 = Structure.from_file("CONTCAR")
它内部对 CIF 走
CifParser,对 POSCAR/CONTCAR 走Poscar。对普通结构文件足够用。
4.2 CIF:CifParser / CifWriter
from pymatgen.io.cif import CifParser, CifWriter
# 解析 CIF(一个 CIF 文件可能含多个结构)
parser = CifParser("example.cif")
structures = parser.parse_structures(primitive=False) # 返回 list[Structure]
s = structures[0]
# primitive=True 会尝试约化到原胞
prim = parser.parse_structures(primitive=True)[0]
# 写 CIF
CifWriter(s).write_file("out.cif")
# 或直接用 Structure 的方法(按扩展名推断格式)
s.to(filename="out.cif")
4.3 POSCAR:Poscar
from pymatgen.io.vasp import Poscar
s = Structure.from_file("CONTCAR") # 已有结构
# 写 POSCAR
poscar = Poscar(s)
poscar.write_file("POSCAR")
# 读 POSCAR
p = Poscar.from_file("POSCAR")
s_read = p.structure
Poscar 还支持写入时给每个元素指定速度(分子动力学)、写 selective dynamics 标志等高级选项(Poscar(s, sort_structure=False, site_symbols=...))。
4.4 多格式互转
from pymatgen.core import Structure
from pymatgen.io.cif import CifWriter
s = Structure.from_file("POSCAR")
# 统一写法:to() 按扩展名决定格式,返回 None(写入文件)
s.to(filename="out.cif")
s.to(filename="out.cssr")
# 若要得到格式字符串(不落盘),用 fmt 参数
poscar_str = s.to(fmt="poscar") # 返回 POSCAR 文本
cif_str = s.to(fmt="cif") # 返回 CIF 文本
print(poscar_str[:80])
批量互转的实用脚本:
# convert.py —— 把一个文件夹里的 POSCAR 全转成 CIF
from pathlib import Path
from pymatgen.core import Structure
for f in Path("poscars").glob("POSCAR*"):
s = Structure.from_file(f)
s.to(filename=f"cifs/{f.name}.cif")
5. 构建与修改结构
构建催化模型、做掺杂、切超胞时,下面这些方法每天都会用到。
5.1 增删改原子
from pymatgen.core import Structure, Lattice
s = Structure.from_spacegroup("Fm-3m", Lattice.cubic(3.615), ["Cu"], [[0, 0, 0]])
# 添加原子(默认分数坐标)
s.append("O", [0.5, 0.5, 0.5], coords_are_cartesian=False)
# 在指定索引插入
s.insert(0, "O", [0.25, 0.25, 0.25], coords_are_cartesian=False)
# 替换某个位置的元素/坐标
s.replace(0, "N", [0.1, 0.1, 0.1], coords_are_cartesian=False)
# 删除指定索引的原子
s.remove_sites([0, 2]) # 删除第 0、2 号原子
# 删除指定元素的所有原子
s.remove_species(["O"])
print(s.formula)
5.2 平移 / 缩放
# 平移若干原子(分数坐标)
s.translate_sites([0, 1], [0.5, 0, 0], frac_coords=True, to_unit_cell=True)
# 整体缩放晶格体积到指定值
s.scale_lattice(s.volume * 2) # 体积翻倍
5.3 掺杂 / 替换(substitute vs replace_species)
# 推荐:replace_species,接受 dict 映射,稳定且直观
s_nico = s.replace_species({"Cu": "Ni"})
print(s_nico.formula)
# substitute 同样可用(接受 dict 映射)。不同版本曾调整签名,不确定时以 replace_species 为准
s_nico2 = s.substitute({"Cu": "Co"})
掺杂质子的常见套路:先
make_supercell,再replace_species或replace某几个 site。
5.4 超胞
# 2x2x2 超胞,两种等价写法
super1 = s.make_supercell([[2, 0, 0], [0, 2, 0], [0, 0, 2]])
super2 = s * (2, 2, 2)
print(super1.num_sites)
5.5 排序 / 扰动 / 排序副本
s.sort() # 就地按电负性等排序
s_sorted = s.get_sorted_structure() # 返回排序后的副本(不修改原对象)
s.perturb(0.01) # 随机扰动原子坐标 0.01 Å(建初始构型/打破对称常用)
5.6 氧化态
s.add_oxidation_state_by_guess() # 按电负性猜测氧化态
print([site.specie.oxi_state for site in s])
s.remove_oxidation_states()
6. 表面与 Slab
切表面是催化建模的第一步。核心类是 pymatgen.core.surface.SlabGenerator。
from pymatgen.core import Structure, Lattice
from pymatgen.core.surface import SlabGenerator
# 1. 先建体相
cu = Structure.from_spacegroup("Fm-3m", Lattice.cubic(3.615), ["Cu"], [[0, 0, 0]])
# 2. 切 (111) 表面
slabgen = SlabGenerator(
cu,
miller_index=(1, 1, 1), # 米勒指数
min_slab_size=10.0, # 最小 slab 厚度(Å)
min_vacuum_size=15.0, # 最小真空层厚度(Å)
lll_reduce=True, # 用 LLL 约化晶格,让超胞尽量"方正"
center_slab=True, # 把 slab 居中、真空均分在上下
)
slab = slabgen.get_slab(shift=0) # 取某个 shift 对应的终结面
slabs = slabgen.get_slabs() # 所有对称不等价的终结面
print("终结面数量:", len(slabs))
print(slab.num_sites, slab.lattice.c)
关键点:
min_vacuum_size至少 12–15 Å,做带电体系/偶极校正时要更大。- 表面建模往往还要
make_supercell扩成 p(x n) 超胞,避免吸附质自相互作用。 get_slabs()返回多个终结面,通常用get_slab(shift=i)逐个选取,比较表面能后挑最稳定的。
加吸附质:AdsorbateSiteFinder(高级)
from pymatgen.core import Molecule
from pymatgen.analysis.adsorption import AdsorbateSiteFinder
asf = AdsorbateSiteFinder(slab)
sites = asf.find_adsorption_sites() # dict,含 ontop/bridge/hollow 等吸附位坐标
co = Molecule(["C", "O"], [[0, 0, 0], [0, 0, 1.15]]) # CO 吸附质
ads_slab = asf.add_adsorbate(co, sites["ontop"][0]) # 放到顶位
ads_slab.to(filename="POSCAR_ads")
AdsorbateSiteFinder内部用 Delaunay 三角剖分找对称不等价位点;add_adsorbate的height(吸附距离)等参数不同版本略有差异,建议help(AdsorbateSiteFinder.add_adsorbate)确认。
7. Materials Project 数据获取
注意:需要 Materials Project API key。 到 materialsproject.org 注册后在 Dashboard 生成。新版 API 与旧 legacy API 是两套体系:
- 旧:
pymatgen.ext.matproj.MPRester+PMG_MAPI_KEY(legacy.materialsproject.org,已弃用)- 新(当前推荐):
mp_api.client.MPRester+ API key(api.materialsproject.org)
新 API 使用方式:
from mp_api.client import MPRester
API_KEY = "你的_API_KEY" # 不要硬编码到提交的脚本里,建议放环境变量
with MPRester(api_key=API_KEY) as mpr:
# 1. 按 material_id 下载结构
structure = mpr.get_structure_by_material_id("mp-19017") # 例:LiFePO4 之类
# 2. 按组分搜索(chemsys 用连字符连接元素)
docs = mpr.summary.search(
chemsys="Cu-O",
fields=["material_id", "formula_pretty",
"formation_energy_per_atom", "band_gap", "structure"],
)
for d in docs[:5]:
print(d.material_id, d.formula_pretty,
d.formation_energy_per_atom, d.band_gap)
# 3. 直接拿相图所需的能量条目
entries = mpr.get_entries_in_chemsys(["Cu", "O"])
print("条目数:", len(entries))
常用字段名(mpr.summary.search 的 fields):material_id、formula_pretty、structure、formation_energy_per_atom、energy_above_hull、band_gap、is_metal、symmetry。
本地可跑替代(无需联网/key):直接按 §3/§5 手工
Structure.from_spacegroup构造,或用 §8 自己填能量做相图。日常练习/教学时优先用本地构造,避免网络与 key 干扰。
推荐做法:把 API key 放环境变量,脚本里读取:
import os
from mp_api.client import MPRester
key = os.environ.get("MP_API_KEY")
with MPRester(api_key=key) as mpr:
...
8. PhaseDiagram
相图/凸包是判断"某物相是否稳定、形成能多少"的标准工具。核心在 pymatgen.analysis.phase_diagram。
from pymatgen.analysis.phase_diagram import PhaseDiagram, PDPlotter
from pymatgen.entries.computed_entries import ComputedEntry
from pymatgen.core import Composition
# 每个条目 = 某物相 + 其 DFT 总能量(eV)
# 注意:energy 是"整个化学式(原胞)"的总能量,PhaseDiagram 内部会自动换算成每原子能量
entries = [
ComputedEntry(Composition("Cu"), -3.7), # 纯 Cu
ComputedEntry(Composition("Cu2O"), -11.6), # Cu2O 原胞(3 原子)
ComputedEntry(Composition("CuO"), -7.4), # CuO 原胞(2 原子)
]
pd = PhaseDiagram(entries)
# 稳定相(落在凸包上的相)
print("=== 稳定相 ===")
for e in pd.stable_entries:
print(e.composition.reduced_formula, round(e.energy_per_atom, 4))
# 形成能(相对组成元素参考态)
print("=== 形成能 (eV/atom) ===")
for e in entries:
print(e.composition.reduced_formula, round(pd.get_form_energy_per_atom(e), 4))
# 距离凸包的能差:e_above_hull == 0 表示热力学稳定
print("=== 凸包能差 (eV/atom) ===")
for e in entries:
decomp, e_above_hull = pd.get_decomp_and_e_above_hull(e)
print(e.composition.reduced_formula, round(e_above_hull, 4), "->", decomp)
能量凸包稳定性判据:e_above_hull == 0(或 < 某个阈值如 0.05–0.1 eV/atom)视为(亚)稳定;> 0 表示会分解成凸包上相邻相的混合物。get_decomp_and_e_above_hull 返回 (分解反应, 能差)。
绘图(需 matplotlib):
import matplotlib.pyplot as plt
plotter = PDPlotter(pd)
plotter.get_plot() # 二元 = 2D 曲线
plt.savefig("pd.png", dpi=150)
# 三元体系会生成 3D 凸包
从 DFT 输出构造条目(比手填能量更真实):
from pymatgen.entries.computed_entries import ComputedStructureEntry
from pymatgen.io.vasp import Vasprun
entries = []
for name in ["cu", "cu2o", "cuo"]:
vr = Vasprun(f"{name}/vasprun.xml", parse_potcar_file=False)
e = ComputedStructureEntry(vr.final_structure, vr.final_energy)
entries.append(e)
pd = PhaseDiagram(entries)
for e in entries:
decomp, eh = pd.get_decomp_and_e_above_hull(e)
print(e.composition.reduced_formula, f"{eh:.3f} eV/atom")
9. 与 VASP 对接
9.1 读 vasprun.xml:能量 / 结构 / DOS / 能带
from pymatgen.io.vasp import Vasprun
vr = Vasprun("vasprun.xml", parse_potcar_file=False) # 无 POTCAR 时务必关掉,否则会告警/报错
# 能量与结构
E = vr.final_energy # 最终总能(eV)
final_struct = vr.final_structure # 弛豫后结构
print("E =", E, "eV")
print("电子步是否收敛:", vr.converged)
print("离子步是否收敛:", vr.converged_ionic)
# 态密度
dos = vr.complete_dos # CompleteDos 对象(含分波态密度)
tdos = vr.tdos # 总 DOS
print(tdos.energies.shape, tdos.densities.shape)
# 带隙 / VBM / CBM(单点或非 line-mode 也能给出带隙信息)
gap, cbm, vbm, is_direct = vr.eigenvalue_band_properties
print(f"gap={gap:.3f} eV, VBM={vbm:.3f}, CBM={cbm:.3f}, direct={is_direct}")
能带(需 line-mode KPOINTS 计算):
bs = vr.get_band_structure(kpoints_filename="KPOINTS", line_mode=True)
print(bs.get_band_gap()) # 带隙
print(bs.bands[Spin.up][0]) # 自旋向上第 0 条能带的能量序列
9.2 读 OUTCAR / OSZICAR
from pymatgen.io.vasp import Outcar, Oszicar
outcar = Outcar("OUTCAR")
print(outcar.final_energy) # eV
print(outcar.is_stopped) # 是否正常结束
print(outcar.magnetization) # 总磁矩(μB)
oszicar = Oszicar("OSZICAR")
print(oszicar.final_energy)
print(oszicar.ionic_steps) # 每个离子步的能量列表
9.3 生成 VASP 输入
from pymatgen.io.vasp.sets import MPRelaxSet, MPStaticSet
# 用 Materials Project 风格参数生成输入文件(INCAR/POSCAR/POTCAR/KPOINTS)
MPRelaxSet(final_struct).write_input("relax")
MPStaticSet(final_struct).write_input("static")
MPRelaxSet/MPStaticSet写 POTCAR 需要配置赝势库(见 §2.3)。只做结构后处理则不需要。
9.4 简单 DOS 绘图
import matplotlib.pyplot as plt
from pymatgen.io.vasp import Vasprun
vr = Vasprun("vasprun.xml", parse_potcar_file=False)
tdos = vr.tdos
plt.plot(tdos.energies, tdos.densities[Spin.up], label="up")
plt.plot(tdos.energies, tdos.densities[Spin.down], label="down")
plt.xlabel("E (eV)")
plt.ylabel("DOS")
plt.legend()
plt.show()
Spin在pymatgen.electronic_structure.core,常用时from pymatgen.electronic_structure.core import Spin。
10. 分析工具
10.1 对称性
from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
finder = SpacegroupAnalyzer(s)
print(finder.get_space_group_symbol()) # 空间群符号
print(finder.get_crystal_system()) # 晶系
prim = finder.get_primitive_standard_structure() # 标准原胞
conv = finder.get_conventional_standard_structure() # 标准惯用胞
10.2 近邻(配位数、键长)
方法 A:按半径简单判近邻
neighbors = s.get_neighbors(s[0], r=3.0) # 距 s[0] 3 Å 内的原子
for n in neighbors:
print(n.species, round(n.nn_distance, 3)) # n.nn_distance 为真实最近邻距离
方法 B:几何算法(更鲁棒,推荐)
from pymatgen.analysis.local_env import CrystalNN
cnn = CrystalNN()
for site in s:
nn_list = cnn.get_nn_info(s, site.index)
print(site.specie, "配位数", len(nn_list))
for nn in nn_list:
print(" ->", nn["site"].specie, round(nn["length"], 3)) # nn['length'] 为键长
10.3 距离矩阵
dm = s.distance_matrix # 周期边界下的最短原子间距矩阵 (N,N)
print(dm)
11. 科研实战示例
示例 1:从零构建 Cu(111) 表面并加 CO(CO2 还原催化剂模型)
# build_cu_surface.py
from pymatgen.core import Structure, Lattice
from pymatgen.core.surface import SlabGenerator
# 体相 fcc Cu
cu = Structure.from_spacegroup("Fm-3m", Lattice.cubic(3.615), ["Cu"], [[0, 0, 0]])
# 切 (111) 表面
slabgen = SlabGenerator(cu, (1, 1, 1), min_slab_size=8, min_vacuum_size=15,
lll_reduce=True, center_slab=True)
slab = slabgen.get_slab(shift=0)
# 扩成 3x3 表面超胞(催化常用,减小吸附质自相互作用)
slab = slab.make_supercell([[3, 0, 0], [0, 3, 0], [0, 0, 1]])
print("原子数:", slab.num_sites, " 晶格c:", round(slab.lattice.c, 2))
slab.to(filename="POSCAR_slab")
print("已写出 POSCAR_slab")
示例 2:读 VASP 输出算吸附能
吸附能定义(以 CO 吸附为例):E_ads = E(slab+CO) - E(slab) - E(CO),负值表示放热、吸附稳定。
# ads_energy.py
from pymatgen.io.vasp import Vasprun
def read_energy(path):
return Vasprun(path, parse_potcar_file=False).final_energy
E_slab = read_energy("slab/vasprun.xml") # 干净表面
E_ads_slab = read_energy("ads_co/vasprun.xml") # 吸附 CO 后
E_CO = read_energy("co/vasprun.xml") # 孤立 CO(放 20 Å 真空盒子算)
E_ads = E_ads_slab - E_slab - E_CO
print(f"CO 吸附能 = {E_ads:.3f} eV")
示例 3:按形成能筛选稳定相(本地 VASP 结果)
# stability.py
from pymatgen.io.vasp import Vasprun
from pymatgen.entries.computed_entries import ComputedStructureEntry
from pymatgen.analysis.phase_diagram import PhaseDiagram
phases = ["cu", "cu2o", "cuo"] # 各自一个目录,含弛豫后的 vasprun.xml
entries = []
for p in phases:
vr = Vasprun(f"{p}/vasprun.xml", parse_potcar_file=False)
entries.append(ComputedStructureEntry(vr.final_structure, vr.final_energy))
pd = PhaseDiagram(entries)
print("稳定相:", [e.composition.reduced_formula for e in pd.stable_entries])
for e in entries:
decomp, eh = pd.get_decomp_and_e_above_hull(e)
print(f"{e.composition.reduced_formula:8s} E_hull={eh:6.3f} eV/atom")
示例 4:从 Materials Project 批量下载并切表面(需 API key)
# mp_surface_screen.py —— 需 Materials Project API key
import os
from mp_api.client import MPRester
from pymatgen.core.surface import SlabGenerator
key = os.environ["MP_API_KEY"]
with MPRester(api_key=key) as mpr:
# 找 Cu 的稳定氧化物
docs = mpr.summary.search(
chemsys="Cu-O",
energy_above_hull=(0, 0.05), # 只看稳定/近稳定相
fields=["material_id", "formula_pretty", "structure"],
)
for d in docs[:3]:
s = d.structure
# 对每个稳定相切低指数面
for mi in [(1, 0, 0), (1, 1, 0), (1, 1, 1)]:
try:
slab = SlabGenerator(s, mi, min_slab_size=8,
min_vacuum_size=15, center_slab=True).get_slab(shift=0)
fname = f"{d.material_id}_{''.join(map(str, mi))}.vasp"
slab.to(filename=fname)
print("写出", fname)
except Exception as ex:
print("跳过", d.material_id, mi, "原因:", ex)
12. 常见坑
-
Materials Project API key 新旧混淆:
pymatgen.ext.matproj.MPRester(legacy)已弃用,务必用mp_api.client.MPRester(需要mp-api包,随新版 pymatgen 安装)。新 key 在 materialsproject.org 的 Dashboard 生成。 -
Vasprun报 POTCAR 相关告警/错误:读vasprun.xml时若目录无 POTCAR,务必parse_potcar_file=False。新版该参数默认值有变化,显式写死最稳。 -
API 版本变动:pymatgen 近年调整过部分接口(如
MPRester位置、Molecule.substitute/Structure.substitute签名、Vasprun参数、SlabGenerator/AdsorbateSiteFinder细节)。不确定时help(Class.method)或查官方文档,勿照搬 2020 年以前的旧教程。 -
晶格精度:CIF/POSCAR 互转时小数位数可能导致晶格常数轻微变化。写 CIF 可用
CifWriter(s, significant_figures=8)提高精度;写 POSCAR 默认足够,但做晶格敏感分析(声子、弹性)要保留充分位数。 -
Python 3.14 依赖 wheel:部分二进制依赖(spglib/scipy)在新 Python 下可能暂缺预编译包,报编译错误时改 conda-forge 安装或退到 3.12/3.13。
-
Structure.to的返回:to(fmt=...)返回字符串,to(filename=...)返回 None 并写文件。二者别混用。 -
slab 真空层:
min_vacuum_size太小会导致相邻周期 slab 相互作用、能量不准;带电/偶极校正体系要更大(≥ 20 Å)并配合LDIPOL/IDIPOL。 -
能量单位:
Vasprun.final_energy是 eV;ComputedEntry的energy是"整个原胞"总能,PhaseDiagram内部自动按每原子处理,别把 per-atom 值当 total 传。
13. 延伸资源
- 官方文档:https://pymatgen.org (最权威,API 变动以它为准)
- API 参考:https://pymatgen.org/pymatgen.core.html 及
pymatgen.analysis、pymatgen.io各页 - Materials Project 文档(新 API):https://docs.materialsproject.org/downloading-data/using-the-api
- 官方示例仓库:https://github.com/materialsproject/pymatgen/tree/master/examples
- 常用分析模块备忘:
- 电子结构:
pymatgen.electronic_structure(Dos、BandStructure、Plotter) - 弹性/力学:
pymatgen.analysis.elasticity - 键价/结构合理性:
pymatgen.analysis.bond_valence、pymatgen.analysis.chemenv - 吸附:
pymatgen.analysis.adsorption - 与 ASE 互转:
pymatgen.io.ase.AseAtomsAdaptor
- 电子结构:
提示:本文所有代码基于 pymatgen 2025.x 编写,若你本机是 2026.x 或更新版本,个别方法签名可能微调。养成习惯:写脚本前
import pymatgen; print(pymatgen.core.__version__),对不确定的接口help()一眼确认,比任何教程都可靠。
评论交流
欢迎留下你的想法