Пример #1
0
    def gen_atom_map(self, basis, vectol):

        images = self._images
        DG = self._distortion_group.matrices
        numIm = len(images)
        numAtoms = len(images[0].frac_coords)
        num_unstar = self._distortion_group.num_unstar

        a_map = np.zeros((len(DG), numIm, numAtoms, numAtoms))

        for i in range(len(DG)):
            for j in range(1, numIm - 1):
                atoms1 = images[j].frac_coords
                num1 = images[j].species

                for k in range(0, numAtoms):

                    t_coord = np.dot(DG[i].rotation_matrix, atoms1[k])
                    t_coord = (t_coord + DG[i].translation_vector) % 1.0

                    if i < num_unstar:
                        atoms2 = images[j].frac_coords
                        num2 = images[j].species
                    else:
                        atoms2 = images[numIm - 1 - j].frac_coords
                        num2 = images[numIm - 1 - j].species

                    for l in range(0, numAtoms):
                        if closewrapped(
                                t_coord, atoms2[l], vectol
                        ) and num1[k] == num2[l] and basis[k] == 1:
                            a_map[i, j, k, l] = 1

        return a_map
Пример #2
0
    def obtain_tmat(self, images, vectol, symprec, angle_tolerance):
        # -- Generate lattice with DG in input basis

        numIm = len(images)
        DG = self.matrices

        cp_pos = images[0].frac_coords
        cp_labels = images[0].species
        newimage = images[int(numIm / 2)].copy()

        for i in [int(numIm / 2), numIm - 1]:

            cp_pos = np.append(cp_pos, images[i].frac_coords, axis=0)
            cp_labels = np.append(cp_labels, images[i].species)

            newimage.remove_sites(range(len(newimage.species)))

        new_pos = [cp_pos[0]]
        new_labels = [cp_labels[0]]

        for j in range(len(cp_pos[:, 0])):
            atom = cp_pos[j]
            for i in range(len(DG)):
                t_coord = np.dot(atom, np.transpose(DG[i].rotation_matrix))
                t_coord = (t_coord + DG[i].translation_vector) % 1.0

                if not any([closewrapped(t_coord, m, vectol)
                            for m in new_pos]):
                    new_pos = np.append(new_pos, [t_coord], axis=0)
                    new_labels = np.append(new_labels, cp_labels[j])

        for k in range(len(new_labels)):
            newimage.append(new_labels[k], new_pos[k])

        dataset2 = SpacegroupAnalyzer(
            newimage, symprec=symprec,
            angle_tolerance=angle_tolerance).get_symmetry_dataset()
        return dataset2["transformation_matrix"], dataset2["origin_shift"]
