示例#1
0
def site_symm(point, gen_pos, tol=1e-3, lattice=Euclidean_lattice):
    '''
    Given gen_pos (a list of SymmOps), return the list of symmetry operations
    leaving a point (coordinate or SymmOp) invariant.
    '''
    #Convert point into a SymmOp
    if type(point) != SymmOp:
        point = SymmOp.from_rotation_and_translation([[0,0,0],[0,0,0],[0,0,0]], point)
    symmetry = []
    for op in gen_pos:
        is_symmetry = True
        #Calculate the effect of applying op to point
        difference = SymmOp(point.affine_matrix - (op*point).affine_matrix)
        #Check that the rotation matrix is unaltered by op
        if not np.allclose(difference.rotation_matrix, np.zeros((3,3)), rtol = 1e-3, atol = 1e-3):
            is_symmetry = False
        #Check that the displacement is less than tol
        displacement = difference.translation_vector
        if distance(displacement, lattice) > tol:
            is_symmetry = False
        if is_symmetry:
            '''The actual site symmetry's translation vector may vary from op by
            a factor of +1 or -1 (especially when op contains +-1/2).
            We record this to distinguish between special Wyckoff positions.
            As an example, consider the point (-x+1/2,-x,x+1/2) in position 16c
            of space group Ia-3(206). The site symmetry includes the operations
            (-z+1,x-1/2,-y+1/2) and (y+1/2,-z+1/2,-x+1). These operations are
            not listed in the general position, but correspond to the operations
            (-z,x+1/2,-y+1/2) and (y+1/2,-z+1/2,-x), respectively, just shifted
            by (+1,-1,0) and (0,0,+1), respectively.
            '''
            el = SymmOp.from_rotation_and_translation(op.rotation_matrix, op.translation_vector + np.round(displacement))
            symmetry.append(el)
    return symmetry
示例#2
0
    def get_jmol2(self):
        from pymatgen.core.operations import SymmOp
        needs_shift = False
        structure = StructureP.from_file(
            BASE_DIR + self.entry.path.split('/var/www/materialsweb')[-1] +
            '/POSCAR')
        if structure.lattice.a == max(structure.lattice.abc):
            translation = SymmOp.from_rotation_and_translation(
                translation_vec=(structure.lattice.a / 2, 0, 0))
            for site in structure.sites:
                if site._frac_coords[0] > 0.9 or site._frac_coords[0] < 0.1:
                    needs_shift = True
            if needs_shift:
                structure.apply_operation(translation)
            structure.make_supercell([1, 6, 6])
        elif structure.lattice.b == max(structure.lattice.abc):
            translation = SymmOp.from_rotation_and_translation(
                translation_vec=(0, structure.lattice.b / 2, 0))
            for site in structure.sites:
                if site._coords[1] > 0.9 or site._coords[1] < 0.1:
                    needs_shift = True
            if needs_shift:
                structure.apply_operation(translation)
            structure.make_supercell([6, 1, 6])
        else:
            translation = SymmOp.from_rotation_and_translation(
                translation_vec=(0, 0, structure.lattice.c / 2))
            for site in structure.sites:
                if site._frac_coords[2] > 0.9 or site._frac_coords[2] < 0.1:
                    needs_shift = True
            if needs_shift:
                structure.apply_operation(translation)

            structure.make_supercell([6, 6, 1])
            print('frac_coord: ' + str(site._frac_coords[2]))

        print(structure.lattice.b)
        xyz_structure = [
            str(structure.num_sites), structure.composition.reduced_formula
        ]
        for site in structure.sites:
            element = site._species.reduced_formula.replace('2', '')
            atom = '{} {} {} {}'.format(element, str(site.x), str(site.y),
                                        str(site.z))
            xyz_structure.append(atom)
        #return '+'.join(xyz_structure)
        string = str(xyz_structure)
        string = string.replace('[', '')
        string = string.replace(']', '')
        string = string.replace(', ', r'\n')
        string = string.replace("'", "")
        return string
示例#3
0
    def combine_slabs(self):
        """
        Combine the slabs generated by get_oriented_slabs into interfaces
        """

        all_substrate_variants = []
        sub_labels = []
        for i, slab in enumerate(self.modified_substrate_structures):
            all_substrate_variants.append(slab)
            sub_labels.append(str(i))
            sg = SpacegroupAnalyzer(slab, symprec=1e-3)
            if not sg.is_laue():
                mirrored_slab = slab.copy()
                reflection_z = SymmOp.from_rotation_and_translation(
                    ((1, 0, 0), (0, 1, 0), (0, 0, -1)), (0, 0, 0))
                mirrored_slab.apply_operation(reflection_z, fractional=True)
                translation = [0, 0, -min(mirrored_slab.frac_coords[:, 2])]
                mirrored_slab.translate_sites(range(mirrored_slab.num_sites),
                                              translation)
                all_substrate_variants.append(mirrored_slab)
                sub_labels.append('%dm' % i)

        all_film_variants = []
        film_labels = []
        for i, slab in enumerate(self.modified_film_structures):
            all_film_variants.append(slab)
            film_labels.append(str(i))
            sg = SpacegroupAnalyzer(slab, symprec=1e-3)
            if not sg.is_laue():
                mirrored_slab = slab.copy()
                reflection_z = SymmOp.from_rotation_and_translation(
                    ((1, 0, 0), (0, 1, 0), (0, 0, -1)), (0, 0, 0))
                mirrored_slab.apply_operation(reflection_z, fractional=True)
                translation = [0, 0, -min(mirrored_slab.frac_coords[:, 2])]
                mirrored_slab.translate_sites(range(mirrored_slab.num_sites),
                                              translation)
                all_film_variants.append(mirrored_slab)
                film_labels.append('%dm' % i)

        # substrate first index, film second index
        self.interfaces = []
        self.interface_labels = []
        # self.interfaces = [[None for j in range(len(all_film_variants))] for i in range(len(all_substrate_variants))]
        for i, substrate in enumerate(all_substrate_variants):
            for j, film in enumerate(all_film_variants):
                self.interfaces.append(self.make_interface(substrate, film))
                self.interface_labels.append('%s/%s' %
                                             (film_labels[j], sub_labels[i]))
示例#4
0
 def transform_symmop(
         self, symmop: Union[SymmOp,
                             MagSymmOp]) -> Union[SymmOp, MagSymmOp]:
     """
     Takes a symmetry operation and transforms it.
     :param symmop: SymmOp or MagSymmOp
     :return:
     """
     W = symmop.rotation_matrix
     w = symmop.translation_vector
     Q = np.linalg.inv(self.P)
     W_ = np.matmul(np.matmul(Q, W), self.P)
     I = np.identity(3)
     w_ = np.matmul(Q, (w + np.matmul(W - I, self.p)))
     w_ = np.mod(w_, 1.0)
     if isinstance(symmop, MagSymmOp):
         return MagSymmOp.from_rotation_and_translation_and_time_reversal(
             rotation_matrix=W_,
             translation_vec=w_,
             time_reversal=symmop.time_reversal,
             tol=symmop.tol,
         )
     if isinstance(symmop, SymmOp):
         return SymmOp.from_rotation_and_translation(rotation_matrix=W_,
                                                     translation_vec=w_,
                                                     tol=symmop.tol)
     raise RuntimeError
