Source code for asr.setup.reduce

import asr
from asr.core import command, atomsopt
import numpy as np
from ase.build import cut, niggli_reduce
from ase import Atoms


def check_one_symmetry(spos_ac, ft_c, a_ij, tol=1.e-7):
    """Check whether atoms satisfy one given symmetry operation."""
    a_a = np.zeros(len(spos_ac), int)
    for a_j in a_ij.values():
        spos_jc = spos_ac[a_j]
        for a in a_j:
            spos_c = spos_ac[a]
            sdiff_jc = spos_c - spos_jc - ft_c
            sdiff_jc -= sdiff_jc.round()
            indices = np.where(abs(sdiff_jc).max(1) < tol)[0]
            if len(indices) == 1:
                j = indices[0]
                a_a[a] = a_j[j]
            else:
                assert len(indices) == 0
                return

    return a_a


def check_if_supercell(spos_ac, Z_a):
    """Check if unit cell can be reduced."""
    a_ij = {}
    for a, Z in enumerate(Z_a):
        if Z in a_ij:
            a_ij[Z].append(a)
        else:
            a_ij[Z] = [a]

    a_j = a_ij[Z_a[0]]  # just pick the first species

    ftrans_sc = spos_ac[a_j[1:]] - spos_ac[a_j[0]]
    ftrans_sc -= np.rint(ftrans_sc)
    for ft_c in ftrans_sc:
        a_a = check_one_symmetry(spos_ac, ft_c, a_ij)
        if a_a is not None:
            return ft_c
        else:
            pass


sel = asr.Selector()
sel.version = sel.EQ(-1)
sel.name = sel.EQ('asr.setup.reduce')


@asr.migration(selector=sel)
def remove_initial_and_final_parameters(record):
    """Remove initial and final parameter. Fix result."""
    atomic_structures = record.parameters.atomic_structures
    atoms = atomic_structures[record.parameters.initial]
    record.parameters.atoms = atoms
    del record.parameters.initial

    final_atoms = atomic_structures[record.parameters.final]
    record.result = final_atoms
    del record.parameters.final
    return record


[docs]@command( 'asr.setup.reduce', ) @atomsopt(default='start.json') def main(atoms: Atoms) -> Atoms: """Reduce supercell and perform niggli reduction if possible.""" Z_a = atoms.get_atomic_numbers() spos_ac = atoms.get_scaled_positions() % 1.0 ft_c = check_if_supercell(spos_ac, Z_a) if ft_c is not None: cell_cv = atoms.get_cell() cell_cv /= cell_cv.lengths() atoms = cut(atoms, a=ft_c, b=cell_cv[1], c=cell_cv[2]) pbc = atoms.get_pbc() atoms.set_pbc(True) niggli_reduce(atoms) atoms.set_pbc(pbc) return atoms
if __name__ == '__main__': main.cli()