Enumerate derivative structures with composition and site constraints#

This example shows how to specify a composition of derivative structures and restrict each site to be occupied by only allowed species.

Import modules#

[1]:
from pathlib import Path

import numpy as np
from pymatgen.core import Lattice, Structure
from pymatgen.core.periodic_table import DummySpecie

from dsenum import ZddStructureEnumerator
from dsenum.utils import write_cif
[2]:
from dsenum import __version__
print(f"dsenum {__version__}")
dsenum 0.3.16.dev19+gc2b1184.d20220615

Enumerate derivative structures with site constraints#

Here, we enumerate Rutile-like SnO\(_{2-x}\) derivative structures.

[3]:
def get_rutile_structure():
    # rutile structure taken from mp-856
    a = 4.832
    c = 3.243
    x_4f = 0.3066

    lattice = Lattice.from_parameters(a, a, c, 90, 90, 90)
    species = ["Sn", "Sn", "O", "O", "O", "O"]
    frac_coords = np.array([
        [0, 0, 0],                      # Sn(2a)
        [0.5, 0.5, 0.5],                # Sn(2a)
        [x_4f, x_4f, 0],                # O(4f)
        [1 - x_4f, 1 - x_4f, 0],        # O(4f)
        [0.5 - x_4f, 0.5 + x_4f, 0.5],  # O(4f)
        [0.5 + x_4f, 0.5 - x_4f, 0.5],  # O(4f)
    ])
    structure = Structure(lattice, species, frac_coords)
    return structure

base_structure = get_rutile_structure()
mapping_color_species = [DummySpecie("X"), "O", "Sn"]

# Only O sites are disordered.
base_site_constraints = [
    [2],  # 2a
    [2],  # 2a
    [0, 1],  # 4f
    [0, 1],  # 4f
    [0, 1],  # 4f
    [0, 1],  # 4f
]
[4]:
max_index = 4

# root = Path("./SnO2-x")
# root.mkdir(exist_ok=True)

for index in range(1, max_index + 1):
    se = ZddStructureEnumerator(
        base_structure,
        index=index,
        num_types=len(mapping_color_species),
        mapping_color_species=mapping_color_species,
        base_site_constraints=base_site_constraints,
        remove_superperiodic=True,
        remove_incomplete=False,
    )
    list_dstructs = se.generate()

    for i, dstruct in enumerate(list_dstructs):
        # remove void
        dstruct.remove_species([mapping_color_species[0]])

        # Save structure here
        # filename = root / f"SnO2-x_{index}_{i}.cif"
        # write_cif(filename, dstruct, refine_cell=True)

100%|██████████| 1/1 [00:00<00:00, 33.30it/s]
total: 6 (Time: 0.03666sec)
100%|██████████| 5/5 [00:00<00:00, 22.48it/s]
total: 132 (Time: 0.2258sec)
100%|██████████| 5/5 [00:00<00:00,  9.69it/s]
total: 1756 (Time: 0.5191sec)
100%|██████████| 17/17 [00:09<00:00,  1.81it/s]
total: 47827 (Time: 9.396sec)

Enumerate derivative structures with composition constraints#

Here, we enumerate oxygen-deficient derivative structures of SrTiO\(_{3-x}\) \((0 \leq x \leq 1)\) in perovskite prototype.

[5]:
def get_perovskite_structure():
    lattice = Lattice(3.945 * np.eye(3))
    species = ["Sr", "Ti", "O", "O", "O"]
    frac_coords = np.array(
        [[0, 0, 0], [0.5, 0.5, 0.5], [0.0, 0.5, 0.5], [0.5, 0.0, 0.5], [0.5, 0.5, 0.0]]
    )
    return Structure(lattice, species, frac_coords)

aristo = get_perovskite_structure()

# Remove cation sites that are nothing to do with oxygen-deficient ordering!
base_structure = aristo.copy()
base_structure.remove_species(["Sr", "Ti"])
# Later append Sr and Ti sites with `additional_species` and `additional_frac_coords`
additional_species = aristo.species[:2]
additional_frac_coords = aristo.frac_coords[:2]

mapping_color_species = [DummySpecie("X"), "O"]
base_site_constraints = []
[6]:
# root = Path("./SrTiO3-x")
# root.mkdir(exist_ok=True)

max_index = 6
counts = {}

for index in range(1, max_index + 1):
    # Enumerate possible compositions
    list_compositions = []
    for num_oxygen in range(2 * index, 3 * index + 1):
        num_vacancy = 3 * index - num_oxygen
        list_compositions.append([num_vacancy, num_oxygen])

    poscars = []
    for composition_constraints in list_compositions:
        zse = ZddStructureEnumerator(
            base_structure,
            index=index,
            num_types=len(mapping_color_species),
            mapping_color_species=mapping_color_species,
            composition_constraints=composition_constraints,
            remove_superperiodic=True,
            remove_incomplete=False,
            verbose=False,
        )
        list_dstructs = zse.generate(
            additional_species=additional_species, additional_frac_coords=additional_frac_coords,
            output='poscar',
        )
        poscars.extend(list_dstructs)
    counts[index] = len(poscars)
[7]:
assert counts[1] == 2
assert counts[2] == 11
assert counts[3] == 45
assert counts[4] == 455
assert counts[5] == 1296
assert counts[6] == 17111