示例#5
0
def parse_symmetry_operations(symmops_str_list):
    """
    Helper method to parse the symmetry operations.

    Args:
        symmops_str_list ([str]): List of symmops strings of the form
            ['x, y, z', '-x, -y, z', '-y+1/2, x+1/2, z+1/2', ...]

    Returns:
        List of SymmOps
    """
    ops = []
    for op_str in symmops_str_list:
        rot_matrix = np.zeros((3, 3))
        trans = np.zeros(3)
        toks = op_str.strip().split(",")
        for i, tok in enumerate(toks):
            for m in re.finditer("([\+\-]*)\s*([x-z\d]+)/*(\d*)", tok):
                factor = -1 if m.group(1) == "-" else 1
                if m.group(2) in ("x", "y", "z"):
                    j = ord(m.group(2)) - 120
                    rot_matrix[i, j] = factor
                else:
                    num = float(m.group(2))
                    if m.group(3) != "":
                        num /= float(m.group(3))
                    trans[i] = factor * num
        op = SymmOp.from_rotation_and_translation(rot_matrix, trans)
        ops.append(op)
    return ops
示例#6
0
 def rotate(self, matrix, tol=1e-5):
     matrix = SquareTensor(matrix)
     if not matrix.is_rotation(tol):
         raise ValueError("Rotation matrix is not valid.")
     sop = SymmOp.from_rotation_and_translation(matrix,
                                                [0., 0., 0.])
     return self.transform(sop)
示例#7
0
def parse_symmetry_operations(symmops_str_list):
    """
    Help method to parse the symmetry operations.

    Args:
        symmops_str_list:
            List of symmops strings of the form
            ['x, y, z', '-x, -y, z', '-y+1/2, x+1/2, z+1/2', ...]

    Returns:
        List of SymmOps
    """
    ops = []
    for op_str in symmops_str_list:
        rot_matrix = np.zeros((3, 3))
        trans = np.zeros(3)
        toks = op_str.strip().split(",")
        for i, tok in enumerate(toks):
            for m in re.finditer("([\+\-]*)\s*([x-z\d]+)/*(\d*)", tok):
                factor = -1 if m.group(1) == "-" else 1
                if m.group(2) in ("x", "y", "z"):
                    j = ord(m.group(2)) - 120
                    rot_matrix[i, j] = factor
                else:
                    num = float(m.group(2))
                    if m.group(3) != "":
                        num /= float(m.group(3))
                    trans[i] = factor * num
        op = SymmOp.from_rotation_and_translation(rot_matrix, trans)
        ops.append(op)
    return ops
示例#8
0
def align_axis(structure, axis='c', direction=(0, 0, 1)):
    """
    Rotates a structure so that the specified axis is along
    the [001] direction. This is useful for adding vacuum, and
    in general for using vasp compiled with no z-axis relaxation.

    Args:
        structure (Structure): Pymatgen Structure object to rotate.
        axis: Axis to be rotated. Can be 'a', 'b', 'c', or a 1x3 vector.
        direction (vector): Final axis to be rotated to.
    Returns:
        structure. Rotated to align axis along direction.
    """

    if axis == 'a':
        axis = structure.lattice._matrix[0]
    elif axis == 'b':
        axis = structure.lattice._matrix[1]
    elif axis == 'c':
        axis = structure.lattice._matrix[2]
    proj_axis = np.cross(axis, direction)
    if not(proj_axis[0] == 0 and proj_axis[1] == 0):
        theta = (
            np.arccos(np.dot(axis, direction)
            / (np.linalg.norm(axis) * np.linalg.norm(direction)))
        )
        R = get_rotation_matrix(proj_axis, theta)
        rotation = SymmOp.from_rotation_and_translation(rotation_matrix=R)
        structure.apply_operation(rotation)
    if axis == 'c' and direction == (0, 0, 1):
        structure.lattice._matrix[2][2] = abs(structure.lattice._matrix[2][2])

    return structure
示例#9
0
def align_axis(structure, axis='c', direction=(0, 0, 1)):
    """
    Rotates a structure so that the specified axis is along
    the [001] direction. This is useful for adding vacuum, and
    in general for using vasp compiled with no z-axis relaxation.

    Args:
        structure (Structure): Pymatgen Structure object to rotate.
        axis: Axis to be rotated. Can be 'a', 'b', 'c', or a 1x3 vector.
        direction (vector): Final axis to be rotated to.
    Returns:
        structure. Rotated to align axis along direction.
    """

    if axis == 'a':
        axis = structure.lattice._matrix[0]
    elif axis == 'b':
        axis = structure.lattice._matrix[1]
    elif axis == 'c':
        axis = structure.lattice._matrix[2]
    proj_axis = np.cross(axis, direction)
    if not (proj_axis[0] == 0 and proj_axis[1] == 0):
        theta = (np.arccos(
            np.dot(axis, direction) /
            (np.linalg.norm(axis) * np.linalg.norm(direction))))
        R = get_rotation_matrix(proj_axis, theta)
        rotation = SymmOp.from_rotation_and_translation(rotation_matrix=R)
        structure.apply_operation(rotation)
    if axis == 'c' and direction == (0, 0, 1):
        structure.lattice._matrix[2][2] = abs(structure.lattice._matrix[2][2])

    return structure
示例#10
0
文件: _lammps.py 项目: kcbhamu/maml
def get_lammps_lattice_and_rotation(structure: Structure, origin=(0, 0, 0)) \
        -> Tuple[np.ndarray, SymmOp, np.ndarray]:
    """
    Transform structure to lammps compatible structure. The lattice and rotation
    matrix are returned

    Args:
        structure (Structure): pymatgen structure
        origin (tuple): origin coordinates

    Returns: new lattice, rotation symmetry operator, rotation matrix

    """

    lattice = structure.lattice
    a, b, c = lattice.abc
    xlo, ylo, zlo = origin
    xhi = a + xlo
    m = lattice.matrix
    xy = np.dot(m[1], m[0] / a)
    yhi = np.sqrt(b**2 - xy**2) + ylo
    xz = np.dot(m[2], m[0] / a)
    yz = (np.dot(m[1], m[2]) - xy * xz) / (yhi - ylo)
    zhi = np.sqrt(c**2 - xz**2 - yz**2) + zlo
    # tilt = None if lattice.is_orthogonal else [xy, xz, yz]
    new_matrix = np.array([[xhi - xlo, 0, 0], [xy, yhi - ylo, 0],
                           [xz, yz, zhi - zlo]])
    rot_matrix = np.linalg.solve(new_matrix, m)
    symmop = SymmOp.from_rotation_and_translation(rot_matrix, origin)
    return new_matrix, symmop, rot_matrix
示例#11
0
def trilayer(doped = None):
    a = 5.43
    fcc = Lattice([[a/2,a/2,0],[a/2,0,a/2],[0,a/2,a/2]])
    trilayer = Structure(fcc,['Si']*2,[[0.00,0.00,0.00],[0.25,0.25,0.25]])
    
    # Make the cell cubic
    trilayer.make_supercell([[1,1,-1],[1,-1,1],[-1,1,1]])
    trilayer.make_supercell([[1,1,0],[1,-1,0],[0,0,4]])
    # Rotate the cell
    rt = 0.70710678118654746
    symmop = SymmOp.from_rotation_and_translation([[rt,rt,0],[rt,-rt,0],[0,0,1]])
    trilayer.apply_operation(symmop)
    
    if doped is not None:
        frac_coords = numpy.array([0.5,0.0,0.5])
        for i,atom in enumerate(trilayer):
            if numpy.linalg.norm(atom.frac_coords-frac_coords) < 0.001:
                trilayer.replace(i,doped,frac_coords)


    for z in [0.375,0.625]:
        for xy in [0.00,0.50]:
            trilayer.append('Mn',[xy,xy,z])

    return trilayer
