Skill Tracer
Skills › Scientific Agent Skills › pymatgen › core_classes.md

core_classes.md

299 lines · skills/pymatgen/references/core_classes.md at 5f2bc03

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# Core classes: explicit chemistry, coordinates, and periodicity
2
3This reference targets the verified `pymatgen==2026.9.24` wrapper with
4`pymatgen-core==2026.9.23`. Core objects now ship from `pymatgen-core` but keep
5the public `pymatgen.core` namespace.
6

Core classes: explicit chemistry, coordinates, and periodicity

This reference targets the verified pymatgen==2026.9.24 wrapper with pymatgen-core==2026.9.23. Core objects now ship from pymatgen-core but keep the public pymatgen.core namespace.

Raw lines 1 to 6
7## Units and representation
8
9Pymatgen does not make every quantity "atomic units." Common contracts include:
11- lattice vectors and Cartesian coordinates: Å
12- lattice angles: degrees
13- structure volume: ų
14- density: g/cm³
15- composition weight: amu for the represented composition
16- electronic and entry energies: usually eV; phase-diagram normalized values:
17 eV/atom
19Read the specific method contract before combining quantities. Record units in
20every artifact.
22`Structure` is periodic and owns a `Lattice`; `Molecule` is non-periodic.
23Structure coordinates are fractional by default. Molecule coordinates are
24Cartesian. Never infer which object or coordinate mode the user intended.

Units and representation

Pymatgen does not make every quantity "atomic units." Common contracts include:

  • lattice vectors and Cartesian coordinates: Å
  • lattice angles: degrees
  • structure volume: ų
  • density: g/cm³
  • composition weight: amu for the represented composition
  • electronic and entry energies: usually eV; phase-diagram normalized values: eV/atom

Read the specific method contract before combining quantities. Record units in every artifact.

Structure is periodic and owns a Lattice; Molecule is non-periodic. Structure coordinates are fractional by default. Molecule coordinates are Cartesian. Never infer which object or coordinate mode the user intended.

Raw lines 7 to 25
26## Element and Species
28```python
29from pymatgen.core import DummySpecies, Element, Species
31iron = Element("Fe")
32silicon = Element.from_Z(14)
33oxygen = Element.from_name("oxygen")
34fe2 = Species("Fe", oxidation_state=2)
35vacancy_label = DummySpecies("X")
36```
38Important distinctions:
40- `Element.symbol` is the chemical symbol.
41- `Element.Z` is atomic number.
42- `Element.X` is Pauling electronegativity, not the symbol.
43- Elemental properties can be missing or uncertain; do not replace missing
44 values with zero.
45- `Species` adds oxidation state and optional properties. Oxidation state is
46 formal chemical annotation, not an automatically validated charge model.
47- A dummy species is a modeling label, not a physical atom.
49Current API documentation also exposes predicates and data such as
50`is_metal`, `is_noble_gas`, `atomic_mass`, oxidation-state sets, and electronic
51configuration. Check for `None`/missing values and retain property provenance.

Element and Species

from pymatgen.core import DummySpecies, Element, Species

iron = Element("Fe")
silicon = Element.from_Z(14)
oxygen = Element.from_name("oxygen")
fe2 = Species("Fe", oxidation_state=2)
vacancy_label = DummySpecies("X")

Important distinctions:

  • Element.symbol is the chemical symbol.
  • Element.Z is atomic number.
  • Element.X is Pauling electronegativity, not the symbol.
  • Elemental properties can be missing or uncertain; do not replace missing values with zero.
  • Species adds oxidation state and optional properties. Oxidation state is formal chemical annotation, not an automatically validated charge model.
  • A dummy species is a modeling label, not a physical atom.

Current API documentation also exposes predicates and data such as is_metal, is_noble_gas, atomic_mass, oxidation-state sets, and electronic configuration. Check for None/missing values and retain property provenance.

Raw lines 26 to 52
53## Composition
55Use strict parsing at external boundaries:
57```python
58from pymatgen.core import Composition
60composition = Composition("LiFePO4", strict=True)
61formula = composition.formula
62reduced = composition.reduced_formula
63chemical_system = composition.chemical_system
64mass_amu = float(composition.weight)
65```
67Construction from a mapping is explicit:
69```python
70composition = Composition({"Fe": 2, "O": 3}, strict=True)
71```
73Safety rules:
751. Bound formula length before parsing.
762. Reject duplicate JSON keys, non-finite values, and non-positive amounts in
77 external mappings.
783. Keep full and reduced formulas distinct. Reduction loses the integer scale.
794. A composition is not a structure, phase, oxidation-state assignment, or
80 proof that a compound exists.
815. `oxi_state_guesses()` is heuristic and can be combinatorial. Call it only
82 after explicit user approval and bound elements, formula size, runtime, and
83 returned guesses.
846. Do not mix `Element` and oxidized `Species` keys without intentionally
85 defining how charge decoration should behave.
87The bundled validator does not guess by default:
89```bash
90python scripts/composition_structure_validator.py composition "Fe2O3"
91python scripts/composition_structure_validator.py composition "Fe2O3" \
92 --guess-oxidation-states
93```

