Source code for smact.builder

"""A collection of functions for building certain lattice types."""

from __future__ import annotations

import itertools
from typing import TYPE_CHECKING

from ase.spacegroup import crystal

if TYPE_CHECKING:
    from ase import Atoms

from smact.lattice import Lattice, Site


def _tile_oxidation_states(
    base_oxidation_states: list[list[int]],
    n_sites: int,
) -> list[list[int]]:
    """Tile the base unit-cell oxidation states to match the number of sites in an expanded cell."""
    n_base = len(base_oxidation_states)
    if n_sites == n_base:
        return base_oxidation_states
    if n_sites % n_base != 0:
        msg = f"Number of sites ({n_sites}) is not a multiple of the base oxidation states pattern ({n_base})"
        raise ValueError(msg)
    return list(itertools.islice(itertools.cycle(base_oxidation_states), n_sites))


[docs] def cubic_perovskite( species: list[str], cell_par: list[float] | None = None, repetitions: list[int] | None = None, oxidation_states: list[list[int]] | None = None, ) -> tuple[Lattice, Atoms]: """ Build a perovskite cell using the crystal function in ASE. Args: ---- species (list[str]): Element symbols cell_par (list): Six floats/ints specifying 3 unit cell lengths and 3 unit cell angles. repetitions (list): Three integers specifying the expansion of the cell in x,y,z directions. oxidation_states (list): Oxidation states per site in the unit cell basis. Defaults to ``[[2], [4], [-2], [-2], [-2]]`` for the standard ABX3 perovskite. Returns: ------- SMACT Lattice object of the unit cell, ASE crystal system of the unit cell. """ if repetitions is None: repetitions = [1, 1, 1] if cell_par is None: cell_par = [6, 6, 6, 90, 90, 90] system = crystal( (species), basis=[(0, 0, 0), (0.5, 0.5, 0.5), (0.5, 0.5, 0)], spacegroup=221, size=repetitions, cellpar=cell_par, ) if oxidation_states is None: oxidation_states = [[2]] + [[4]] + [[-2]] * 3 tiled_oxi = _tile_oxidation_states(oxidation_states, len(system)) sites_list = [Site(pos, ox) for pos, ox in zip(system.get_scaled_positions(), tiled_oxi, strict=True)] return Lattice(sites_list), system
[docs] def wurtzite( species: list[str], cell_par: list[float] | None = None, repetitions: list[int] | None = None, oxidation_states: list[list[int]] | None = None, ) -> tuple[Lattice, Atoms]: """ Build a wurtzite cell using the crystal function in ASE. Args: ---- species (list[str]): Element symbols cell_par (list): Six floats/ints specifying 3 unit cell lengths and 3 unit cell angles. repetitions (list): Three integers specifying the expansion of the cell in x,y,z directions. oxidation_states (list): Oxidation states per site in the unit cell basis. Defaults to ``[[2], [2], [-2], [-2]]`` for the standard AX wurtzite. Returns: ------- SMACT Lattice object of the unit cell, ASE crystal system of the unit cell. """ if repetitions is None: repetitions = [1, 1, 1] if cell_par is None: cell_par = [3, 3, 6, 90, 90, 120] system = crystal( (species), basis=[(2.0 / 3.0, 1.0 / 3.0, 0), (2.0 / 3.0, 1.0 / 3.0, 5.0 / 8.0)], spacegroup=186, size=repetitions, cellpar=cell_par, ) if oxidation_states is None: oxidation_states = [[2]] * 2 + [[-2]] * 2 tiled_oxi = _tile_oxidation_states(oxidation_states, len(system)) sites_list = [Site(pos, ox) for pos, ox in zip(system.get_scaled_positions(), tiled_oxi, strict=True)] return Lattice(sites_list), system