def align_axis(structure, axis='c', direction=(0, 0, 1)):
    
    """
    Copied from MPInterfaces with some modification.
    Rotates a structure so that the specified axis is along
    the [001] direction. This is useful for adding vacuum, and
    in general for using vasp compiled with no z-axis relaxation.
        
    Parameters
    ----------
    structure (Structure): Pymatgen Structure object to rotate.
    axis: Axis to be rotated. Can be 'a', 'b', 'c', or a 1x3 vector.
    direction (vector): Final axis to be rotated to.
    
    Returns
    -------
    (Structure) Structure object rotated to align axis along direction.  
        
    """

    ## rotate the specified axis to be along the 001 direction
    if axis == 'a':
        axis = structure.lattice._matrix[0]
    elif axis == 'b':
        axis = structure.lattice._matrix[1]
    elif axis == 'c':
        axis = structure.lattice._matrix[2]
    rot_axis = np.cross(axis, direction)
    if not(rot_axis[0] == 0 and rot_axis[1] == 0):
        theta = (np.arccos(np.dot(axis, direction) / 
                 (np.linalg.norm(axis) * np.linalg.norm(direction))))
        R = get_rotation_matrix(rot_axis, theta)
        rotation = SymmOp.from_rotation_and_translation(rotation_matrix=R)
        structure.apply_operation(rotation,fractional=False)

    ## rotate such that the 001 direction lies along the 'c' axis
    axis = structure.lattice._matrix[2]  
    rot_axis = np.cross(direction, axis)
    if not(rot_axis[0] == 0 and rot_axis[1] == 0):
        theta = (np.arccos(np.dot(axis, direction) / 
                 (np.linalg.norm(axis) * np.linalg.norm(direction))))
        R = get_rotation_matrix(rot_axis, theta)
        rotation = SymmOp.from_rotation_and_translation(rotation_matrix=R)
        structure.apply_operation(rotation,fractional=True)
#    structure.lattice._matrix[2][2] = abs(structure.lattice._matrix[2][2])

    return structure
示例#13
0
def generate_elastic_workflow(structure, tags=None):
    """
    Generates a standard production workflow.

    Notes:
        Uses a primitive structure transformed into
        the conventional basis (for equivalent deformations).

        Adds the "minimal" category to the minimal portion
        of the workflow necessary to generate the elastic tensor,
        and the "minimal_full_stencil" category to the portion that
        includes all of the strain stencil, but is symmetrically complete
    """
    if tags == None:
        tags = []
    # transform the structure
    ieee_rot = Tensor.get_ieee_rotation(structure)
    if not SquareTensor(ieee_rot).is_rotation(tol=0.005):
        raise ValueError(
            "Rotation matrix does not satisfy rotation conditions")
    symm_op = SymmOp.from_rotation_and_translation(ieee_rot)
    ieee_structure = structure.copy()
    ieee_structure.apply_operation(symm_op)

    # construct workflow
    wf = wf_elastic_constant(ieee_structure)

    # Set categories, starting with optimization
    opt_fws = get_fws_and_tasks(wf, fw_name_constraint="optimization")
    wf.fws[opt_fws[0][0]].spec['elastic_category'] = "minimal"

    # find minimal set of fireworks using symmetry reduction
    fws_by_strain = {
        Strain(fw.tasks[-1]['pass_dict']['strain']): n
        for n, fw in enumerate(wf.fws) if 'deformation' in fw.name
    }
    unique_tensors = symmetry_reduce(list(fws_by_strain.keys()),
                                     ieee_structure)
    for unique_tensor in unique_tensors:
        fw_index = get_tkd_value(fws_by_strain, unique_tensor)
        if np.isclose(unique_tensor, 0.005).any():
            wf.fws[fw_index].spec['elastic_category'] = "minimal"
        else:
            wf.fws[fw_index].spec['elastic_category'] = "minimal_full_stencil"

    # Add tags
    if tags:
        wf = add_tags(wf, tags)

    wf = add_modify_incar(wf)
    priority = 500 - structure.num_sites
    wf = add_priority(wf, priority)
    for fw in wf.fws:
        if fw.spec.get('elastic_category') == 'minimal':
            fw.spec['_priority'] += 2000
        elif fw.spec.get('elastic_category') == 'minimal_full_stencil':
            fw.spec['_priority'] += 1000
    return wf
示例#14
0
    def apply_transformations(self, match):
        """
        Using ZSL match, transform all of the film_structures by the ZSL
        supercell transformation.

        Args:
            match (dict): ZSL match returned by ZSLGenerator.__call__
        """
        film_transformation = match["film_transformation"]
        sub_transformation = match["substrate_transformation"]

        modified_substrate_structures = [struct.copy() for struct in self.substrate_structures]
        modified_film_structures = [struct.copy() for struct in self.film_structures]

        # Match angles in lattices with 𝛾=θ° and 𝛾=(180-θ)°
        if np.isclose(180 - modified_film_structures[0].lattice.gamma, modified_substrate_structures[0].lattice.gamma,
                      atol=3):
            reflection = SymmOp.from_rotation_and_translation(((-1, 0, 0), (0, 1, 0), (0, 0, 1)), (0, 0, 1))
            for modified_film_structure in modified_film_structures:
                modified_film_structure.apply_operation(reflection, fractional=True)
            self.oriented_film.apply_operation(reflection, fractional=True)

        # ------------------------------------------------------------------------------------------------------------------------

        sub_scaling = np.diag(np.diag(sub_transformation))
        sub_shearing = np.dot(np.linalg.inv(sub_scaling), sub_transformation)

        # Turn into 3x3 Arrays
        sub_scaling = np.diag(np.append(np.diag(sub_scaling), 1))
        temp_matrix = np.diag([1, 1, 1])
        temp_matrix[:2, :2] = sub_transformation
        sub_shearing = temp_matrix

        for modified_substrate_structure in modified_substrate_structures:
            modified_substrate_structure = self.apply_transformation(modified_substrate_structure, temp_matrix)
            self.modified_substrate_structures.append(modified_substrate_structure)

        self.oriented_substrate = self.apply_transformation(self.oriented_substrate, temp_matrix)

        # ------------------------------------------------------------------------------------------------------------------------

        film_scaling = np.diag(np.diag(film_transformation))
        film_shearing = np.dot(np.linalg.inv(film_scaling), film_transformation)

        # Turn into 3x3 Arrays
        film_scaling = np.diag(np.append(np.diag(film_scaling), 1))
        temp_matrix = np.diag([1, 1, 1])
        temp_matrix[:2, :2] = film_transformation
        film_shearing = temp_matrix

        for modified_film_structure in modified_film_structures:
            modified_film_structure = self.apply_transformation(modified_film_structure, temp_matrix)
            self.modified_film_structures.append(modified_film_structure)
                               
        self.oriented_film = self.apply_transformation(self.oriented_film, temp_matrix)

        return