Composition

Use strict parsing at external boundaries:

from pymatgen.core import Composition

composition = Composition("LiFePO4", strict=True)
formula = composition.formula
reduced = composition.reduced_formula
chemical_system = composition.chemical_system
mass_amu = float(composition.weight)

Construction from a mapping is explicit:

composition = Composition({"Fe": 2, "O": 3}, strict=True)

Safety rules:

  1. Bound formula length before parsing.
  2. Reject duplicate JSON keys, non-finite values, and non-positive amounts in external mappings.
  3. Keep full and reduced formulas distinct. Reduction loses the integer scale.
  4. A composition is not a structure, phase, oxidation-state assignment, or proof that a compound exists.
  5. oxi_state_guesses() is heuristic and can be combinatorial. Call it only after explicit user approval and bound elements, formula size, runtime, and returned guesses.
  6. Do not mix Element and oxidized Species keys without intentionally defining how charge decoration should behave.

The bundled validator does not guess by default:

python scripts/composition_structure_validator.py composition "Fe2O3"
python scripts/composition_structure_validator.py composition "Fe2O3" \
  --guess-oxidation-states
Raw lines 53 to 94
Runs code python scripts/composition_structure_validator.py :90
95## Lattice
97```python
98from pymatgen.core import Lattice
100cubic = Lattice.cubic(5.64)
101triclinic = Lattice.from_parameters(
102 a=4.0,
103 b=5.0,
104 c=6.0,
105 alpha=80,
106 beta=90,
107 gamma=100,
109matrix_lattice = Lattice(
110 [
111 [4.0, 0.0, 0.0],
112 [0.5, 5.0, 0.0],
113 [0.2, 0.3, 6.0],
114 ],
115 pbc=(True, True, True),
117```
119The matrix rows are lattice vectors. Preserve:
121- matrix and `(a, b, c)`
122- `(alpha, beta, gamma)`
123- determinant/volume and handedness
124- periodic-boundary-condition tuple
125- whether the cell was reduced, standardized, strained, or transformed
127Niggli/LLL reduction and crystallographic standardization can change the cell
128basis and site coordinates without changing intended periodic geometry. They
129still produce new representations and require provenance.

Lattice

from pymatgen.core import Lattice

cubic = Lattice.cubic(5.64)
triclinic = Lattice.from_parameters(
    a=4.0,
    b=5.0,
    c=6.0,
    alpha=80,
    beta=90,
    gamma=100,
)
matrix_lattice = Lattice(
    [
        [4.0, 0.0, 0.0],
        [0.5, 5.0, 0.0],
        [0.2, 0.3, 6.0],
    ],
    pbc=(True, True, True),
)

The matrix rows are lattice vectors. Preserve:

  • matrix and (a, b, c)
  • (alpha, beta, gamma)
  • determinant/volume and handedness
  • periodic-boundary-condition tuple
  • whether the cell was reduced, standardized, strained, or transformed

Niggli/LLL reduction and crystallographic standardization can change the cell basis and site coordinates without changing intended periodic geometry. They still produce new representations and require provenance.

Raw lines 95 to 130
131## Structure and IStructure
133The verified constructor includes explicit safety-relevant switches:
135```python
136from pymatgen.core import Lattice, Structure
138structure = Structure(
139 lattice=Lattice.cubic(5.64),
140 species=["Na", "Cl"],
141 coords=[[0, 0, 0], [0.5, 0.5, 0.5]],
142 coords_are_cartesian=False,
143 validate_proximity=True,
144 to_unit_cell=False,
146```
148`Structure` is mutable. `IStructure` is immutable/hashable. Prefer:
150```python
151original = Structure.from_file("input.cif", primitive=False, sort=False)
152derived = original.copy()
153derived.make_supercell([2, 2, 2])
154```
156Do not mutate `original` in a provenance-sensitive workflow.

Structure and IStructure

The verified constructor includes explicit safety-relevant switches:

from pymatgen.core import Lattice, Structure

structure = Structure(
    lattice=Lattice.cubic(5.64),
    species=["Na", "Cl"],
    coords=[[0, 0, 0], [0.5, 0.5, 0.5]],
    coords_are_cartesian=False,
    validate_proximity=True,
    to_unit_cell=False,
)

Structure is mutable. IStructure is immutable/hashable. Prefer:

original = Structure.from_file("input.cif", primitive=False, sort=False)
derived = original.copy()
derived.make_supercell([2, 2, 2])

