skills/pymatgen/references/analysis_modules.md
This reference targets pymatgen==2026.5.4 with
pymatgen-core==2026.7.16. An analysis object returning a value does not
establish convergence, uncertainty, experimental agreement, or suitability of
the underlying model.
from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
analyzer = SpacegroupAnalyzer(
structure,
symprec=0.01, # Å
angle_tolerance=5.0, # degrees
)
result = {
"symbol": analyzer.get_space_group_symbol(),
"number": analyzer.get_space_group_number(),
"crystal_system": str(analyzer.get_crystal_system()),
"point_group": analyzer.get_point_group_symbol(),
"operation_count": len(analyzer.get_symmetry_operations()),
}
symmetrized = analyzer.get_symmetrized_structure()
equivalent_indices = symmetrized.equivalent_indices
wyckoff_symbols = symmetrized.wyckoff_symbols
The documented pymatgen default is symprec=0.01 Å; a looser value such as
0.1 Å is often used for relaxed structures and by the Materials Project
pipeline. Results can change with:
symprec, angle_tolerance, and spglib versionAlways sweep justified tolerances and report the entire sensitivity grid. Do not choose a tolerance solely because it gives a desired group.
Standardized or primitive structures are new representations:
conventional = analyzer.get_conventional_standard_structure(
keep_site_properties=False
)
primitive = analyzer.get_primitive_standard_structure(
keep_site_properties=False
)
Site properties can be lost or propagated without symmetry-aware adjustment. Preserve the parent and compare composition, volume per atom, magnetic order, and property semantics.
from pymatgen.analysis.structure_matcher import StructureMatcher
matcher = StructureMatcher(
ltol=0.2,
stol=0.3,
angle_tol=5,
primitive_cell=True,
scale=True,
)
matches = matcher.fit(first, second)
Record every tolerance and option. A match is equivalence under the chosen algorithm, reductions, scaling, and species comparator—not identity of files, provenance, defects, magnetic states, or experimental phases.
from pymatgen.analysis.local_env import CrystalNN, VoronoiNN
crystal_nn = CrystalNN()
neighbors = crystal_nn.get_nn_info(structure, 0)
voronoi_nn = VoronoiNN()
voronoi_neighbors = voronoi_nn.get_nn_info(structure, 0)
Coordination depends on the method, radii/oxidation information, weights, cutoffs, disorder, and geometry. Preserve:
Bound the number of sites and neighbors emitted. Cross-check model-sensitive conclusions with more than one justified definition.
An Entry contains a composition and a total energy:
from pymatgen.analysis.phase_diagram import PhaseDiagram
from pymatgen.entries.computed_entries import ComputedEntry
entries = [
ComputedEntry("Li", -1.0, entry_id="local-Li"),
ComputedEntry("O2", -2.0, entry_id="local-O2"),
ComputedEntry("Li2O", -4.0, entry_id="local-Li2O"),
]
diagram = PhaseDiagram(entries)
for entry in entries:
print(
entry.entry_id,
diagram.get_form_energy_per_atom(entry),
diagram.get_e_above_hull(entry),
)
ComputedEntry.energy is total eV for the represented composition, not
eV/atom. energy_per_atom, formation energy, and hull distance are normalized
values.
Before constructing a hull, verify that entries share a compatible:
Include elemental endpoints and all relevant competing phases. Missing phases can make unstable entries appear stable. Duplicate compositions are allowed as polymorphs only when their energies are comparable and provenance is distinct.
diagram.stable_entries means on the computed zero-temperature convex hull for
that exact entry set. It is not experimental stability or synthesizability.
from pymatgen.core import Composition
target = Composition("Li2O", strict=True)
decomposition = diagram.get_decomposition(target)
For an existing entry, use get_e_above_hull(entry). A bare composition has no
candidate energy, so it has a hull decomposition but no intrinsic energy above
hull.
from pymatgen.analysis.phase_diagram import PDPlotter
plotter = PDPlotter(diagram, show_unstable=0.2)
plotter.write_image("phase.new.svg", image_format="svg")
Plot to a new path, bound unstable points and output size, and preserve the machine-readable entry table. Plotting backends and image export can introduce optional dependencies.
ChemicalPotentialDiagram and PourbaixDiagram add assumptions beyond a
composition hull. Record reference states, open species, aqueous ion data,
concentrations, pH, electrochemical potential, temperature, corrections, and
solvent convention. Do not reuse a solid-state entry set as a valid aqueous
thermodynamic model without the required transformations and references.
from pymatgen.io.vasp import Vasprun
run = Vasprun(
"vasprun.xml",
parse_dos=False,
parse_eigen=True,
parse_projected_eigen=False,
parse_potcar_file=False,
)
bands = run.get_band_structure(line_mode=True)
gap = bands.get_band_gap()
vbm = bands.get_vbm()
cbm = bands.get_cbm()
metal = bands.is_metal()
Report:
A DFT band gap is method-dependent. Materials Project documents that its PBE band gaps are systematically underestimated.
BSPlotter can plot a BandStructureSymmLine; plotting does not validate the
k-path. High-symmetry paths depend on crystallographic setting and magnetic
primitive-cell assumptions.
from pymatgen.io.vasp import Vasprun
run = Vasprun(
"vasprun.xml",
parse_dos=True,
parse_eigen=False,
parse_projected_eigen=False,
parse_potcar_file=False,
)
dos = run.complete_dos
element_dos = dos.get_element_dos()
site_dos = dos.get_site_dos(run.final_structure[0])
orbital_dos = dos.get_spd_dos()
Check:
Do not compare integrated/projected DOS across calculations until these conventions match.
Vasprun(parse_projected_eigen=True) can require extreme time and memory.
BSVasprun is optimized for eigenvalue-focused band-structure parsing. Large
XML/HDF5/volumetric files need file-size, array-size, site/k-point/band, memory,
and wall-time bounds.
from pymatgen.analysis.diffraction.xrd import XRDCalculator
calculator = XRDCalculator(wavelength="CuKa")
pattern = calculator.get_pattern(
structure,
scaled=True,
two_theta_range=(5, 90),
)
for two_theta, intensity, hkls in zip(
pattern.x,
pattern.y,
pattern.hkls,
strict=True,
):
print(two_theta, intensity, hkls)
Peak positions/intensities depend on radiation, occupancies, structure, instrumental broadening, preferred orientation, temperature/displacement, and the ideal-powder model. A simulated pattern is not a phase-identification result by itself.
from pymatgen.core.surface import SlabGenerator
generator = SlabGenerator(
structure,
miller_index=(1, 1, 1),
min_slab_size=12.0,
min_vacuum_size=15.0,
center_slab=True,
in_unit_planes=False,
)
slabs = generator.get_slabs()
Record bulk parent, Miller-index convention, slab/vacuum units, termination, symmetrization, dipole correction, in-plane cell, fixed layers, and candidate limit. Slab thickness and vacuum are convergence parameters, not universal constants.
Current WulffShape takes parallel Miller-index and surface-energy sequences:
from pymatgen.analysis.wulff import WulffShape
wulff = WulffShape(
structure.lattice,
[(1, 0, 0), (1, 1, 0), (1, 1, 1)],
[1.0, 1.1, 0.9], # one consistent energy unit per area
)
Surface energies must share composition/chemical-potential, slab, functional, and area conventions. Report their unit explicitly.
AdsorbateSiteFinder produces geometric candidates, not adsorption energies or
preferred sites. Bound generated structures and preserve slab termination,
adsorbate geometry/charge/spin, coverage, orientation, and parent mapping.
pymatgen.analysis.elasticity represents strain, stress, and elastic tensors.
Verify Voigt index convention, stress sign, units (typically GPa for reported
moduli), reference frame, crystal symmetry, finite-strain magnitude, and fit
quality. Mechanical-stability criteria depend on crystal class and conditions.