Пример #1
0
    def primitive(self) -> Structure:
        if self._primitive is None:
            primitive = \
                spglib.find_primitive(self.cell,
                                      symprec=self.symprec,
                                      angle_tolerance=self.angle_tolerance)
            if primitive is None:
                raise ViseSymmetryError(
                    "Spglib couldn't find the primitive cell. "
                    "Change the symprec and/or angle_tolerance.")
            else:
                # To manage spglib cyclic behavior, we need to run this again.
                second_primitive = cell_to_structure(
                    spglib.find_primitive(primitive,
                                          symprec=self.symprec,
                                          angle_tolerance=self.angle_tolerance)
                ).get_sorted_structure()
                primitive = cell_to_structure(primitive)

                if primitive != second_primitive:
                    if first_structure_is_primitive(primitive,
                                                    second_primitive):
                        self._primitive = primitive
                        self._second_primitive = second_primitive

                    else:
                        self._primitive = second_primitive
                        self._second_primitive = primitive
                else:
                    self._primitive = primitive

        return self._primitive
Пример #2
0
 def test_find_primitive(self):
     for fname in self._filenames:
         spgnum = int(fname.split('-')[1])
         cell = read_vasp("./data/%s" % fname)
         if 'distorted' in fname:
             dataset = get_symmetry_dataset(cell, symprec=1e-1)
             primitive = find_primitive(cell, symprec=1e-1)
         else:
             dataset = get_symmetry_dataset(cell, symprec=1e-5)
             primitive = find_primitive(cell, symprec=1e-5)
         spg_type = get_spacegroup_type(dataset['hall_number'])
         c = spg_type['international_short'][0]
         if c in ['A', 'B', 'C', 'I']:
             multiplicity = 2
         elif c == 'F':
             multiplicity = 4
         elif c == 'R':
             self.assertEqual(spg_type['choice'], 'H')
             if spg_type['choice'] == 'H':
                 multiplicity = 3
             else: # spg_type['choice'] == 'R'
                 multiplicity = 1
         else:
             multiplicity = 1
         self.assertEqual(len(dataset['std_types']),
                          len(primitive[2]) * multiplicity,
                          msg=("multi: %d, %s" % (multiplicity, fname)))
Пример #3
0
 def test_find_primitive(self):
     for fname in self._filenames:
         cell = read_vasp(fname)
         if 'distorted' in fname:
             dataset = get_symmetry_dataset(cell, symprec=1e-1)
             primitive = find_primitive(cell, symprec=1e-1)
         else:
             dataset = get_symmetry_dataset(cell, symprec=1e-5)
             primitive = find_primitive(cell, symprec=1e-5)
         spg_type = get_spacegroup_type(dataset['hall_number'])
         c = spg_type['international_short'][0]
         if c in ['A', 'B', 'C', 'I']:
             multiplicity = 2
         elif c == 'F':
             multiplicity = 4
         elif c == 'R':
             self.assertEqual(spg_type['choice'], 'H')
             if spg_type['choice'] == 'H':
                 multiplicity = 3
             else:  # spg_type['choice'] == 'R'
                 multiplicity = 1
         else:
             multiplicity = 1
         self.assertEqual(len(dataset['std_types']),
                          len(primitive[2]) * multiplicity,
                          msg=("multi: %d, %s" % (multiplicity, fname)))
Пример #4
0
def get_sym(cell, symprec=1e-5, print_atom=False, print_analysis=True):
    '''Giving a cell, return symmetry analysis'''

    # spglib only work with tuple
    cell = tuple(cell)

    #Space group info
    spg_label, spg_number = spglib.get_spacegroup(cell, symprec).split(' ')
    spg_number = spg_number.split("(")[1].split(")")[0]
    Schoenflies_label = spglib.get_spacegroup(cell, symprec,
                                              symbol_type=1).split(' ')[0]
    sym = spglib.get_symmetry(cell, symprec)
    rotations = sym['rotations']
    translations = sym['translations']
    equi_atoms = sym['equivalent_atoms']

    is_std = is_prim = False
    std_cell = spglib.refine_cell(cell, symprec)
    prim_cell = spglib.find_primitive(cell, symprec)
    if compare_cells(cell, std_cell): is_std = True
    if compare_cells(cell, prim_cell): is_prim = True

    atoms = utils.convert_atomtype(cell[2])
    if print_analysis == True:
        #Cell info
        std_cell = spglib.refine_cell(cell, symprec)
        prim_cell = spglib.find_primitive(cell, symprec)

        #Print
        misc.print_msg("Spacegroup  number           : %s" % (spg_number))
        misc.print_msg("Short International symbol   : %s" % (spg_label))
        misc.print_msg("Schoenflies symbol           : %s" %
                       (Schoenflies_label))
        if print_atom == True:
            misc.print_msg("Atoms list (No. - Sym - Symbol):")
            for i, atom in enumerate(atoms):
                misc.print_msg("%3d   %3d   %s" %
                               (i + 1, equi_atoms[i] + 1, atom))
            misc.print_msg("Irreducible atoms:")
            for i, index in enumerate(np.unique(equi_atoms)):
                coord = cell[1][index]
                misc.print_msg(
                    "%3d  %3s    %7f5 %7f5 %7f5" %
                    (i + 1, atoms[index], coord[0], coord[1], coord[2]))
        misc.print_msg("Number of irreducible atoms  : %d" %
                       (np.unique(equi_atoms).shape[0]))
        misc.print_msg("Standard cell                : %r" % (is_std))
        misc.print_msg("Primitive cell               : %r" % (is_prim))
    else:
        # Return an standard cell object with irreducible atoms
        irred_idx = np.unique(equi_atoms)
        lattice = cell[0]
        irred_coord = cell[1][irred_idx, :]
        irred_label = np.array(cell[2])[irred_idx]
        irred_cell = (lattice, irred_coord, irred_label)

        return irred_cell, int(spg_number), spg_label, rotations, translations