Do not mutate original in a provenance-sensitive workflow.

Raw lines 131 to 157
158### Disorder and occupancy
160Each periodic site's `species` is a composition-like mapping. An ordered site
161has one species with occupancy 1. A disordered site can contain multiple
162species and fractional occupancies.
164```python
165for index, site in enumerate(structure):
166 occupancy_sum = sum(float(value) for value in site.species.values())
167 print(index, site.species, occupancy_sum)
168```
170Before downstream analysis:
172- report `structure.is_ordered`
173- reject non-positive or overfull occupancy unless an explicitly documented
174 parser tolerance explains a tiny rounding deviation
175- preserve vacancy conventions and oxidation-state decoration
176- check whether the target method supports disorder
178Ordering a disordered structure changes the model and may create many
179candidates. It is never a format cleanup.

Disorder and occupancy

Each periodic site's species is a composition-like mapping. An ordered site has one species with occupancy 1. A disordered site can contain multiple species and fractional occupancies.

for index, site in enumerate(structure):
    occupancy_sum = sum(float(value) for value in site.species.values())
    print(index, site.species, occupancy_sum)

Before downstream analysis:

  • report structure.is_ordered
  • reject non-positive or overfull occupancy unless an explicitly documented parser tolerance explains a tiny rounding deviation
  • preserve vacancy conventions and oxidation-state decoration
  • check whether the target method supports disorder

Ordering a disordered structure changes the model and may create many candidates. It is never a format cleanup.

Raw lines 158 to 180
181### Coordinate safety
183`site.frac_coords` and `site.coords` are fractional and Cartesian,
184respectively. Fractional coordinates outside `[0, 1)` can be valid periodic
185images; wrapping them is a transformation, not an automatic fix.
187Record whether `to_unit_cell`, sorting, merging, primitive reduction, or
188standardization occurred. Check minimum periodic distances under a site-count
189bound; an all-pairs matrix is quadratic.
190The bundled distance checks exclude periodic images of the same site, so a
191one-site structure has a null pair distance. Check lattice self-image contacts
192separately when small cells are possible.

Coordinate safety

site.frac_coords and site.coords are fractional and Cartesian, respectively. Fractional coordinates outside [0, 1) can be valid periodic images; wrapping them is a transformation, not an automatic fix.

Record whether to_unit_cell, sorting, merging, primitive reduction, or standardization occurred. Check minimum periodic distances under a site-count bound; an all-pairs matrix is quadratic. The bundled distance checks exclude periodic images of the same site, so a one-site structure has a null pair distance. Check lattice self-image contacts separately when small cells are possible.

Raw lines 181 to 193
194### Oxidation states
196Oxidation states can be attached to species:
198```python
199decorated = structure.copy()
200decorated.add_oxidation_state_by_element({"Na": 1, "Cl": -1})
201```
203This mutates the copied structure. Preserve the undecorated parent, mapping,
204method, and any charge-balance assumptions. `add_oxidation_state_by_guess()` is
205heuristic; do not invoke it implicitly.

Oxidation states

Oxidation states can be attached to species:

decorated = structure.copy()
decorated.add_oxidation_state_by_element({"Na": 1, "Cl": -1})

This mutates the copied structure. Preserve the undecorated parent, mapping, method, and any charge-balance assumptions. add_oxidation_state_by_guess() is heuristic; do not invoke it implicitly.

Raw lines 194 to 206
207### Common methods
209Current public operations include:
211- `Structure.from_file(path, primitive=False, sort=False, merge_tol=0.0)`
212- `Structure.from_str(text, fmt=...)`
213- `structure.to(filename=..., fmt=...)`
214- `get_distance(i, j)` and bounded neighbor methods
215- `get_primitive_structure()`
216- `copy()`, `make_supercell()`, `apply_strain()`, and site editing
217- `interpolate()` for compatible endpoints
219Every operation has assumptions. Interpolation does not establish a physical
220path; primitive/standard cells can alter site order and properties.

Common methods

Current public operations include:

  • Structure.from_file(path, primitive=False, sort=False, merge_tol=0.0)
  • Structure.from_str(text, fmt=...)
  • structure.to(filename=..., fmt=...)
  • get_distance(i, j) and bounded neighbor methods
  • get_primitive_structure()
  • copy(), make_supercell(), apply_strain(), and site editing
  • interpolate() for compatible endpoints

Every operation has assumptions. Interpolation does not establish a physical path; primitive/standard cells can alter site order and properties.