示例#15
0
def get_symmetry(mol, already_oriented=False):
    '''
    Return a list of SymmOps for a molecule's point symmetry
    already_oriented: whether or not the principle axes of mol are already reoriented 
    '''
    pga = PointGroupAnalyzer(mol)
    #Handle linear molecules
    if '*' in pga.sch_symbol:
        if already_oriented == False:
            #Reorient the molecule
            oriented_mol, P = reoriented_molecule(mol)
            pga = PointGroupAnalyzer(oriented_mol)
        pg = pga.get_pointgroup()
        symm_m = []
        for op in pg:
            symm_m.append(op)
        #Add 12-fold  and reflections in place of ininitesimal rotation
        for axis in [[1, 0, 0], [0, 1, 0], [0, 0, 1]]:
            op = SymmOp.from_rotation_and_translation(aa2matrix(axis, pi / 6),
                                                      [0, 0, 0])
            if pga.is_valid_op(op):
                symm_m.append(op)
                #Any molecule with infinitesimal symmetry is linear;
                #Thus, it possess mirror symmetry for any axis perpendicular
                #To the rotational axis. pymatgen does not add this symmetry
                #for all linear molecules - for example, hydrogen
                if axis == [1, 0, 0]:
                    symm_m.append(SymmOp.from_xyz_string('x,-y,z'))
                    symm_m.append(SymmOp.from_xyz_string('x,y,-z'))
                elif axis == [0, 1, 0]:
                    symm_m.append(SymmOp.from_xyz_string('-x,y,z'))
                    symm_m.append(SymmOp.from_xyz_string('x,y,-z'))
                elif axis == [0, 0, 1]:
                    symm_m.append(SymmOp.from_xyz_string('-x,y,z'))
                    symm_m.append(SymmOp.from_xyz_string('x,-y,z'))
                #Generate a full list of SymmOps for the molecule's pointgroup
                symm_m = generate_full_symmops(symm_m, 1e-3)
                break
        #Reorient the SymmOps into mol's original frame
        if not already_oriented:
            new = []
            for op in symm_m:
                new.append(P.inverse * op * P)
            return new
        elif already_oriented:
            return symm_m
    #Handle nonlinear molecules
    else:
        pg = pga.get_pointgroup()
        symm_m = []
        for op in pg:
            symm_m.append(op)
        return symm_m
示例#16
0
    def __init__(self, int_symbol):
        """
        Initializes a Point Group from its international symbol.

        Args:
            int_symbol (str): International or Hermann-Mauguin Symbol.
        """
        self.symbol = int_symbol
        self.generators = [get_symm_data("generator_matrices")[c]
                           for c in get_symm_data("point_group_encoding")[int_symbol]]
        self._symmetry_ops = set([SymmOp.from_rotation_and_translation(m)
                                  for m in self._generate_full_symmetry_ops()])
        self.order = len(self._symmetry_ops)
示例#17
0
文件: groups.py 项目: albalu/pymatgen
    def __init__(self, int_symbol):
        """
        Initializes a Point Group from its international symbol.

        Args:
            int_symbol (str): International or Hermann-Mauguin Symbol.
        """
        self.symbol = int_symbol
        self.generators = [get_symm_data("generator_matrices")[c]
                           for c in get_symm_data("point_group_encoding")[int_symbol]]
        self._symmetry_ops = set([SymmOp.from_rotation_and_translation(m)
                                  for m in self._generate_full_symmetry_ops()])
        self.order = len(self._symmetry_ops)
示例#18
0
    def __init__(self, int_symbol):
        """
        Initializes a Point Group from its international symbol.

        Args:
            int_symbol (str): International or Hermann-Mauguin Symbol.
        """
        self.symbol = int_symbol
        self.generators = [GENERATOR_MATRICES[c]
                           for c in POINT_GROUP_ENC[int_symbol]]
        self._symmetry_ops = set([SymmOp.from_rotation_and_translation(m)
                                  for m in self._generate_full_symmetry_ops()])
        self.order = len(self._symmetry_ops)
示例#19
0
def get_rot(slab):
    """
    Gets the transformation to rotate the z axis into the miller index
    """
    new_z = get_mi_vec(slab)
    a, b, c = slab.lattice.matrix
    new_x = a / np.linalg.norm(a)
    new_y = np.cross(new_z, new_x)
    x, y, z = np.eye(3)
    rot_matrix = np.array([np.dot(*el) for el in itertools.product([x, y, z], [new_x, new_y, new_z])]).reshape(3, 3)
    rot_matrix = np.transpose(rot_matrix)
    sop = SymmOp.from_rotation_and_translation(rot_matrix)
    return sop
def get_wyckoff_positions(sg):
    """find the wyckoff positions
    Args:
        sg: space group number (19)
    Return: a list containg the operation matrix sorted by multiplicity
    4a
        [Rot:
        [[ 1.  0.  0.]
        [ 0.  1.  0.]
        [ 0.  0.  1.]]
        tau
        [ 0.  0.  0.], 
        Rot:
        [[-1.  0.  0.]
         [ 0. -1.  0.]
         [ 0.  0.  1.]]
        tau
        [ 0.5  0.   0.5], 
        Rot:
        [[-1.  0.  0.]
         [ 0.  1.  0.]
         [ 0.  0. -1.]]
        tau
        [ 0.   0.5  0.5], 
        Rot:
        [[ 1.  0.  0.]
         [ 0. -1.  0.]
         [ 0.  0. -1.]]
        tau
        [ 0.5  0.5  0. ]]]
    """
    array = []
    hall_number = hall.hall_from_hm(sg)
    wyckoff_positions = make_sitesym.get_wyckoff_position_operators('database/Wyckoff.csv', hall_number)
    for x in wyckoff_positions:
    	temp = []
    	for y in x:
    	    temp.append(SymmOp.from_rotation_and_translation(list(y[0]), filter_site(y[1]/24)))
    	array.append(temp)
        
    i = 0
    wyckoffs_organized = [[]] #2D Array of Wyckoff positions organized by multiplicity
    old = len(array[0])
    for x in array:
        mult = len(x)
        if mult != old:
            wyckoffs_organized.append([])
            i += 1
            old = mult
        wyckoffs_organized[i].append(x)
    return wyckoffs_organized
示例#21
0
 def __init__(self, op):
     if type(op) == deepcopy(SymmOp):
         self.op = op
         self.tol = op.tol
         self.affine_matrix = op.affine_matrix
         self.m = op.rotation_matrix
         self.det = det(self.m)
     elif (type(op) == np.ndarray) or (type(op) == np.matrix):
         if op.shape == (3, 3):
             self.op = SymmOp.from_rotation_and_translation(op, [0, 0, 0])
             self.m = self.op.rotation_matrix
             self.det = det(op)
     else:
         print("Error: OperationAnalyzer requires a SymmOp or 3x3 array.")
     #If rotation matrix is not orthogonal
     if not is_orthogonal(self.m):
         self.type = "general"
         self.axis, self.angle, self.order, self.rotation_order = None, None, None, None
     #If rotation matrix is orthogonal
     else:
         #If determinant is positive
         if det(self.m) > 0:
             self.inverted = False
             self.axis, self.angle = matrix2aa(self.m)
             if isclose(self.angle, 0):
                 self.type = "identity"
                 self.order = int(1)
                 self.rotation_order = int(1)
             else:
                 self.type = "rotation"
                 self.order = OperationAnalyzer.get_order(self.angle)
                 self.rotation_order = self.order
         #If determinant is negative
         elif det(self.m) < 0:
             self.inverted = True
             mi = self.m * -1
             self.axis, self.angle = matrix2aa(mi)
             if isclose(self.angle, 0):
                 self.type = "inversion"
                 self.order = int(2)
                 self.rotation_order = int(1)
             else:
                 self.axis *= -1
                 self.type = "rotoinversion"
                 self.order = OperationAnalyzer.get_order(
                     self.angle, rotoinversion=True)
                 self.rotation_order = OperationAnalyzer.get_order(
                     self.angle, rotoinversion=False)
         elif det(self.m) == 0:
             self.type = "degenerate"
             self.axis, self.angle = None, None
示例#22
0
    def rotate(self, matrix, tol=1e-3):
        """
        Applies a rotation directly, and tests input matrix to ensure a valid
        rotation.

        Args:
            matrix (3x3 array-like): rotation matrix to be applied to tensor
            tol (float): tolerance for testing rotation matrix validity
        """
        matrix = SquareTensor(matrix)
        if not matrix.is_rotation(tol):
            raise ValueError("Rotation matrix is not valid.")
        sop = SymmOp.from_rotation_and_translation(matrix, [0., 0., 0.])
        return self.transform(sop)