Пример #5
0
def find_primitive_cell(structure):
    """
    uses spglib find_primitive to find the primitive cell
    params: AiiDa structure data

    returns: list of new AiiDa structure data
    """
    # TODO: if refinced structure is the same as given structure
    # return the given structure (Is this good practise for prov?)
    from spglib import find_primitive
    from ase.atoms import Atoms
    symprec = 1e-7
    #print('old {}'.format(len(structure.sites)))
    ase_structure = structure.get_ase()
    lattice, scaled_positions, numbers = find_primitive(ase_structure,
                                                        symprec=symprec)
    new_structure_ase = Atoms(numbers,
                              scaled_positions=scaled_positions,
                              cell=lattice,
                              pbc=True)
    new_structure = StructureData(ase=new_structure_ase)
    #print('new {}'.format(len(new_structure.sites)))

    new_structure.label = structure.label + ' primitive'
    new_structure.description = structure.description + ' primitive cell'
    return new_structure
Пример #6
0
def cif2structure(filename, primitive=False, symprec=0.001):
    """
    Read a given file  as a cif file, convert it into a
    ase atoms object and finally into a pychemia
    structure

    :param filename: (str) Filename of the CIF file that will be read
    :param primitive: (boolean) if primitive cell should be returned
    :param symprec: (float) Desired precision for computing the primitive cell
    :return:
    """
    aseatoms = _ase.io.read(filename)
    if primitive and USE_SPGLIB:
        lattice, scaled_positions, numbers = spg.find_primitive(
            aseatoms, symprec)
        if lattice is not None and scaled_positions is not None and numbers is not None:
            fin_atoms = _ase.atoms.Atoms(cell=lattice,
                                         scaled_positions=scaled_positions,
                                         numbers=numbers,
                                         pbc=True)
        else:
            fin_atoms = aseatoms
    else:
        fin_atoms = aseatoms
    ret = ase2pychemia(fin_atoms)
    return ret
Пример #7
0
def get_primitive_cell(axis, atom_pos):
    import spglib
    import numpy as np
    L = np.mat(axis)
    pos = []
    atom_type = []
    atom_dic = {}
    type_dic = {}
    index = 0
    for line in atom_pos:
        pos.append(line[0:3])
        if not line[4] in atom_dic.keys():
            atom_dic[line[4]] = index
            type_dic[index] = [line[3], line[4]]
            index = index + 1
        atom_type.append(atom_dic[line[4]])
    D = np.mat(pos)
    Cell = (L, D, atom_type)
    prim_cell = spglib.find_primitive(Cell, symprec=2e-3)
    equ_atoms = spglib.get_symmetry_dataset(prim_cell,
                                            symprec=2e-3)['equivalent_atoms']
    prim_axis = prim_cell[0].tolist()
    prim_pos = prim_cell[1].tolist()
    prim_type = prim_cell[2].tolist()

    prim_atom_pos = []
    for i in range(len(prim_pos)):
        prim_atom_pos.append(prim_pos[i] + type_dic[prim_type[i]])

    sym = spglib.get_spacegroup(Cell, symprec=2e-3).split('(')[1].split(')')[0]

    [new_axis, new_pos, sym_typ] = axis_rotation(prim_axis, prim_atom_pos, sym)
    return [new_axis, new_pos, sym_typ]
Пример #8
0
def _except_main(types, coords, symprec):
    types = np.array(types, dtype=int)
    fracs = np.array(coords.pop('fracs'))
    lattice = np.array(coords.pop('lattice'))

    cell = (lattice, fracs, types)

    # check primitiveness
    # alas, SPGLIB's symmetry dataset does not give any reliable way to
    # check this.
    #
    # FIXME this should be checked sooner in RSP2, not after expensive relaxation
    prim = spglib.find_primitive(cell, symprec=symprec)
    if not prim:
        SpgError.throw()

    prim_lattice = prim[0]
    vol_ratio = abs(np.linalg.det(lattice) / np.linalg.det(prim_lattice))
    if abs(abs(vol_ratio) - 1) > 1e-4:
        return {"Err": "rsp2 requires the input to be a primitive cell"}

    ds = spglib.get_symmetry_dataset(cell, symprec=symprec)
    if not ds:
        SpgError.throw()

    # you can't JSON-serialize numpy types
    def un_numpy_ify(d):
        if isinstance(d, dict):
            return {k: un_numpy_ify(v) for (k, v) in d.items()}
        if isinstance(d, list): return [un_numpy_ify(x) for x in d]
        if hasattr(d, 'tolist'): return d.tolist()
        if isinstance(d, (float, int, str)): return d
        raise TypeError

    return {"Ok": un_numpy_ify(ds)}