Пример #3
0
    def from_images(
        cls,
        images: List,
        symprec: float,
        angle_tolerance: float,
        gentol: float,
        vectol: List[float],
        vectol2: List[float],
    ):

        dataset = cls.get_img_sym_data(images, symprec, angle_tolerance,
                                       gentol)

        # -- Finds H, the symmetry operations common for each image
        # H[0] is the list of rotations, H[1] is the list of translations

        numIm = len(images)

        H = [[], []]  # type: List[List]
        rotH = dataset[0]["rotations"]
        tranH = dataset[0]["translations"]

        for i in range(0, len(rotH)):
            add = True
            for data in dataset:
                found = False
                for j in range(0, len(data["rotations"])):
                    if np.allclose(
                            data["rotations"][j], rotH[i],
                            atol=gentol, rtol=0.0) and closewrapped(
                                data["translations"][j], tranH[i], vectol2):
                        found = True
                        break
                if not found:
                    add = False
                    break
            if add:
                H[0].append(rotH[i])
                H[1].append(tranH[i])

        # -- Finds A*, the starred symmetry operations that map all images to their opposite image
        # Astar[0] is the list of rotations, Astar[1] is the list of translations
        Astar = [[], []]  # type: List[List]
        rotA = dataset[int(numIm / 2)]["rotations"]
        tranA = dataset[int(numIm / 2)]["translations"]

        for i in range(0, len(rotA)):
            add = True
            for j in range(0, int(numIm / 2)):
                positions = images[j].frac_coords
                positions = np.dot(positions, np.transpose(rotA[i]))
                positions = positions + findtranslation(
                    images[int(numIm / 2)], rotA[i], tranA[i], gentol, vectol2,
                    symprec, angle_tolerance)

                newimage = images[j].copy()
                new_species = newimage.species
                for k in range(len(new_species)):
                    newimage.replace(k, new_species[k], positions[k])

                if not atomsequal(newimage, images[numIm - 1 - j], vectol):
                    add = False
                    break
            if add:
                Astar[0].append(rotA[i])
                Astar[1].append(tranA[i])

        # -- Finds the general distortion group with a direct product of H and A*
        # DG[0] is the list of rotations, DG[1] is the list of translations
        # The first len(H[0]) operations are unstarred operations; the rest are starred.
        DG = []
        for i in range(0, len(H[0])):
            DG.append(SymmOp.from_rotation_and_translation(H[0][i], H[1][i]))

        for i in range(0, len(H[0])):
            for j in range(0, len(Astar[0])):
                add = True
                testrot = np.dot(H[0][i], Astar[0][j])
                testtran = standardize(
                    np.dot(Astar[1][j], np.transpose(H[0][i])) + H[1][i],
                    gentol)
                for k in range(len(H[0]), len(DG)):
                    if np.allclose(testrot, DG[k].rotation_matrix,
                                   atol=gentol) and closewrapped(
                                       testtran, DG[k].translation_vector,
                                       vectol):
                        add = False
                        break
                if add:
                    DG.append(
                        SymmOp.from_rotation_and_translation(
                            testrot, testtran))

        return cls(matrices=DG, num_unstar=len(H[0]), img_sym_dataset=dataset)
Пример #4
0
def gen_perturb(path, irrep, io):

    images = path.images
    DG = path.distortion_group.matrices
    num_unstar = path.distortion_group.num_unstar
    numIm = len(images)

    irrep_tools = IrrepTools()

    # -- Generate starting basis
    atoms1 = images[0].frac_coords
    numAtoms = len(atoms1)
    basis = np.zeros(numAtoms)
    atoms2 = images[numIm - 1].frac_coords
    m_vec = np.dot(np.linalg.inv(images[0].lattice.matrix),
                   [io.min_move, io.min_move, io.min_move])

    for i in range(0, numAtoms):
        if not closewrapped(atoms1[i, :], atoms2[i, :], m_vec):
            basis[i] = 1

    # -- Generate matrix showing atom mapping for each operations
    a_map = path.gen_atom_map(basis=basis, vectol=io.vectol)

    # -- Generate and apply modes for an irrep of arbitrary dimension
    pt = np.zeros((numIm, numAtoms, 3))

    pt_mode_init = irrep_tools.projection_diag(images=images,
                                               symmop_list=DG,
                                               irrep=irrep,
                                               num_unstar=num_unstar,
                                               a_map=a_map,
                                               basis=basis)

    if not np.any(pt_mode_init):
        raise RuntimeError(
            f"Uniform random initial perturbation does not contain any non-zero contributions from irrep {irrep.stokes_number}.\
 Try a different irrep.")
    pt_mode_init = pt_mode_init / np.linalg.norm(
        np.ndarray.flatten(pt_mode_init))

    pt += io.m_co[0] * pt_mode_init

    if io.irr_dim > 1:
        for i in range(1, io.irr_dim):
            pt_mode = irrep_tools.projection_odiag(
                images=images,
                symmop_list=DG,
                num_unstar=num_unstar,
                irrep=irrep,
                vec=pt_mode_init,
                index=i,
                a_map=a_map,
                basis=basis,
            )

            pt += io.m_co[i] * (pt_mode /
                                np.linalg.norm(np.ndarray.flatten(pt_mode)))

    p_vec = [
        io.p_mag / np.linalg.norm(images[0].lattice.matrix[m, :])
        for m in range(0, 3)
    ]
    # print pt[3]/np.amax(abs(pt[3]))
    # print(np.amax(p_vec*(pt[:,:,:]/np.amax(abs(pt)))))
    images_alt = []

    for i in range(numIm):
        image_copy = images[i].copy()
        alt_species = image_copy.species

        perturbed_coords = image_copy.frac_coords + p_vec * (pt[i, :, :] /
                                                             np.amax(abs(pt)))
        for j in range(numAtoms):
            image_copy.replace(j, alt_species[j], perturbed_coords[j])

        images_alt.append(image_copy)

    return images_alt, basis
