mcpField
P
pymatgen

pymatgen

github.com/jaechang-hits数据与数据库38471 次安装1 周前更新
代码仓库

关于 pymatgen

pymatgen 是面向材料科学计算的 Python 库,适用于处理晶体结构和材料数据的研究者。它统一多种文件格式的结构读写,并提供结构分析、Materials Project 查询及计算输入生成能力。

主要功能

  1. 01统一的晶体与分子数据模型
  2. 02读写多种结构文件格式
  3. 03查询 Materials Project 属性
  4. 04对称性与相图分析
  5. 05模拟 XRD 衍射图谱
  6. 06生成 DFT 输入文件

适用场景

  1. 01转换 CIF、POSCAR 和 XYZ 文件
  2. 02获取计算得到的材料属性
  3. 03评估热力学相稳定性
  4. 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")

关键参数

参数模块/函数默认值范围 / 选项作用
symprecSpacegroupAnalyzer0.010.01–0.5 Å对称性检测容差;数值越大,判定越宽松
wavelengthXRDCalculator"CuKa""CuKa"、"MoKa"、浮点数(Å)用于衍射模拟的 X 射线波长
two_theta_rangeXRDCalculator.get_pattern(0, 90)角度范围元组XRD 图谱的角度范围
ENCUTMPRelaxSet INCAR520 eV300–800 eVVASP 的平面波能量截断值
chemsysMPRester.search—["Li-Fe-O"]Materials Project 查询的化学体系筛选条件
fieldsMPRester.search全部字符串列表限制返回字段,以减少 API 传输量
rStructure.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 轨迹或属性数据库中的大型数组

参考资料

评论

支持 Markdown