Пример #9
0
def get_primitive_cell(atoms, tol=1e-8):
    """Atoms object interface with spglib primitive cell finder:
    https://atztogo.github.io/spglib/python-spglib.html#python-spglib

    Parameters:
    -----------
    atoms : object
        Atoms object to search for a primitive unit cell.
    tol : float
        Tolerance for floating point rounding errors.

    Returns:
    --------
    primitive cell : object
        The primitive unit cell returned by spglib if one is found.
    """
    lattice = atoms.cell
    positions = atoms.get_scaled_positions()
    numbers = atoms.get_atomic_numbers()

    cell = (lattice, positions, numbers)

    _lattice, _positions, _numbers = spglib.find_primitive(cell, symprec=tol)

    atoms = Gratoms(symbols=_numbers, cell=_lattice, pbc=atoms.pbc)
    atoms.set_scaled_positions(_positions)

    return atoms
Пример #10
0
def cell_to_prim(cell, symprec=1e-5):
    prim_cell = spglib.find_primitive(cell, symprec)
    if compare_cells(cell, prim_cell):
        print('Unit cell is already a primitive cell. Nothing changes')
        return cell
    else:
        print('Unit cell was transformed to a primitive cell')
        return prim_cell
Пример #11
0
def get_sym(cell, symprec=1e-5, print_atom=False, export_operator=False):

    #Space group info
    intl_label, number = spglib.get_spacegroup(cell, symprec).split(' ')
    number = number.split("(")[1].split(")")[0]
    Schoenflies_label = spglib.get_spacegroup(cell, symprec,
                                              symbol_type=1).split(' ')[0]
    sym = spglib.get_symmetry(cell, symprec)
    rotations = sym['rotations']
    translations = sym['translations']
    equi_atoms = sym['equivalent_atoms']

    is_std = is_prim = False
    std_cell = spglib.refine_cell(cell, symprec)
    prim_cell = spglib.find_primitive(cell, symprec)
    if compare_cells(cell, std_cell): is_std = True
    if compare_cells(cell, prim_cell): is_prim = True

    atoms = utils.convert_atomtype(cell[2])
    if export_operator == False:
        #Cell info
        std_cell = spglib.refine_cell(cell, symprec)
        prim_cell = spglib.find_primitive(cell, symprec)
        #Print
        misc.print_msg("Spacegroup  number           : %s" % (number))
        misc.print_msg("Short International symbol   : %s" % (intl_label))
        misc.print_msg("Schoenflies symbol           : %s" %
                       (Schoenflies_label))
        if print_atom == True:
            misc.print_msg("Atoms list (No. - Sym - Symbol):")
            for i, atom in enumerate(atoms):
                misc.print_msg("%3d   %3d   %s" %
                               (i + 1, equi_atoms[i] + 1, atom))
            misc.print_msg("Irreducible atoms:")
            for i, index in enumerate(np.unique(equi_atoms)):
                misc.print_msg("%3d  %3s    %7f5 %7f5 %7f5" %
                               (i + 1, atoms[index], cell[1][index][0],
                                cell[1][index][1], cell[1][index][2]))
        misc.print_msg("Number of irreducible atoms  : %d" %
                       (np.unique(equi_atoms).shape[0]))
        misc.print_msg("Standard cell                : %r" % (is_std))
        misc.print_msg("Primitive cell               : %r" % (is_prim))
        return is_std, is_prim
    else:
        return (number, intl_label), equi_atoms, rotations, translations
Пример #12
0
def to_primitive(structure):
    """Returns aiida StructureData with primitive cell"""
    from aiida.orm import StructureData
    cell, positions, numbers = spglib.find_primitive(structure.get_ase())
    ase_struct = Atoms(numbers,
                       scaled_positions=positions,
                       cell=cell,
                       pbc=True)
    return StructureData(ase=ase_struct)
Пример #13
0
def check_if_primitive(atoms: "ase.atoms.Atoms") -> None:
    """ Checks if input configuration is primitive via spglib.
    
    A warning is raised if not.

    """
    cell = (atoms.cell, atoms.get_scaled_positions(), atoms.numbers)
    lattice, scaled_positions, numbers = find_primitive(cell, symprec=1e-5)
    is_primitive = (np.abs(lattice - atoms.cell) < 1e-4).all()
    if not is_primitive:
        logger.warning("It seems that the structure {} is not primitive.".format(atoms))
        logger.warning("This might lead to unexpected results.")