def gen_perturb(path, irrep, io):

    images = path.images
    DG = path.distortion_group.matrices
    num_unstar = path.distortion_group.num_unstar
    numIm = len(images)

    irrep_tools = IrrepTools()

    io.print("\n\n\n\n" + ("=" * 27 + "\n") * 2 +
             "\nGenerating perturbations...\n\n" + ("=" * 27 + "\n") * 2 +
             "\n")
    io.print("***THE FOLLOWING DATA IS FOR THE PERTURBED IMAGES***\n\n")

    # -- Generate starting basis
    atoms1 = images[0].frac_coords
    numAtoms = len(atoms1)
    basis = np.zeros(numAtoms)
    atoms2 = images[numIm - 1].frac_coords
    m_vec = np.dot(np.linalg.inv(images[0].lattice.matrix),
                   [io.min_move, io.min_move, io.min_move])

    for i in range(0, numAtoms):
        if not closewrapped(atoms1[i, :], atoms2[i, :], m_vec):
            basis[i] = 1

    io.print("------- Atoms included in basis:")

    symbols = images[0].species
    for i in range(0, numAtoms):
        if basis[i] == 0:
            io.print(str(symbols[i]) + " No")
        else:
            io.print(str(symbols[i]) + " Yes")

    # -- Generate matrix showing atom mapping for each operations
    a_map = path.gen_atom_map(basis=basis, vectol=io.vectol)

    # -- Generate and apply modes for an irrep of arbitrary dimension
    pt = np.zeros((numIm, numAtoms, 3))

    pt_mode_init = irrep_tools.projection_diag(images=images,
                                               symmop_list=DG,
                                               irrep=irrep,
                                               num_unstar=num_unstar,
                                               a_map=a_map,
                                               basis=basis)
    pt_mode_init = pt_mode_init / \
        np.linalg.norm(np.ndarray.flatten(pt_mode_init))

    pt += io.m_co[0] * pt_mode_init

    if io.irr_dim > 1:
        for i in range(1, io.irr_dim):
            pt_mode = irrep_tools.projection_odiag(images=images,
                                                   symmop_list=DG,
                                                   num_unstar=num_unstar,
                                                   irrep=irrep,
                                                   vec=pt_mode_init,
                                                   index=i,
                                                   a_map=a_map,
                                                   basis=basis)

            pt += io.m_co[i] * \
                (pt_mode/np.linalg.norm(np.ndarray.flatten(pt_mode)))

    p_vec = [
        io.p_mag / np.linalg.norm(images[0].lattice.matrix[m, :])
        for m in range(0, 3)
    ]
    # print pt[3]/np.amax(abs(pt[3]))
    # print(np.amax(p_vec*(pt[:,:,:]/np.amax(abs(pt)))))
    images_alt = []

    for i in range(numIm):
        image_copy = images[i].copy()
        alt_species = image_copy.species

        perturbed_coords = image_copy.frac_coords + p_vec * (pt[i, :, :] /
                                                             np.amax(abs(pt)))
        for j in range(numAtoms):
            image_copy.replace(j, alt_species[j], perturbed_coords[j])

        images_alt.append(image_copy)

    return images_alt