Defining polyhedra recipes

A PolyhedraRecipe describes how to identify coordination polyhedra in a structure. This guide covers the different ways to select atoms and the available coordination methods.

All examples use TiOF2, which adopts the ReO3 structure with anion disorder. We want to find the TiX6 octahedra in a 2x2x2 supercell.

from pymatgen.io.vasp import Poscar
from polyhedral_analysis.configuration import Configuration
from polyhedral_analysis.polyhedra_recipe import PolyhedraRecipe

structure = Poscar.from_file('POSCAR').structure

Selecting atoms by species

The simplest approach is to pass species strings. A single string selects all atoms of that species; a list of strings selects atoms matching any of the listed species.

recipe = PolyhedraRecipe(
    method='distance cutoff',
    coordination_cutoff=3.0,
    central_atoms='Ti',
    vertex_atoms=['O', 'F'],
)

config = Configuration(structure=structure, recipes=[recipe])
config.polyhedra  # list of TiX6 polyhedra

Selecting atoms by index

You can pass explicit lists of integer site indices:

ti_indices = list(structure.indices_from_symbol('Ti'))
of_indices = (list(structure.indices_from_symbol('O'))
              + list(structure.indices_from_symbol('F')))

recipe = PolyhedraRecipe(
    method='distance cutoff',
    coordination_cutoff=3.0,
    central_atoms=ti_indices,
    vertex_atoms=of_indices,
)

This gives the same result but is useful when you need to select a specific subset of sites.

Selecting atoms with functions

For maximum flexibility, pass a callable that takes a pymatgen Structure and returns a sequence of site indices:

recipe = PolyhedraRecipe(
    method='distance cutoff',
    coordination_cutoff=3.0,
    central_atoms=lambda s: s.indices_from_symbol('Ti'),
    vertex_atoms=lambda s: (s.indices_from_symbol('O')
                            + s.indices_from_symbol('F')),
)

This is particularly useful for trajectory analysis where site indices may need to be recalculated for each frame. The helper function create_matching_site_generator() creates a generator that matches sites to a reference structure, which is useful when atom ordering may change between frames.

Distance cutoff method

Include all vertex atoms within a specified distance of each centre:

recipe = PolyhedraRecipe(
    method='distance cutoff',
    coordination_cutoff=3.0,
    central_atoms='Ti',
    vertex_atoms=['O', 'F'],
)

This is the most common method. The coordination_cutoff parameter is required.

Nearest neighbours method

Include the n nearest vertex atoms to each centre:

recipe = PolyhedraRecipe(
    method='nearest neighbours',
    n_neighbours=6,
    central_atoms='Ti',
    vertex_atoms=['O', 'F'],
)

The n_neighbours parameter is required. This guarantees a fixed coordination number for every polyhedron.

Closest centre method

Assign each vertex atom to whichever centre it is nearest to:

recipe = PolyhedraRecipe(
    method='closest centre',
    central_atoms='Ti',
    vertex_atoms=['O', 'F'],
)

Every vertex atom is assigned to exactly one polyhedron. This method does not require a cutoff or neighbour count, but the coordination number may vary between polyhedra.

Combining multiple recipes

Pass a list of recipes to Configuration to find different types of polyhedra in the same structure:

oct_recipe = PolyhedraRecipe(
    method='distance cutoff',
    coordination_cutoff=3.0,
    central_atoms='Ti',
    vertex_atoms=['O', 'F'],
    label='oct',
)
tet_recipe = PolyhedraRecipe(
    method='nearest neighbours',
    n_neighbours=4,
    central_atoms='Si',
    vertex_atoms='O',
    label='tet',
)

config = Configuration(
    structure=structure,
    recipes=[oct_recipe, tet_recipe],
)

The label parameter lets you distinguish polyhedra types when inspecting the results.