Пример #14
0
def get_primitive_cell(cell, tolerance=1e-5):
    numbers = cell.numbers
    (prim_lattice,
     prim_positions,
     prim_numbers) = spglib.find_primitive(
         (cell.lattice.T, cell.get_points().T, numbers),
         symprec=tolerance)
    masses = cell.get_masses()
    prim_masses = _transfer_masses_by_numbers(prim_numbers, numbers, masses)
    return Cell(lattice=prim_lattice.T,
                points=prim_positions.T,
                numbers=prim_numbers,
                masses=prim_masses)
Пример #15
0
    def find_primitive_cell(self, symprec = 1e-3, angle_tolerance = 5):
        """
        Find the primitive cell of the structure.

        Returns:
            Primitive cell as a Structure object.
        """
        vectors, positions, atomic_numbers = spglib.find_primitive(self.as_tuple(), symprec = symprec, angle_tolerance = angle_tolerance)
        for i in range(len(positions)):
            for j in range(3):
                if fabs(positions[i][j] - 1) < 0.01:
                    positions[i][j] = 0
        return Structure(vectors, positions, atomic_numbers)
Пример #16
0
def cell_to_prim(cell, symprec=1e-5):
    '''Convert a cell to a primitive cell'''

    # spglib only work with tuple
    cell = tuple(cell)

    prim_cell = spglib.find_primitive(cell, symprec)
    if compare_cells(cell, prim_cell):
        print('Unit cell is already a primitive cell. Nothing changes')
        return cell
    else:
        print('Unit cell was transformed to a primitive cell')
        return prim_cell
Пример #17
0
    def find_primitive(self,
                       symprec: float = 1e-5,
                       angle_tolerance: float = -1) -> Union[Stru, None]:
        """Return a primitive cell

        :params symprec: distance tolerance in Cartesian coordinates to find crystal symmetry. Default: 1e-5
        :params angle_tolerance: tolerance of angle between basis vectors in degrees to be tolerated in the symmetry finding. Default: -1
        :return lattice, atomic scaled positions, and atomic numbersthat are symmetrized following space group type
        """

        import spglib
        newcell = spglib.find_primitive(self.spgcell, symprec, angle_tolerance)

        return self.modified_stru(newcell)
Пример #18
0
    def is_primitive(self, symprec=1e-5):
        """
        is_primitive_cell decide if a cell is primitive

        parameters:

        cell: Cell object
        prec: float, the precision to judge, default=1e-5

        return: bool
        """
        natoms = len(self.atoms)
        spg_cell = (self.lattice, self.positions, self.atoms)
        pnatoms = len(spglib.find_primitive(spg_cell, symprec)[2])
        return natoms == pnatoms
Пример #19
0
def find_primitive(cell, symprec=1e-5):
    """
    A primitive cell is searched in the input cell. When a primitive
    cell is found, an object of Atoms class of the primitive cell is
    returned. When not, None is returned.
    """
    lattice, positions, numbers = spglib.find_primitive(cell.totuple(),
                                                        symprec)
    if lattice is None:
        return None
    else:
        return Atoms(numbers=numbers,
                     scaled_positions=positions,
                     cell=lattice,
                     pbc=True)
Пример #20
0
def find_primitive_structure(struct):
    """Find the structure contained within the reduced cell

    | Args:
    |   struct (ase.Atoms): structure to find the reduced cell for.
    |
    | Returns:
    |   reduced_struct(ase.Atoms): the structure in the reduced cell.

    """
    params = (struct.cell, struct.get_scaled_positions(), struct.numbers)
    lattice, scaled_positions, numbers = find_primitive(params)
    reduced_struct = Atoms(cell=lattice, scaled_positions=scaled_positions,
                           numbers=numbers)
    return reduced_struct
Пример #21
0
    def find_primitive(self):
        """
        Find a primitive version of the unit cell.

        Returns:
            A primitive cell in the input cell is searched and returned
            as an Structure object. If no primitive cell is found, None is
            returned.
        """
        lattice, scaled_positions, numbers = spglib.find_primitive(
            self._cell, symprec=self._symprec)

        species = [self._unique_species[i - 1] for i in numbers]

        return Structure(lattice, species, scaled_positions,
                         to_unit_cell=True).get_reduced_structure()
Пример #22
0
def get_primitive_cell(atoms):
    """
    Get the primitive cell for spglib given an atoms object. 
    
    Parameters:
        atoms (ase.Atoms): atoms object.
        
    Returns:
        primitive (cell): spglib tuple for primitive cell.
    """

    cell = make_spglib_cell_from_atoms(atoms)
    primitive = spglib.find_primitive(cell, symprec=1e-10)
    if primitive is None:
        return cell
    return primitive
Пример #23
0
    def find_primitive(self):
        """
        Find a primitive version of the unit cell.

        Returns:
            A primitive cell in the input cell is searched and returned
            as an Structure object. If no primitive cell is found, None is
            returned.
        """
        lattice, scaled_positions, numbers = spglib.find_primitive(
            self._cell, symprec=self._symprec)

        species = [self._unique_species[i - 1] for i in numbers]

        return Structure(lattice, species, scaled_positions,
                         to_unit_cell=True).get_reduced_structure()