示例#23
0
    def rotate(self, matrix, tol=1e-3):
        """
        Applies a rotation directly, and tests input matrix to ensure a valid
        rotation.

        Args:
            matrix (3x3 array-like): rotation matrix to be applied to tensor
            tol (float): tolerance for testing rotation matrix validity
        """
        matrix = SquareTensor(matrix)
        if not matrix.is_rotation(tol):
            raise ValueError("Rotation matrix is not valid.")
        sop = SymmOp.from_rotation_and_translation(matrix, [0.0, 0.0, 0.0])
        return self.transform(sop)
示例#24
0
    def _rotate_structure(self, structure, angle):
        copy_structure = copy.copy(structure)
        angle = angle * (np.pi / 180)
        operation = SymmOp.from_rotation_and_translation(
            rotation_matrix=np.array([
                [np.cos(angle), -np.sin(angle), 0],
                [np.sin(angle), np.cos(angle), 0],
                [0, 0, 1],
            ]),
            translation_vec=[0, 0, 0],
        )
        copy_structure.apply_operation(operation, fractional=False)

        return copy_structure
示例#25
0
 def reorient(mol):
     new_mol = mol.get_centered_molecule()
     A = get_inertia_tensor(new_mol)
     #Store the eigenvectors of the inertia tensor
     P = np.transpose(eigh(A)[1])
     if det(P) < 0:
         P[0] *= -1
     #reorient the molecule
     P = SymmOp.from_rotation_and_translation(P, [0, 0, 0])
     new_mol.apply_operation(P)
     #Our molecule should never be inverted during reorientation.
     if det(P.rotation_matrix) < 0:
         print("Error: inverted reorientation applied.")
     return new_mol, P
示例#26
0
def get_symmops(structure, symprec=defaults["symprec"]):
    """Returns fractional ops as the cartesian ones from pmg have issues."""
    from pymatgen.symmetry.analyzer import SpacegroupAnalyzer

    sga = SpacegroupAnalyzer(structure, symprec=symprec)

    # fractional rotation matrices from spglib need to be transposed so that the
    # operation is R.M
    return [
        SymmOp.from_rotation_and_translation(
            rotation_matrix=o.rotation_matrix.T,
            translation_vec=o.translation_vector)
        for o in sga.get_symmetry_operations(cartesian=False)
    ]
示例#27
0
def get_wyckoff_symmetry(sg, molecular=False):
    '''
    Returns a list of Wyckoff position site symmetry for a given space group.
    1st index: index of WP in sg (0 is the WP with largest multiplicity)
    2nd index: a point within the WP
    3rd index: a site symmetry SymmOp of the point
    molecular: whether or not to return the Euclidean point symmetry operations
        If True, cuts off translational part of operation, and converts non-orthogonal
        (3-fold and 6-fold rotation) operations to pure rotations
    '''
    P = SymmOp.from_rotation_and_translation(
        [[1, -.5, 0], [0, sqrt(3) / 2, 0], [0, 0, 1]], [0, 0, 0])
    symmetry_strings = eval(wyckoff_symmetry_df["0"][sg])
    symmetry = []
    convert = False
    if molecular is True:
        if sg >= 143 and sg <= 194:
            convert = True
    #Loop over Wyckoff positions
    for x in symmetry_strings:
        symmetry.append([])
        #Loop over points in WP
        for y in x:
            symmetry[-1].append([])
            #Loop over ops
            for z in y:
                op = SymmOp.from_xyz_string(z)
                if convert is True:
                    #Convert non-orthogonal trigonal/hexagonal operations
                    op = P * op * P.inverse
                if molecular is False:
                    symmetry[-1][-1].append(op)
                elif molecular is True:
                    op = SymmOp.from_rotation_and_translation(
                        op.rotation_matrix, [0, 0, 0])
                    symmetry[-1][-1].append(op)
    return symmetry
示例#28
0
def get_rot(slab):
    """
    Gets the transformation to rotate the z axis into the miller index
    """
    new_z = get_mi_vec(slab)
    a, b, c = slab.lattice.matrix
    new_x = a / np.linalg.norm(a)
    new_y = np.cross(new_z, new_x)
    x, y, z = np.eye(3)
    rot_matrix = np.array([np.dot(*el) for el in
                           itertools.product([x, y, z],
                                             [new_x, new_y, new_z])]).reshape(3, 3)
    rot_matrix = np.transpose(rot_matrix)
    sop = SymmOp.from_rotation_and_translation(rot_matrix)
    return sop
示例#29
0
    def __init__(self, int_symbol):
        """
        Initializes a Point Group from its international symbol.

        Args:
            int_symbol (str): International or Hermann-Mauguin Symbol.
        """
        self.symbol = int_symbol
        self.generators = [
            GENERATOR_MATRICES[c] for c in POINT_GROUP_ENC[int_symbol]
        ]
        self.symmetry_ops = [
            SymmOp.from_rotation_and_translation(m)
            for m in self._generate_full_symmetry_ops()
        ]
        self.order = len(self.symmetry_ops)
示例#30
0
 def get_point_group_operations(self, cartesian=False):
     """
     Return symmetry operations as a list of SymmOp objects.
     By default returns fractional coord symmops.
     But cartesian can be returned too.
     """
     (rotation, translation) = self._get_symmetry()
     symmops = []
     mat = self._structure.lattice.matrix.T
     invmat = np.linalg.inv(mat)
     for rot, trans in zip(rotation, translation):
         if cartesian:
             rot = np.dot(mat, np.dot(rot, invmat))
         op = SymmOp.from_rotation_and_translation(rot, np.array([0, 0, 0]))
         symmops.append(op)
     return symmops
示例#31
0
 def get_point_group_operations(self, cartesian=False):
     """
     Return symmetry operations as a list of SymmOp objects.
     By default returns fractional coord symmops.
     But cartesian can be returned too.
     """
     (rotation, translation) = self._get_symmetry()
     symmops = []
     mat = self._structure.lattice.matrix.T
     invmat = np.linalg.inv(mat)
     for rot, trans in zip(rotation, translation):
         if cartesian:
             rot = np.dot(mat, np.dot(rot, invmat))
         op = SymmOp.from_rotation_and_translation(rot, np.array([0, 0, 0]))
         symmops.append(op)
     return symmops
示例#32
0
    def get_op(self, angle="random"):
        """
        Generate a SymmOp object consistent with the orientation's
        constraints. Allows for specification of an angle (possibly random) to
        rotate about the constraint axis.

        Args:
            angle: an angle to rotate about the constraint axis. If "random",
                chooses a random rotation angle. If self.degrees==2, chooses a
                random 3d rotation matrix to multiply by. If the original matrix
                is wanted, set angle=0, or call self.matrix

        Returns:
            pymatgen.core.structure. SymmOp object
        """
        #If "random", rotates by a random amount
        m = self.get_matrix(angle=angle)
        return SymmOp.from_rotation_and_translation(m,[0,0,0])
示例#33
0
    def test_find_mapping(self):
        m = np.array([[0.1, 0.2, 0.3], [-0.1, 0.2, 0.7], [0.6, 0.9, 0.2]])
        latt = Lattice(m)

        op = SymmOp.from_origin_axis_angle([0, 0, 0], [2, 3, 3], 35)
        rot = op.rotation_matrix
        scale = np.array([[1, 1, 0], [0, 1, 0], [0, 0, 1]])

        latt2 = Lattice(np.dot(rot, np.dot(scale, m).T).T)
        (aligned_out, rot_out, scale_out) = latt2.find_mapping(latt)
        self.assertAlmostEqual(abs(np.linalg.det(rot)), 1)

        rotated = SymmOp.from_rotation_and_translation(rot_out).operate_multi(latt.matrix)

        self.assertArrayAlmostEqual(rotated, aligned_out.matrix)
        self.assertArrayAlmostEqual(np.dot(scale_out, latt2.matrix), aligned_out.matrix)
        self.assertArrayAlmostEqual(aligned_out.parameters, latt.parameters)
        self.assertFalse(np.allclose(aligned_out.parameters, latt2.parameters))
