关于 pymatgen
pymatgen 是面向材料科学计算的 Python 库,适用于处理晶体结构和材料数据的研究者。它统一多种文件格式的结构读写,并提供结构分析、Materials Project 查询及计算输入生成能力。
主要功能
- 01统一的晶体与分子数据模型
- 02读写多种结构文件格式
- 03查询 Materials Project 属性
- 04对称性与相图分析
- 05模拟 XRD 衍射图谱
- 06生成 DFT 输入文件
适用场景
- 01转换 CIF、POSCAR 和 XYZ 文件
- 02获取计算得到的材料属性
- 03评估热力学相稳定性
- 04准备 VASP 计算输入
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jaechang-hits/ sciagent-skills --skill pymatgen安装后在 Claude Code 中输入/pymatgen确认已加载。
详细介绍
pymatgen
概述
pymatgen 是用于材料科学计算的标准 Python 库。其核心数据模型——Structure(周期性晶体材料)和 Molecule(非周期性材料)——为 30 多种文件格式(CIF、POSCAR/CONTCAR、XYZ、PDB、Gaussian、VASP)的输入和输出提供统一表示。该库与 Materials Project REST API(mp_api)集成,可获取 150,000 多种经 DFT 计算的结构及其带隙、形成能和弹性常数。pymatgen 是用于高通量 DFT 的 atomate2 和 Custodian 工作流框架的基础。
适用场景
- 在 CIF、POSCAR、XYZ 及其他格式之间解析和转换晶体结构文件
- 查询 Materials Project API,获取计算得出的带隙、形成能和稳定性数据
- 构建并分析相图和 Pourbaix 图,以研究热力学稳定性
- 根据结构对象生成 VASP、Quantum ESPRESSO 或 CP2K 输入文件
- 计算 X 射线衍射(XRD)和中子衍射图谱,并与实验结果进行比较
- 分析晶体结构的对称性、空间群和 Wyckoff 位置
- 运行分子动力学,或通过统一运行器连接多种 MD/DFT 程序时,请使用 ASE
前提条件
- Python 包:
pymatgen、mp-api(Materials Project 客户端) - 数据要求:结构文件(CIF、POSCAR)或 Materials Project API 密钥
- API 密钥:可在 materialsproject.org 免费获取;设置
PMG_MAPI_KEY环境变量
pip install pymatgen mp-api
# Set API key
export PMG_MAPI_KEY="your_api_key_here"
# Or via pymatgen config
python -c "from pymatgen.core import SETTINGS; SETTINGS['PMG_MAPI_KEY'] = 'your_key'"
快速开始
from pymatgen.core import Structure, Lattice, Species
# Build silicon diamond cubic structure from scratch
a = 5.431 # Angstroms
lattice = Lattice.cubic(a)
silicon = Structure(
lattice=lattice,
species=["Si", "Si"],
coords=[[0, 0, 0], [0.25, 0.25, 0.25]],
)
print(f"Silicon: {silicon.formula}, {silicon.volume:.2f} ų")
print(f"Space group: {silicon.get_space_group_info()}")
# Silicon: Si2, 40.89 ų
# Space group: ('Fd-3m', 227)
核心 API
模块 1:Structure 和 Lattice
用于周期性晶体的核心数据结构。
from pymatgen.core import Structure, Lattice, Element, Species
import numpy as np
# From lattice parameters
lattice = Lattice.from_parameters(a=4.05, b=4.05, c=4.05,
alpha=90, beta=90, gamma=90)
# Build FCC aluminum
al_fcc = Structure(lattice, ["Al", "Al", "Al", "Al"],
[[0, 0, 0], [0.5, 0.5, 0], [0.5, 0, 0.5], [0, 0.5, 0.5]])
print(f"Formula: {al_fcc.formula}")
print(f"Sites: {len(al_fcc)}")
print(f"Volume: {al_fcc.volume:.3f} ų")
print(f"Density: {al_fcc.density:.3f} g/cm³")
# Access sites
for site in al_fcc:
print(f" {site.species_string} at {site.frac_coords}")
# Load from file
from pymatgen.core import Structure
# From CIF (most common exchange format)
struct = Structure.from_file("material.cif")
# From POSCAR (VASP format)
struct_vasp = Structure.from_file("POSCAR")
# Get neighbors within cutoff
site = struct[0]
neighbors = struct.get_neighbors(site, r=3.0)
print(f"Neighbors within 3 Å: {len(neighbors)}")
for nn in neighbors[:3]:
print(f" {nn.species_string}: {nn.nn_distance:.3f} Å")
模块 2:Materials Project API 查询
获取 150,000 多种材料经 DFT 计算得出的属性。
from mp_api.client import MPRester
import os
api_key = os.environ.get("PMG_MAPI_KEY", "your_key")
with MPRester(api_key) as mpr:
# Search by chemical system
docs = mpr.materials.summary.search(
chemsys=["Li-Fe-O"],
fields=["material_id", "formula_pretty", "energy_above_hull",
"band_gap", "is_stable"]
)
print(f"Li-Fe-O materials: {len(docs)}")
for d in docs[:5]:
print(f" {d.material_id}: {d.formula_pretty}, "
f"Eg={d.band_gap:.2f} eV, above_hull={d.energy_above_hull:.3f} eV/atom")
# Get specific material by MP ID
with MPRester(api_key) as mpr:
doc = mpr.materials.summary.get_data_by_id(
"mp-149", # Silicon
fields=["structure", "band_gap", "formation_energy_per_atom",
"density", "is_stable", "symmetry"]
)
struct = doc.structure
print(f"Si mp-149: band_gap={doc.band_gap:.3f} eV, "
f"density={doc.density:.3f} g/cm³")
print(f"Space group: {doc.symmetry.symbol}")
模块 3:对称性分析
from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
from pymatgen.core import Structure
struct = Structure.from_file("material.cif")
# Symmetry analysis
sga = SpacegroupAnalyzer(struct, symprec=0.1)
print(f"Space group: {sga.get_space_group_symbol()} ({sga.get_space_group_number()})")
print(f"Crystal system: {sga.get_crystal_system()}")
print(f"Point group: {sga.get_point_group_symbol()}")
# Get conventional / primitive cell
primitive = sga.get_primitive_standard_structure()
conventional = sga.get_conventional_standard_structure()
print(f"Primitive: {len(primitive)} sites | Conventional: {len(conventional)} sites")
# Wyckoff positions
sym_dataset = sga.get_symmetry_dataset()
print(f"Wyckoff letters: {set(sym_dataset['wyckoffs'])}")
模块 4:相图
热力学稳定性和相边界分析。
from pymatgen.analysis.phase_diagram import PhaseDiagram, PDPlotter
from mp_api.client import MPRester
import os
api_key = os.environ.get("PMG_MAPI_KEY", "your_key")
with MPRester(api_key) as mpr:
# Get all entries in the Li-Fe-P-O chemical system
entries = mpr.get_pourbaix_entries(["Li", "Fe"])
# For phase diagram, use computed entries
with MPRester(api_key) as mpr:
entries = mpr.get_entries_in_chemsys(["Li", "Fe", "O"])
pd = PhaseDiagram(entries)
print(f"Stable phases: {len(pd.stable_entries)}")
# Check stability of a specific composition
from pymatgen.core import Composition
comp = Composition("LiFeO2")
e_hull = pd.get_e_above_hull(pd.qhull_entries[0])
print(f"E above hull: {e_hull:.3f} eV/atom")
# Plot (requires matplotlib)
plotter = PDPlotter(pd, backend="matplotlib")
plotter.show()
模块 5:XRD 图谱模拟
from pymatgen.analysis.diffraction.xrd import XRDCalculator
from pymatgen.core import Structure
import matplotlib.pyplot as plt
struct = Structure.from_file("material.cif") # or build programmatically
# Calculate XRD pattern (Cu Kα radiation, λ = 1.5406 Å)
calculator = XRDCalculator(wavelength="CuKa")
pattern = calculator.get_pattern(struct, two_theta_range=(10, 80))
print(f"Diffraction peaks: {len(pattern.x)}")
for two_theta, intensity, hkl in zip(pattern.x[:5], pattern.y[:5], pattern.hkls[:5]):
print(f" 2θ={two_theta:.2f}°, I={intensity:.1f}, hkl={hkl}")
# Plot
fig, ax = plt.subplots(figsize=(10, 4))
ax.bar(pattern.x, pattern.y, width=0.3, color="black")
ax.set_xlabel("2θ (degrees)")
ax.set_ylabel("Intensity (arb. units)")
ax.set_title(f"XRD Pattern — {struct.formula}")
plt.tight_layout()
plt.savefig("xrd_pattern.pdf", bbox_inches="tight")
模块 6:DFT 输入文件生成
生成用于 DFT 计算的 VASP 输入集。
from pymatgen.io.vasp.sets import MPRelaxSet, MPStaticSet
from pymatgen.core import Structure
struct = Structure.from_file("material.cif")
# Generate VASP relaxation input set (Materials Project standard)
relax_set = MPRelaxSet(struct)
# Write to directory
import os
os.makedirs("vasp_relax", exist_ok=True)
relax_set.write_input("vasp_relax")
print("Generated: POSCAR, INCAR, KPOINTS, POTCAR (requires VASP pseudopotentials)")
# Inspect key INCAR settings
incar = relax_set.incar
print(f"ENCUT: {incar.get('ENCUT')} eV")
print(f"KPOINTS: {relax_set.kpoints}")
# For static calculation after relaxation
static_set = MPStaticSet.from_prev_calc(prev_calc_dir="vasp_relax")
static_set.write_input("vasp_static")
核心概念
分数坐标与笛卡尔坐标
pymatgen 的 Structure 使用分数坐标(相对于晶格矢量,范围为 0–1)存储原子位置。可使用 struct.lattice.get_cartesian_coords(frac) 或 struct.lattice.get_fractional_coords(cart) 转换为笛卡尔坐标(埃)或从笛卡尔坐标转换而来。大多数文件格式使用笛卡尔坐标;pymatgen 会在读写时自动转换。
化学组成和氧化态
Composition("LiFePO4") 可解析化学式。Structure.add_oxidation_state_by_guess() 使用键价态来指定形式电荷(+Li、-O 等),这些电荷是 Pourbaix 图和部分属性计算所需的。
常见工作流
工作流 1:高通量稳定性筛选
from mp_api.client import MPRester
from pymatgen.analysis.phase_diagram import PhaseDiagram
import pandas as pd, os
api_key = os.environ.get("PMG_MAPI_KEY", "your_key")
# Screen lithium-transition-metal oxides for stability
systems = [f"Li-{m}-O" for m in ["Mn", "Co", "Ni", "Fe", "V"]]
results = []
with MPRester(api_key) as mpr:
for system in systems:
docs = mpr.materials.summary.search(
chemsys=[system],
fields=["material_id", "formula_pretty", "energy_above_hull",
"band_gap", "is_stable", "formation_energy_per_atom"]
)
for d in docs:
results.append({
"system": system,
"mpid": d.material_id,
"formula": d.formula_pretty,
"e_above_hull": d.energy_above_hull,
"band_gap": d.band_gap,
"stable": d.is_stable,
})
df = pd.DataFrame(results)
stable = df[df["stable"] == True].sort_values("band_gap")
print(f"Stable phases: {len(stable)}/{len(df)}")
print(stable[["formula", "system", "band_gap", "e_above_hull"]].head(10))
stable.to_csv("stability_screen.csv", index=False)
工作流 2:结构操作与导出
from pymatgen.core import Structure
from pymatgen.transformations.standard_transformations import (
SupercellTransformation, SubstitutionTransformation
)
# Load and analyze structure
struct = Structure.from_file("material.cif")
print(f"Original: {struct.formula}, {len(struct)} sites")
# Create 2×2×2 supercell
sc_matrix = [[2, 0, 0], [0, 2, 0], [0, 0, 2]]
supercell = SupercellTransformation(sc_matrix).apply_transformation(struct)
print(f"Supercell: {len(supercell)} sites")
# Substitute element (e.g., 10% Fe doping on Mn sites)
sub = SubstitutionTransformation({"Mn": {"Mn": 0.9, "Fe": 0.1}})
doped = sub.apply_transformation(struct)
print(f"Doped composition: {doped.composition.reduced_formula}")
# Export in multiple formats
struct.to(filename="output.cif") # CIF
struct.to(filename="POSCAR") # VASP POSCAR
struct.to(filename="output.xyz") # XYZ
print("Exported CIF, POSCAR, XYZ")
关键参数
| 参数 | 模块/函数 | 默认值 | 范围 / 选项 | 作用 |
|---|---|---|---|---|
symprec | SpacegroupAnalyzer | 0.01 | 0.01–0.5 Å | 对称性检测容差;数值越大,判定越宽松 |
wavelength | XRDCalculator | "CuKa" | "CuKa"、"MoKa"、浮点数(Å) | 用于衍射模拟的 X 射线波长 |
two_theta_range | XRDCalculator.get_pattern | (0, 90) | 角度范围元组 | XRD 图谱的角度范围 |
ENCUT | MPRelaxSet INCAR | 520 eV | 300–800 eV | VASP 的平面波能量截断值 |
chemsys | MPRester.search | — | ["Li-Fe-O"] | Materials Project 查询的化学体系筛选条件 |
fields | MPRester.search | 全部 | 字符串列表 | 限制返回字段,以减少 API 传输量 |
r | Structure.get_neighbors | — | 1–8 Å | 邻居搜索的截断半径 |
常用示例
示例:批量将 CIF 转换为 POSCAR
from pymatgen.core import Structure
from pathlib import Path
cif_dir = Path("cif_files")
poscar_dir = Path("poscar_files")
poscar_dir.mkdir(exist_ok=True)
for cif_path in cif_dir.glob("*.cif"):
try:
struct = Structure.from_file(str(cif_path))
out_path = poscar_dir / f"{cif_path.stem}_POSCAR"
struct.to(filename=str(out_path))
print(f"Converted: {cif_path.name} → {out_path.name}")
except Exception as e:
print(f"FAILED {cif_path.name}: {e}")
示例:获取材料列表的带隙
from mp_api.client import MPRester
import pandas as pd, os
mp_ids = ["mp-149", "mp-2815", "mp-1265"] # Si, GaAs, TiO2
api_key = os.environ.get("PMG_MAPI_KEY", "your_key")
with MPRester(api_key) as mpr:
docs = mpr.materials.summary.get_data_by_ids(
mp_ids, fields=["material_id", "formula_pretty", "band_gap", "is_gap_direct"]
)
df = pd.DataFrame([{
"mpid": d.material_id,
"formula": d.formula_pretty,
"band_gap_eV": d.band_gap,
"direct_gap": d.is_gap_direct,
} for d in docs])
print(df.to_string(index=False))
故障排查
| 问题 | 原因 | 解决方案 |
|---|---|---|
APIError: Invalid API key | 未设置或已过期 PMG_MAPI_KEY | 设置环境变量:export PMG_MAPI_KEY="your_key";在 materialsproject.org 重新生成密钥 |
SpacegroupAnalyzer 返回错误的空间群 | 原子位置存在轻微无序;symprec 过于严格 | 将 symprec 从 0.01 增加到 0.1;先使用 get_refined_structure() |
Structure.from_file 无法读取 CIF | 存在无序、部分占位或非标准 CIF | 使用 CifParser(file).get_structures(primitive=False);设置 occupancy_tolerance=2.0 |
MPRester 挂起或超时 | 大型查询返回数千条结果 | 添加 fields=["material_id", "formula_pretty"] 以减少数据量;使用 chunk_size |
| VASP 输入集找不到 POTCAR | 未配置 VASP 赝势库 | 运行 pmg config --add PMG_VASP_PSP_DIR /path/to/potpaw |
| 大型超胞导致内存错误 | 超胞包含数千个原子 | 减小超胞尺寸;使用 Structure.get_sorted_structure(),然后逐步写入 |
XRDCalculator 未生成衍射峰 | 结构只有 1 个位点或所有位点的元素相同 | 确保结构包含多个位点;通过 print(struct) 检查结构是否正确加载 |
相关技能
pymoo— 使用 pymatgen 描述符进行材料属性筛选的多目标优化autodock-vina-docking— 与 pymatgen 类似的分子对接结构准备工作流zarr-python— 高效存储 MD 轨迹或属性数据库中的大型数组
参考资料
- pymatgen 文档 — 完整的 API 参考、教程和兼容性矩阵
- Materials Project API 文档 — REST API 和 mp-api 客户端参考
- pymatgen 论文:Ong 等(2013),CMS — 原始论文及设计理念
- Materials Project 论文:Jain 等(2013),APL Materials — 数据库介绍及计算属性
- pymatgen GitHub — 源代码和示例