Пример #24
0
def get_primitive_unit_cell(directories: Directories, visualise=False):
    """
    Wrapper for reading CIF file, converting it to a primitive unit cell
    and returning it in data structure, along with lattice vectors

    :param directories: Structure, input and output strings
    :param visualise: Output structure as .xyz
    :return: unit_cell, lattice_vectors: Unit cell and lattice vectors
    """
    structure_name = directories.structure
    input_dir = directories.input
    output_dir = directories.output

    ase_input_data = ase.io.read(input_dir + "/" + structure_name + ".cif",
                                 store_tags=False)
    spg_input = ase_to_spglib(ase_input_data)
    print("Number of atoms in input", len(spg_input[2]))

    # Reduce to primitive with SPG
    #print("Find primitive of conventional structure")
    lattice, positions, numbers = spglib.find_primitive(spg_input,
                                                        symprec=1e-5)

    if visualise:
        spg_molecule = (lattice, positions, numbers)
        #spg_show_cell(lattice, positions, numbers)
        spg_write(output_dir + '/' + structure_name + '_primitive_cell.xyz',
                  spg_molecule,
                  pbc=(1, 1, 1))

    # Need lattice vectors column-wise, in np array
    lattice_vectors = np.zeros(shape=(3, 3))
    for i in range(0, 3):
        lattice_vectors[:, i] = lattice[i]

    # Need positions in angstrom, not fractional
    positions_ang = []
    for position in positions:
        positions_ang.append(np.matmul(lattice, position))

    # Need unit cell in my molecule format
    species = [an_to_symbol[an] for an in numbers]
    unit_cell = atoms.Atoms(species=species, positions=positions_ang)

    return unit_cell, lattice_vectors
Пример #25
0
def get_symmetry(unit_cell, base, atoms, verbose=True):
    """
    Symmetry analysis with spglib

    spglib must be installed
    """
    if _spglib_present:
        if verbose:
            print('#####################')
            print('# Symmetry Analysis #')
            print('#####################')

        atomic_number = []
        for i in range(len(atoms)):
            a = atoms[i]
            b = base[i]
            atomic_number.append(electronFF[a]['Z'])
            if verbose:
                print(
                    f'{i + 1}: {atomic_number[i]} = {2} : [{base[i][0]:.2f}, {base[i][1]:.2f}, {base[i][2]:.2f}]'
                )

        lattice = (unit_cell, base, atomic_number)
        spgroup = spglib.get_spacegroup(lattice)
        sym = spglib.get_symmetry(lattice)

        if verbose:
            print("  Spacegroup  is %s." % spgroup)
            print('  Crystal has {0} symmetry operation'.format(
                sym['rotations'].shape[0]))

        p_lattice, p_positions, p_numbers = spglib.find_primitive(lattice,
                                                                  symprec=1e-5)
        print("\n########################\n #Basis vectors of primitive Cell:")
        for i in range(3):
            print('[{0:.4f}, {1:.4f}, {2:.4f}]'.format(p_lattice[i][0],
                                                       p_lattice[i][1],
                                                       p_lattice[i][2]))

        print('There {0} atoms and {1} species in primitive unit cell:'.format(
            len(p_positions), p_numbers))
    else:
        print('spglib is not installed')

    return True
Пример #26
0
def find_primitive(structure, symprec, angle_tolerance):
    """compute the primitive cell for an AiiDA structure

    When computing symmetry, atomic sites with the same **Kind** are treated as
    symmetrically equivalent (rather than just the atomic elements).

    Parameters
    ----------
    structure: aiida.StructureData
    symprec: float
        Symmetry search tolerance in the unit of length.
    angle_tolerance: float or None
        Symmetry search tolerance in the unit of angle degrees.
        If the value is negative, an internally optimized routine
        is used to judge symmetry.

    Returns
    -------
    aiida.StructureData

    """
    from aiida.orm.nodes.data.structure import Site

    structure = convert_structure(structure, "aiida")

    cell, int2kind_map = prepare_for_spglib(structure)

    new_cell = spglib.find_primitive(
        cell,
        symprec=symprec,
        angle_tolerance=-1 if angle_tolerance is None else angle_tolerance,
    )
    if new_cell is None:
        raise ValueError("standardization of cell failed")

    new_structure = structure.clone()
    new_structure.clear_sites()
    new_structure.cell = new_cell[0].tolist()
    positions = frac_to_cartesian(new_structure.cell, new_cell[1])
    for position, eid in zip(positions, new_cell[2].tolist()):
        new_structure.append_site(
            Site(kind_name=int2kind_map[eid], position=position))

    return new_structure
Пример #27
0
    def primitive(self, symprec=1e-5):
        """
        primitive structure
        
        Arugments:
            symprec (symmetry tolerance): distance tolerance in Cartesian coordinates to find crystal symmetry 
        """
        cell = self.structure.formatting('cell')
        cell = (cell['lattice'], cell['positions'], cell['numbers'])
        newcell = spglib.find_primitive(cell, symprec=symprec)

        if newcell == None:
            raise StructureFactoryError('the search is filed')
        else:
            poscar = self.__toPOSCAR(newcell)

            self.structure.pop()  # delete old object
            self.structure = Structure().append(poscar)
            return self.structure