示例#34
0
    def __init__(self, int_symbol: str) -> None:
        """
        Initializes a Point Group from its international symbol.

        Args:
            int_symbol (str): International or Hermann-Mauguin Symbol.
        """
        from pymatgen.core.operations import SymmOp

        self.symbol = int_symbol
        self.generators = [
            _get_symm_data("generator_matrices")[c]
            for c in _get_symm_data("point_group_encoding")[int_symbol]
        ]
        self._symmetry_ops = {
            SymmOp.from_rotation_and_translation(m)
            for m in self._generate_full_symmetry_ops()
        }
        self.order = len(self._symmetry_ops)
示例#35
0
def project_point(point, op, lattice=Euclidean_lattice, PBC=[1,1,1]):
    """
    Given a 3-vector and a Wyckoff position operator, returns the projection of that
    point onto the axis, plane, or point.

    Args:
        point: a 3-vector (numeric list, tuple, or array)
        op: a SymmOp object representing a symmetry element within a symmetry group
        lattice: 3x3 matrix describing the unit cell vectors
        PBC: A periodic boundary condition list, where 1 means periodic, 0 means not periodic.
            Ex: [1,1,1] -> full 3d periodicity, [0,0,1] -> periodicity along the z axis

    Returns:
        a transformed 3-vector (numpy array)
    """
    if PBC == [0,0,0]:
        #Temporarily move the point in the opposite direction of the translation
        translation = op.translation_vector
        point -= translation
        new_vector = np.array([0.0,0.0,0.0])
        #Loop over basis vectors of the symmetry element
        for basis_vector in np.transpose(op.rotation_matrix):
            b = np.linalg.norm(basis_vector)
            if not np.isclose(b, 0):
                new_vector += basis_vector*(np.dot(point, basis_vector)/(b**2))
        new_vector += translation
        return new_vector
    else:
        #With PBC, the point could be projected onto multiple places on the symmetry element
        point = filtered_coords(point)
        #Generate translation vectors for the equivalent symmetry elements
        m = create_matrix(PBC=PBC)
        #Create new symmetry elements for each of the PBC vectors
        new_vectors = []
        distances = []
        for v in m:
            #Get the direct projection onto each of the new symmetry elements
            new_op = SymmOp.from_rotation_and_translation(op.rotation_matrix, op.translation_vector + v)
            new_vector = project_point(point, new_op, lattice=lattice, PBC=[0,0,0])
            new_vectors.append(new_vector)
            distances.append(distance(new_vector - point, lattice=lattice, PBC=[0,0,0]))
        i = np.argmin(distances)
        return filtered_coords(new_vectors[i], PBC=PBC)
示例#36
0
    def test_find_mapping(self):
        m = np.array([[0.1, 0.2, 0.3], [-0.1, 0.2, 0.7], [0.6, 0.9, 0.2]])
        latt = Lattice(m)

        op = SymmOp.from_origin_axis_angle([0, 0, 0], [2, 3, 3], 35)
        rot = op.rotation_matrix
        scale = np.array([[1, 1, 0], [0, 1, 0], [0, 0, 1]])

        latt2 = Lattice(np.dot(rot, np.dot(scale, m).T).T)
        (aligned_out, rot_out, scale_out) = latt2.find_mapping(latt)
        self.assertAlmostEqual(abs(np.linalg.det(rot)), 1)

        rotated = SymmOp.from_rotation_and_translation(rot_out).operate_multi(latt.matrix)

        self.assertArrayAlmostEqual(rotated, aligned_out.matrix)
        self.assertArrayAlmostEqual(np.dot(scale_out, latt2.matrix), aligned_out.matrix)
        self.assertArrayAlmostEqual(aligned_out.lengths_and_angles, latt.lengths_and_angles)
        self.assertFalse(np.allclose(aligned_out.lengths_and_angles,
                                     latt2.lengths_and_angles))
示例#37
0
def get_shared_symmetry_operations(struc, pointops, tol=0.1):
    """
        Get all the point group operations shared by a pair of atomic sites
        in the form [[point operations of site index 1],[],...,[]]

        Args:
            struc: Pymatgen structure
            pointops: list of point group operations from get_site_symmetries method

        Return:
            list of lists of shared point operations for each pair of atomic sites
    """
    numsites = len(struc)
    sharedops = [[0 for x in range(numsites)] for y in range(numsites)]
    for site1 in range(numsites):
        for site2 in range(numsites):
            sharedops[site1][site2] = []
            for op1 in range(len(pointops[site1])):
                for op2 in range(len(pointops[site2])):
                    if np.allclose(
                            pointops[site1][op1].rotation_matrix,
                            pointops[site2][op2].rotation_matrix,
                    ):
                        sharedops[site1][site2].append(pointops[site1][op1])

    for site1 in range(len(sharedops)):
        for site2 in range(len(sharedops[site1])):
            uniqueops = []
            for ops in range(len(sharedops[site1][site2])):
                op = SymmOp.from_rotation_and_translation(
                    rotation_matrix=sharedops[site1][site2]
                    [ops].rotation_matrix,
                    translation_vec=(0, 0, 0),
                    tol=tol,
                )
                if op in uniqueops:
                    continue
                else:
                    uniqueops.append(op)
            sharedops[site1][site2] = uniqueops

    return sharedops
示例#38
0
    def get_symmetry_operations(self, cartesian=False):
        """
        Return symmetry operations as a list of SymmOp objects.
        By default returns fractional coord symmops.
        But cartesian can be returned too.

        Returns:
            ([SymmOp]): List of symmetry operations.
        """
        rotation, translation = self._get_symmetry()
        symmops = []
        mat = self._structure.lattice.matrix.T
        invmat = np.linalg.inv(mat)
        for rot, trans in zip(rotation, translation):
            if cartesian:
                rot = np.dot(mat, np.dot(rot, invmat))
                trans = np.dot(trans, self._structure.lattice.matrix)
            op = SymmOp.from_rotation_and_translation(rot, trans)
            symmops.append(op)
        return symmops
示例#39
0
 def transform_symmop(self, symmop):
     # type: (Union[SymmOp, MagSymmOp]) -> Union[SymmOp, MagSymmOp]
     """
     Takes a symmetry operation and transforms it.
     :param symmop: SymmOp or MagSymmOp
     :return: 
     """
     W = symmop.rotation_matrix
     w = symmop.translation_vector
     Q = np.linalg.inv(self.P)
     W_ = np.matmul(np.matmul(Q, W), self.P)
     I = np.identity(3)
     w_ = np.matmul(Q, (w + np.matmul(W - I, self.p)))
     if isinstance(symmop, MagSymmOp):
         return MagSymmOp.from_rotation_and_translation_and_time_reversal(rotation_matrix=W_,
                                                                          translation_vec=w_,
                                                                          time_reversal=symmop.time_reversal,
                                                                          tol=symmop.tol)
     elif isinstance(symmop, SymmOp):
         return SymmOp.from_rotation_and_translation(rotation_matrix=W_, translation_vec=w_, tol=symmop.tol)