Raw lines 207 to 221
222## Molecule and IMolecule
224```python
225from pymatgen.core import Molecule
227water = Molecule(
228 ["O", "H", "H"],
229 [[0.0, 0.0, 0.0], [0.758, 0.0, 0.504], [-0.758, 0.0, 0.504]],
230 charge=0,
231 spin_multiplicity=1,
233```
235Molecule coordinates are Cartesian Å. Record:
237- charge and spin multiplicity
238- atom order, labels, and site properties
239- coordinate origin/orientation
240- whether hydrogens, bond perception, centering, or geometry generation changed
241 the object
243File formats often omit charge, multiplicity, bonding, isotope, or atom-label
244semantics. `Molecule.from_file()` parsing success does not prove those fields
245were present or preserved.

Molecule and IMolecule

from pymatgen.core import Molecule

water = Molecule(
    ["O", "H", "H"],
    [[0.0, 0.0, 0.0], [0.758, 0.0, 0.504], [-0.758, 0.0, 0.504]],
    charge=0,
    spin_multiplicity=1,
)

Molecule coordinates are Cartesian Å. Record:

  • charge and spin multiplicity
  • atom order, labels, and site properties
  • coordinate origin/orientation
  • whether hydrogens, bond perception, centering, or geometry generation changed the object

File formats often omit charge, multiplicity, bonding, isotope, or atom-label semantics. Molecule.from_file() parsing success does not prove those fields were present or preserved.

Raw lines 222 to 246
247## Explicit JSON serialization
249Core objects expose `as_dict()` and `from_dict()`:
251```python
252import json
253from pymatgen.core import Structure
255payload = structure.as_dict()
256text = json.dumps(payload, allow_nan=False, sort_keys=True)
258decoded = json.loads(text)
259restored = Structure.from_dict(decoded)
260```
262For untrusted JSON:
2641. enforce byte, nesting, collection, and string limits
2652. reject duplicate keys and non-finite numbers
2663. validate the expected `Structure` schema
2674. call the specific class constructor
269Do not use pickle. Do not feed attacker-controlled MSON metadata to a general
270decoder that dynamically imports classes. JSON is only a syntax; schema
271validation is the trust boundary.
273In this release, even `Structure.from_dict()` decodes MSON-valued site
274properties through `PeriodicSite.from_dict()`. The example above is a trusted
275round trip. The bundled intake rejects nested `@...` metadata and duplicate
276keys before this constructor; supply ordinary JSON lists/numbers for properties
277such as magmoms rather than serialized arbitrary Python objects.

Explicit JSON serialization

Core objects expose as_dict() and from_dict():

import json
from pymatgen.core import Structure

payload = structure.as_dict()
text = json.dumps(payload, allow_nan=False, sort_keys=True)

decoded = json.loads(text)
restored = Structure.from_dict(decoded)

For untrusted JSON:

  1. enforce byte, nesting, collection, and string limits
  2. reject duplicate keys and non-finite numbers
  3. validate the expected Structure schema
  4. call the specific class constructor

Do not use pickle. Do not feed attacker-controlled MSON metadata to a general decoder that dynamically imports classes. JSON is only a syntax; schema validation is the trust boundary.

In this release, even Structure.from_dict() decodes MSON-valued site properties through PeriodicSite.from_dict(). The example above is a trusted round trip. The bundled intake rejects nested @... metadata and duplicate keys before this constructor; supply ordinary JSON lists/numbers for properties such as magmoms rather than serialized arbitrary Python objects.

Raw lines 247 to 278
279## Validation checklist
281- object kind (composition/molecule/periodic structure) is explicit
282- units and coordinate mode are explicit
283- lattice/PBC and charge/spin are recorded where applicable
284- all parser warnings are preserved
285- occupancy/disorder and oxidation states are reported
286- coordinates and lattice values are finite
287- minimum distances are checked under a bound
288- original is immutable or retained unchanged
289- output schema and maximum size are explicit
290- provenance links every derived object to its parent checksum

Validation checklist

  • object kind (composition/molecule/periodic structure) is explicit
  • units and coordinate mode are explicit
  • lattice/PBC and charge/spin are recorded where applicable
  • all parser warnings are preserved
  • occupancy/disorder and oxidation states are reported
  • coordinates and lattice values are finite
  • minimum distances are checked under a bound
  • original is immutable or retained unchanged
  • output schema and maximum size are explicit
  • provenance links every derived object to its parent checksum
Raw lines 279 to 291
292## Sources (verified 2026-09-30)
294- [pymatgen core API](https://pymatgen.org/pymatgen.core.html)
295- [pymatgen usage guide](https://pymatgen.org/usage.html)
296- [pymatgen-core 2026.9.23 package metadata](https://pypi.org/project/pymatgen-core/)
297- [pymatgen 2026.9.24 package metadata](https://pypi.org/project/pymatgen/)
298- [pymatgen-core source](https://github.com/materialsproject/pymatgen-core)
299- [pymatgen changelog](https://pymatgen.org/CHANGES.html)