Пример #28
0
 def __init__(self, lattice_vectors, atom_positions, atom_types, hall=None):
     if not issubclass(atom_types.dtype.type, np.integer):
         _, atom_types = np.unique(atom_types, return_inverse=True)
     self.input = BrCell(lattice_vectors, atom_positions, atom_types)
     self.primitive = BrCell(*spglib.find_primitive(self.input.cell()))
     self.input_is_primitive = self.input.isapprox(self.primitive)
     if hall is None:
         # Relying on spglib to determine the symmetry of this crystal has
         # the disadvantage that it might introduce an axis rotation, so
         # that even if the input and primitive cells are equivalent the
         # *wrong* Hall symbol will be passed to brille. If the input is not
         # the primitive cell there might *still* be a rotation of axes, but
         # this needs to be investigated.
         self.spglib_dict = spglib.get_symmetry_dataset(self.input.cell())
         self.hall = self.spglib_dict['hall']
         self.spglib_used = True
     else:
         self.hall = hall  # no error checking
         self.spglib_used = False
Пример #29
0
 def primitive_atoms(self):
     """Get primitive atoms."""
     phonopy_atoms = (
         self._atoms.lattice_mat,
         self._atoms.frac_coords,
         self._atoms.atomic_numbers,
     )
     lattice, scaled_positions, numbers = spglib.find_primitive(
         phonopy_atoms, symprec=self._symprec)
     elements = self._atoms.elements
     el_dict = {}
     for i in elements:
         el_dict.setdefault(Specie(i).Z, i)
     prim_elements = [el_dict[i] for i in numbers]
     prim_atoms = Atoms(
         lattice_mat=lattice,
         elements=prim_elements,
         coords=scaled_positions,
         cartesian=False,
     )
     return prim_atoms
Пример #30
0
def find_primitive(cell, symprec=1e-5):
    """
    A primitive cell is searched in the input cell. When a primitive
    cell is found, an object of Atoms class of the primitive cell is
    returned. When not, None is returned.
    
    From phonopy/structure/symmetry.py
    """

    # return as is when spglib is not installed
    if not has_spglib:
        return cell

    lattice, positions, numbers = spglib.find_primitive(cell, symprec)
    if lattice is None:
        return cell
    else:
        return Atoms(numbers=numbers,
                     scaled_positions=positions,
                     cell=lattice,
                     pbc=True)
Пример #31
0
def cif2structure(filename, primitive=False, symprec=0.001):
    """
    Read a given file  as a cif file, convert it into a
    ase atoms object and finally into a pychemia
    structure

    :param filename: (str) Filename of the CIF file that will be read
    :param primitive: (boolean) if primitive cell should be returned
    :param symprec: (float) Desired precision for computing the primitive cell
    :return:
    """
    aseatoms = _ase.io.read(filename)
    if primitive and USE_SPGLIB:
        lattice, scaled_positions, numbers = spg.find_primitive(aseatoms, symprec)
        if lattice is not None and scaled_positions is not None and numbers is not None:
            fin_atoms = _ase.atoms.Atoms(cell=lattice, scaled_positions=scaled_positions, numbers=numbers, pbc=True)
        else:
            fin_atoms = aseatoms
    else:
        fin_atoms = aseatoms
    ret = ase2pychemia(fin_atoms)
    return ret
Пример #32
0
    def primitive(self, symprec=1e-2):
        """ 
        Returns a Crystal object in the primitive unit cell.
        
        Parameters
        ----------
        symprec : float, optional
            Symmetry-search distance tolerance in Cartesian coordinates [Angstroms].

        Returns
        -------
        primitive : Crystal
            Crystal with primitive cell. Even if the crystal already has a primitive
            cell, a new crystal is returned.

        Raises
        ------
        RuntimeError : If primitive cell could not be found.
        
        Notes
        -----
        Optional atomic properties (e.g magnetic moment) might be lost in the reduction.
        """
        search = find_primitive(self._spglib_cell(), symprec=symprec)
        if search is None:
            raise RuntimeError("Primitive cell could not be found.")

        lattice_vectors, scaled_positions, numbers = search
        atoms = [
            Atom(int(Z), coords=coords)
            for Z, coords in zip(numbers, scaled_positions)
        ]

        # Preserve whatever subclass this object already is
        # This is important because some properties can be extracted from
        # source files (e.g. PWSCF output files)
        return type(self)(unitcell=atoms,
                          lattice_vectors=lattice_vectors,
                          source=self.source)
Пример #33
0
def find_primitive(structure, symprec=1e-3, verbosity=0):
    """
    Finds the primitive unit cell of the crystal structure.

    Args:
        structure: :class:`simulation.Structure` object with a crystal structure.
        symprec: Float with the Cartesian distance tolerance.
        verbosity: Integer with the level of standard output verbosity.

    Returns: :class:`simulation.Structure` object with the primitive unit cell
        if successful, the input structure as is, otherwise.

    """
    _check_spglib_install()
    rev_lookup = dict(
        zip(structure.site_comp_indices, structure.site_compositions))
    cell = spglib.find_primitive(_structure_to_cell(structure),
                                 symprec=symprec)
    if not _check_spglib_success(
            cell, func='find_primitive', verbosity=verbosity):
        return structure
    _cell_to_structure(cell, structure, rev_lookup)
    return structure