示例#40
0
    def get_symmetry_operations(self, cartesian=False):
        """
        Return symmetry operations as a list of SymmOp objects.
        By default returns fractional coord symmops.
        But cartesian can be returned too.

        Returns:
            ([SymmOp]): List of symmetry operations.
        """
        rotation, translation = self._get_symmetry()
        symmops = []
        mat = self._structure.lattice.matrix.T
        invmat = np.linalg.inv(mat)
        for rot, trans in zip(rotation, translation):
            if cartesian:
                rot = np.dot(mat, np.dot(rot, invmat))
                trans = np.dot(trans, self._structure.lattice.matrix)
            op = SymmOp.from_rotation_and_translation(rot, trans)
            symmops.append(op)
        return symmops
示例#41
0
def get_symmops(structure, symprec):
    """
    Helper function to get the symmetry operations of the structure
    in the reciprocal lattice fractional coordinates.

    Args:
            structure (pymatgen.core.structure.Structure)
            symprec (number): symmetry precision for pymatgen SpacegroupAnalyzer
    """

    sga = SpacegroupAnalyzer(structure, symprec * max(structure.lattice.abc))
    symmops = sga.get_symmetry_operations(cartesian=True)
    lattice = structure.lattice.matrix
    invlattice = structure.lattice.inv_matrix
    newops = []
    for op in symmops:
        newrot = np.dot(lattice, op.rotation_matrix)
        newrot = np.dot(newrot, invlattice)
        newtrans = np.dot(op.translation_vector, invlattice)
        newops.append(SymmOp.from_rotation_and_translation(newrot, newtrans))
    return newops
示例#42
0
    def get_point_group_operations(self, cartesian=False):
        """
        Return symmetry operations as a list of SymmOp objects.
        By default returns fractional coord symmops.
        But cartesian can be returned too.

        Args:
            cartesian (bool): Whether to return SymmOps as cartesian or
                direct coordinate operations.

        Returns:
            ([SymmOp]): List of point group symmetry operations.
        """
        rotation, translation = self._get_symmetry()
        symmops = []
        mat = self._structure.lattice.matrix.T
        invmat = np.linalg.inv(mat)
        for rot in rotation:
            if cartesian:
                rot = np.dot(mat, np.dot(rot, invmat))
            op = SymmOp.from_rotation_and_translation(rot, np.array([0, 0, 0]))
            symmops.append(op)
        return symmops
示例#43
0
    def get_point_group_operations(self, cartesian=False):
        """
        Return symmetry operations as a list of SymmOp objects.
        By default returns fractional coord symmops.
        But cartesian can be returned too.

        Args:
            cartesian (bool): Whether to return SymmOps as cartesian or
                direct coordinate operations.

        Returns:
            ([SymmOp]): List of point group symmetry operations.
        """
        rotation, translation = self._get_symmetry()
        symmops = []
        mat = self._structure.lattice.matrix.T
        invmat = np.linalg.inv(mat)
        for rot in rotation:
            if cartesian:
                rot = np.dot(mat, np.dot(rot, invmat))
            op = SymmOp.from_rotation_and_translation(rot, np.array([0, 0, 0]))
            symmops.append(op)
        return symmops
示例#44
0
def align_c_axis_along_001(structure):
    """
    Given a structure with a c-axis not along [001],
    returns the same structure rotated so that the c-axis is along
    the [001] direction. This is useful for vasp compiled with no
    z-axis relaxation.

    Args:
        structure (structure): Pymatgen Structure object to rotate.

    Returns:
        structure. Rotated to align c-axis along [001].
    """

    c = structure.lattice._matrix[2]
    z = [0, 0, 1]
    axis = np.cross(c, z)
    if not(axis[0] == 0 and axis[1] == 0):
        theta = (np.arccos(np.dot(c, z) /
                 (np.linalg.norm(c) * np.linalg.norm(z))))
        R = get_rotation_matrix(axis, theta)
        rotation = SymmOp.from_rotation_and_translation(rotation_matrix=R)
        structure.apply_operation(rotation)
    return structure
示例#45
0
def add_vacuum(delta, cut=0.9):
    """
    Adds vacuum to a POSCAR.

    Args:
        delta (float): vacuum thickness in Angstroms
        cut (delta): fractional height above which atoms will
            need to be fixed. Defaults to 0.9.
    """

    # Fix the POSCAR to put bottom atoms (even if they are above the
    # current vacuum layer) at 0.0.

    structure = Structure.from_file('POSCAR')
    n_sites = structure.num_sites
    poscar_lines = open('POSCAR').readlines()
    with open('POSCAR', 'w') as poscar:
        for line in poscar_lines[:8]:
            poscar.write(line)
        for line in poscar_lines[8:8+n_sites]:
            split_line = line.split()
            if float(split_line[2]) > cut:
                new_line = ' '.join([split_line[0], split_line[1],
                            str(float(split_line[2]) - 1.0)])
            else:
                new_line = ' '.join(split_line)
            poscar.write(new_line + '\n')

    min_z = 1
    for site in structure.sites:
        if site._fcoords[2] > cut:
            height = site._fcoords[2] - 1
        else:
            height = site._fcoords[2]
        if height < min_z:
            min_z = height

    translation = SymmOp.from_rotation_and_translation(
        translation_vec=(0, 0, -min_z))
    structure.apply_operation(translation, fractional=True)
    structure.to('POSCAR', 'POSCAR')
    with open('POSCAR', 'r') as poscar:
        poscar_lines = poscar.readlines()
    atom_lines = []
    for i in range(8, 8+n_sites):
        atom_lines.append(poscar_lines[i].split())
    atom_line_2s = []
    for atom_line in atom_lines:
        atom_line_2s.append(float(atom_line[2]))
    fixable = False
    addables = []
    for atom_line_2 in atom_line_2s:
        if float(atom_line_2) > cut or\
                (float(atom_line_2) < 0.0 and 1.0 + float(atom_line_2) > cut):
            if float(atom_line_2) < 0.0 and 1.0 + float(atom_line_2) > cut:
                atom_line_2 = float(atom_line_2) + 1.0
            addables.append(atom_line_2)
            fixable = True
#    if fixable:
#        add_factor = 1.0 - min(addables)
#    else:
    add_factor = 0.0
    new_atom_lines = []
    for atom_line in atom_lines:
        new_atom_line_2 = str(float(atom_line[2]) + add_factor)
        if float(new_atom_line_2) >= 1.0:
            new_atom_line_2 = str(float(new_atom_line_2) - 1.0)
        new_atom_lines.append('{} {} {}'.format(atom_line[0], atom_line[1],
                                                new_atom_line_2))
    with open('POSCAR', 'w') as poscar:
        for line in poscar_lines[0:8]:
            poscar.write(line)
        for new_atom_line in new_atom_lines:
            poscar.write('{}\n'.format(new_atom_line))

    # Open files and read in values from POSCAR
    old_poscar = open('POSCAR', 'r')
    new_poscar = open('new_POSCAR', 'w')
    oldlines = old_poscar.readlines()
    name = oldlines[0].split()[0]
    lattice_constant = oldlines[1].strip()
    a_lat_par = [float(x) for x in oldlines[2].split()]
    b_lat_par = [float(y) for y in oldlines[3].split()]
    c_lat_par = [abs(float(z)) for z in oldlines[4].split()]
    elements = oldlines[5].split()
    stoichiometry = oldlines[6].split()
    coordinate_type = oldlines[7].strip()

    # Elongate c-vector by delta

    save = float(c_lat_par[2])
    c_length = float(c_lat_par[2]) * float(lattice_constant)
    c_length_plus_delta = c_length + float(delta)
    c_lat_par[2] = c_length_plus_delta / float(lattice_constant)
    scalar = c_lat_par[2] / save

    # Create list of atom coordinates and adjust their z-coordinate on
    # the fly

    atoms = []
    for i in range(8, 8+n_sites):
        atom = oldlines[i].split()
        atom[2] = float(atom[2]) / scalar
        atoms.append(atom)

    # Write updated values to new_POSCAR, copy it to old_POSCAR, then
    # close files and delete new_POSCAR

    new_poscar.write('{}\n'.format(name))
    new_poscar.write('{}\n'.format(lattice_constant))
    for item in a_lat_par:
        new_poscar.write('{} '.format(item))
    new_poscar.write('\n')
    for item in b_lat_par:
        new_poscar.write('{} '.format(item))
    new_poscar.write('\n')
    for item in c_lat_par:
        new_poscar.write('{} '.format(item))
    new_poscar.write('\n')
    for item in elements:
        new_poscar.write('{} '.format(item))
    new_poscar.write('\n')
    for item in stoichiometry:
        new_poscar.write('{} '.format(item))
    new_poscar.write('\n')
    new_poscar.write('{}\n'.format(coordinate_type))
    for item in atoms:
        new_poscar.write('{} {} {}\n'.format(item[0], item[1], item[2]))

    new_poscar.close()
    os.remove('POSCAR')

    new_lines = open('new_POSCAR').readlines()
    with open('POSCAR', 'w') as poscar:
        for line in new_lines:
            poscar.write(line)
    old_poscar.close()
    os.remove('new_POSCAR')