Пример #34
0
 def get_primitive_cell(self):
     """
     get the primitve cell as a new mol object
     """
     assert self.spgcell != None
     new_spgcell = spglib.find_primitive(self.spgcell)
     if new_spgcell == None:
         logger.error("Search for primitive cell failed with symprec %f" %
                      self.symprec)
         return
     print(new_spgcell[0])
     print(new_spgcell[2])
     new_mol = molsys.mol()
     new_mol.set_natoms(len(new_spgcell[2]))
     new_mol.set_cell(new_spgcell[0])
     new_mol.set_xyz(new_mol.get_real_from_frac(new_spgcell[1]))
     new_mol.set_elems_number(new_spgcell[2])
     # now add the connectivity
     new_mol.detect_conn()
     # RS: we could do atomtyping ... but this would have to be a method of mol ...
     new_mol.set_atypes(["0"] * new_mol.get_natoms())
     new_mol.set_nofrags()
     return new_mol
Пример #35
0
    print("  rotation:")
    for x in rot:
        print("     [%2d %2d %2d]" % (x[0], x[1], x[2]))
    print("  translation:")
    print("     (%8.5f %8.5f %8.5f)" % (trans[0], trans[1], trans[2]))
print('')

print("[refine_cell]")
print(" Refine distorted rutile structure")
lattice, positions, numbers = spglib.refine_cell(rutile_dist, symprec=1e-1)
show_cell(lattice, positions, numbers)
print('')

print("[find_primitive]")
print(" Fine primitive distorted silicon structure")
lattice, positions, numbers = spglib.find_primitive(silicon_dist, symprec=1e-1)
show_cell(lattice, positions, numbers)
print('')

print("[standardize_cell]")
print(" Standardize distorted rutile structure:")
print(" (to_primitive=0 and no_idealize=0)")
lattice, positions, numbers = spglib.standardize_cell(rutile_dist,
                                                      to_primitive=0,
                                                      no_idealize=0,
                                                      symprec=1e-1)
show_cell(lattice, positions, numbers)
print('')

print("[standardize_cell]")
print(" Standardize distorted rutile structure:")
Пример #36
0
def analyze_QHA_run(Calc, Tmin=1, Tmax=1500, Tsteps=100):
    '''
    Run the QHA analysis procedure on the set of volume calculation Calc.
    This procedure produces an array with thermodynamic functions for
    all calculated volumes and given temperature range (the zero temperature is always included).
    
    Input
    =====
    
        Calc   - List of calculation data
        Tmin   - Minimum temperature of the scan (K)
        Tmax   - Maximum temperature of the scan (K)
        Tsteps - Number of temperature steps
        bdir   - base directory (subdirectories host and calculation are located below)
        
    Output
    ======
        
        qha  - array of N x Tsteps x #params containing resulting data:
               V, T, Etot, Fph, P*V, Cv, S, ... 
               for each calculation and each temperature step.
    '''
    phdos={}
    qha=[]
    
    for n,c in enumerate(Calc):
        PCMUL=len(c.get_atomic_numbers())/len(spglib.find_primitive(c)[2])
        # Read the calculated dos
        clc=c.calc.results
        phdos[n]=clc['phdos']
        #Etot=c.get_potential_energy()
        Etot=clc['etotal']*Rydberg

        # Pressure returned in kbar we need to change it to eV/A^3 to get p*V in eV
        # eV/A^3=160.2176487GPa
        # kbar=0.1 GPa
        # eV/A^3 = 1602.176487 kbar
        P=clc['pressure']/1602.176487
        #P=c.get_isotropic_pressure(c.get_stress())

        # Scan the temperatures at this volume 
        # Unit cell (primitive) volume in Bohr^3 => (A^3)
        #V=(calcQHA[idx][2]['A'])**3
        
        #V=clc['volume']*(Bohr**3)
        V=c.get_volume()/PCMUL
    
        # get the ndf from the normalization of dos
        dos=phdos[n]
        ndf=round(simps(dos[1],dos[0]))
        
        # frequencies/energies
        # QE outputs dos in cm^-1, let's convert to sane units 
        # Let's convert to energy to include the hbar
        nu=1e-3*cminv2meV*phdos[n][0]
        dos=phdos[n][1]
        
        # We need to cut the nu to positive range
        no=array([[o,g] for o,g in zip(nu,dos) if o>0 ])
        nu=no[:,0]
        dos=no[:,1]
    
        # correct the normalization for units, negative cut and numerical errors
        dos=dos/simps(dos,nu)
    
        # plot in meV
        #plot(1e-3*nu,dos,label=n);
        #legend()
        #show()
        
        # plot the integrand at 300K
        #T=300
        #plot(nu,dos*log(2*sinh(0.5*nu/(k_B*T))),label=idx)
        
        # Zero-point energy - $\hbar\omega/2$ for each degree of freedom integrated over $\omega$
        F0=ndf*simps(0.5*dos*nu,nu)
    
        # Put in special case for the T=0. Just ZPV energy.
        qhav=[[V,0,Etot,F0,0,0,0,0]]
        qha.append(qhav)
        print '# %s: V=%.2f A^3, Etot=%.3f eV, P=%6.1f GPa' % (n, V, Etot, P/GPa)
        for T in linspace(Tmin,Tmax,Tsteps):
            # Maradudin book formula - the only one important for thermal expansion
            # The result is in eV, temperature in K
            e=0.5*nu/(k_B*T)
            Fph=ndf*T*k_B*simps(dos*log(2*sinh(e)),nu)
            Cv=ndf*k_B*simps(e*e*dos/sinh(e)**2,nu)
            S=k_B*(simps(2*dos*e/(exp(2*e)-1),nu)-simps(dos*(1-exp(-2*e)),nu))
            # Alternative formula from QE
            Sqe=k_B*simps(dos*(e/tanh(e)-log(2*sinh(e))),nu)
            # Formulas lifted from the QHA code in QE - not correct with current units
            #q=0.5*a3*nu/T
            #E_int=simps(a1*dos*nu/tanh(q),nu)
            #S0=simps(dos*(q/tanh(q)-log(2*sinh(q))),nu)
            qhav.append([V, T, Etot, Fph, P*V, Cv, S, Sqe])
            #print " %5.2f  %12f  %12f  %12f" % (T, Cv, S, Sqe)
        
    return array(qha)
Пример #37
0
 def find_primitive(self, symprec=1e-5):
     new_spglib_cell = spg.find_primitive(self.spglib_cell, symprec=symprec)
     return self.get_new_structure(new_spglib_cell)
Пример #38
0
def write_cell_params(fh, a, p):
    '''
    Write the specification of the cell using a traditional A,B,C, 
    alpha, beta, gamma scheme. The symmetry and parameters are determined
    from the atoms (a) object. The atoms object is translated into a 
    primitive unit cell but *not* converted. This is just an internal procedure.
    If you wish to work with primitive unit cells in ASE, you need to make 
    a conversion yourself. The cell params are in angstrom.
    
    Input
    -----
        fh  file handle of the opened pw.in file
        a   atoms object
        p   parameters dictionary
        
    Output
    ------
        Primitive cell tuple of arrays: (lattice, atoms, atomic numbers)
    '''
    
    assert(p['use_symmetry'])
    
    # Get a spacegroup name and number for the a
    sg,sgn=spglib.get_spacegroup(a).split()
    # Extract the number
    sgn=int(sgn[1:-1])
    # Extract the lattice type
    ltyp=sg[0]
    
    # Find a primitive unit cell for the system
    # puc is a tuple of (lattice, atoms, atomic numbers)
    puc=spglib.find_primitive(a)
    cell=puc[0]
    apos=puc[1]
    anum=puc[2]
    icell=a.get_cell()
    A=norm(icell[0])
    B=norm(icell[1])
    C=norm(icell[2])

    # Select appropriate ibrav
    if sgn >= 195 :
        # Cubic lattice
        if   ltyp=='P':  
            p['ibrav']=1  # Primitive
            qepc=array([[1,0,0],[0,1,0],[0,0,1]])
        elif ltyp=='F':  
            p['ibrav']=2  # FCC
            qepc=array([[-1,0,1],[0,1,1],[-1,1,0]])/2.0
        elif ltyp=='I':  
            p['ibrav']=3  # BCC
            qepc=array([[1,1,1],[-1,1,1],[-1,-1,1]])/2.0
        else :
            print 'Impossible lattice symmetry! Contact the author!'
            raise NotImplementedError
        #a=sqrt(2)*norm(cell[0])
        qepc=A*qepc
        fh.write('      A = %f,\n' % (A,))
    elif sgn >= 143 :
        # Hexagonal and trigonal 
        if   ltyp=='P' :  
            p['ibrav']=4  # Primitive
            qepc=array([[1,0,0],[-1/2,sqrt(3)/2,0],[0,0,C/A]])
        elif ltyp=='R' :  
            p['ibrav']=5  # Trigonal rhombohedral
            raise NotImplementedError
        else :
            print 'Impossible lattice symmetry! Contact the author!'
            raise NotImplementedError
        qepc=A*qepc
        fh.write('      A = %f,\n' % (A,))
        fh.write('      C = %f,\n' % (C,))
    elif sgn >= 75 :
        raise NotImplementedError
    elif sgn ==1 :
        # P1 symmetry - no special primitive cell signal to the caller
        p['ibrav']=0
        return None
    else :
        raise NotImplementedError
    cp=Atoms(cell=puc[0], scaled_positions=puc[1], numbers=puc[2], pbc=True)
    qepc=Atoms(cell=qepc, 
        positions=cp.get_positions(), 
        numbers=cp.get_atomic_numbers(), pbc=True)
    return qepc.get_cell(), qepc.get_scaled_positions(), qepc.get_atomic_numbers()