示例#46
0
文件: cif.py 项目: shyamd/pymatgen
    def __init__(self, struct, symprec=None):
        format_str = "{:.8f}"

        block = OrderedDict()
        loops = []
        spacegroup = ("P 1", 1)
        if symprec is not None:
            sf = SpacegroupAnalyzer(struct, symprec)
            spacegroup = (sf.get_space_group_symbol(),
                          sf.get_space_group_number())
            # Needs the refined struture when using symprec. This converts
            # primitive to conventional structures, the standard for CIF.
            struct = sf.get_refined_structure()

        latt = struct.lattice
        comp = struct.composition
        no_oxi_comp = comp.element_composition
        block["_symmetry_space_group_name_H-M"] = spacegroup[0]
        for cell_attr in ['a', 'b', 'c']:
            block["_cell_length_" + cell_attr] = format_str.format(
                getattr(latt, cell_attr))
        for cell_attr in ['alpha', 'beta', 'gamma']:
            block["_cell_angle_" + cell_attr] = format_str.format(
                getattr(latt, cell_attr))
        block["_symmetry_Int_Tables_number"] = spacegroup[1]
        block["_chemical_formula_structural"] = no_oxi_comp.reduced_formula
        block["_chemical_formula_sum"] = no_oxi_comp.formula
        block["_cell_volume"] = latt.volume.__str__()

        reduced_comp, fu = no_oxi_comp.get_reduced_composition_and_factor()
        block["_cell_formula_units_Z"] = str(int(fu))

        if symprec is None:
            block["_symmetry_equiv_pos_site_id"] = ["1"]
            block["_symmetry_equiv_pos_as_xyz"] = ["x, y, z"]
        else:
            sf = SpacegroupAnalyzer(struct, symprec)

            def round_symm_trans(i):

                for t in TRANSLATIONS.values():
                    if abs(i - t) < symprec:
                        return t
                if abs(i - round(i)) < symprec:
                    return 0
                raise ValueError("Invalid translation!")

            symmops = []
            for op in sf.get_symmetry_operations():
                v = op.translation_vector
                v = [round_symm_trans(i) for i in v]
                symmops.append(SymmOp.from_rotation_and_translation(
                    op.rotation_matrix, v))

            ops = [op.as_xyz_string() for op in symmops]
            block["_symmetry_equiv_pos_site_id"] = \
                ["%d" % i for i in range(1, len(ops) + 1)]
            block["_symmetry_equiv_pos_as_xyz"] = ops

        loops.append(["_symmetry_equiv_pos_site_id",
                      "_symmetry_equiv_pos_as_xyz"])

        contains_oxidation = True
        try:
            symbol_to_oxinum = OrderedDict([
                (el.__str__(), float(el.oxi_state))
                for el in sorted(comp.elements)])
        except AttributeError:
            symbol_to_oxinum = OrderedDict([(el.symbol, 0) for el in
                                            sorted(comp.elements)])
            contains_oxidation = False
        if contains_oxidation:
            block["_atom_type_symbol"] = symbol_to_oxinum.keys()
            block["_atom_type_oxidation_number"] = symbol_to_oxinum.values()
            loops.append(["_atom_type_symbol", "_atom_type_oxidation_number"])

        atom_site_type_symbol = []
        atom_site_symmetry_multiplicity = []
        atom_site_fract_x = []
        atom_site_fract_y = []
        atom_site_fract_z = []
        atom_site_label = []
        atom_site_occupancy = []
        count = 1
        if symprec is None:
            for site in struct:
                for sp, occu in site.species_and_occu.items():
                    atom_site_type_symbol.append(sp.__str__())
                    atom_site_symmetry_multiplicity.append("1")
                    atom_site_fract_x.append("{0:f}".format(site.a))
                    atom_site_fract_y.append("{0:f}".format(site.b))
                    atom_site_fract_z.append("{0:f}".format(site.c))
                    atom_site_label.append("{}{}".format(sp.symbol, count))
                    atom_site_occupancy.append(occu.__str__())
                    count += 1
        else:
            # The following just presents a deterministic ordering.
            unique_sites = [
                (sorted(sites, key=lambda s: tuple([abs(x) for x in
                                                   s.frac_coords]))[0],
                 len(sites))
                for sites in sf.get_symmetrized_structure().equivalent_sites
            ]
            for site, mult in sorted(
                    unique_sites,
                    key=lambda t: (t[0].species_and_occu.average_electroneg,
                                   -t[1], t[0].a, t[0].b, t[0].c)):
                for sp, occu in site.species_and_occu.items():
                    atom_site_type_symbol.append(sp.__str__())
                    atom_site_symmetry_multiplicity.append("%d" % mult)
                    atom_site_fract_x.append("{0:f}".format(site.a))
                    atom_site_fract_y.append("{0:f}".format(site.b))
                    atom_site_fract_z.append("{0:f}".format(site.c))
                    atom_site_label.append("{}{}".format(sp.symbol, count))
                    atom_site_occupancy.append(occu.__str__())
                    count += 1

        block["_atom_site_type_symbol"] = atom_site_type_symbol
        block["_atom_site_label"] = atom_site_label
        block["_atom_site_symmetry_multiplicity"] = \
            atom_site_symmetry_multiplicity
        block["_atom_site_fract_x"] = atom_site_fract_x
        block["_atom_site_fract_y"] = atom_site_fract_y
        block["_atom_site_fract_z"] = atom_site_fract_z
        block["_atom_site_occupancy"] = atom_site_occupancy
        loops.append(["_atom_site_type_symbol",
                      "_atom_site_label",
                      "_atom_site_symmetry_multiplicity",
                      "_atom_site_fract_x",
                      "_atom_site_fract_y",
                      "_atom_site_fract_z",
                      "_atom_site_occupancy"])
        d = OrderedDict()
        d[comp.reduced_formula] = CifBlock(block, loops, comp.reduced_formula)
        self._cf = CifFile(d)
示例#47
0
 def test_symmops(self):
     sg = SpaceGroup("Pnma")
     op = SymmOp.from_rotation_and_translation([[1, 0, 0], [0, -1, 0],
                                                [0, 0, -1]], [0.5, 0.5, 0.5])
     self.assertIn(op, sg.symmetry_ops)