def find_correspondences(structure, symmetry, tolerance): """ Map each symmetry operation to a permutation over the atoms in structure. """ natoms = structure.get_number_of_atoms() operations = symmetry.get_symmetry_operations() translations = operations["translations"] rotations = operations["rotations"] correspondences = [] positions = structure.get_scaled_positions() nsym = len(translations) for isym in range(nsym): remaining = list(range(natoms)) perm = [] for iatom in range(natoms): dest = np.dot(rotations[isym, :, :], positions[iatom, :]) + translations[isym, :] dest %= 1. for jatom in remaining: delta = dest - positions[jatom, :] delta -= np.round(delta) if np.allclose(delta, 0., atol=tolerance): remaining.remove(jatom) perm.append(jatom) break else: raise ValueError( "the structure must have the specified symmetry") correspondences.append(perm) return tuplify(correspondences)
def get_crotations(structure, symmetry): """ Return the matrices representing the rotations in Cartesian coordinates. """ lattvec = structure.cell.T operations = symmetry.get_symmetry_operations() rotations = operations["rotations"] nruter = [] for r in rotations: crotation = (np.dot(np.linalg.solve(lattvec.T, r.T), lattvec.T)).T nruter.append(crotation * (np.fabs(crotation) >= 1e-12)) return nruter
def get_symmetry_information(sposcar_file): """ Obtain the symmetry information useful to compute the 2nd order force constants irreducible elements. """ logging.basicConfig(level=0) SYMPREC = 1e-5 if not os.path.isfile(sposcar_file): sys.exit("The specified SPOSCAR file does not exist.") supercell_matrix = np.diag([1, 1, 1]) structure = phonopy.interface.read_crystal_structure(sposcar_file, "vasp")[0] natoms = structure.get_number_of_atoms() symmetry = phonopy.structure.symmetry.Symmetry(structure, symprec=SYMPREC) dataset = symmetry.get_dataset() print("Space group {0} ({1}) detected".format(dataset["international"], dataset["number"])) crotations = get_crotations(structure, symmetry) operations = symmetry.get_symmetry_operations() translations = operations["translations"] rotations = operations["rotations"] logging.debug("About to classify atom pairs") permutations = find_correspondences(structure, symmetry, SYMPREC) print("permutations: " + str(permutations)) equivalences = classify_pairs(structure, permutations) logging.debug("{0} equivalence classes found".format(len(equivalences))) for i, eq in enumerate(equivalences): logging.debug("Equivalence class #{0}".format(i)) for il, l in enumerate(eq): logging.debug("\t{0}. {1}".format(il + 1, l)) kernels = [] irreducible = [] for i, eq in enumerate(equivalences): logging.debug("Representative of equivalence class #{0}".format(i)) invariances = find_invariances(eq[0][0], permutations) logging.debug("is left invariant by {0} operations".format( len(invariances))) for iinv, inv in enumerate(invariances): logging.debug("\t{0}. {1}".format(iinv, inv)) logging.debug("About to build the constraint matrix") coefficients = get_constraints( [crotations[inv] for inv in invariances]) rank = np.linalg.matrix_rank(coefficients) logging.debug("{0} constraints".format(coefficients.shape[0])) logging.debug( "{0} independent components in this equivalence class:".format( 9 - rank)) if (rank > 0): v = sp.linalg.svd(coefficients, full_matrices=False)[2].T kernels.append(v[:, rank - 9:]) irreducible.append(complete_constraints(coefficients)) else: kernels.append(np.identity(9)) irreducible.append([0, 1, 2, 3, 4, 5, 6, 7, 8]) for iirr, irr in enumerate(irreducible[-1]): c1, c2 = np.unravel_index(irr, (3, 3)) logging.debug("\t{0}. {1}{2},{3}{4}".format( iirr, eq[0][0][0], "xyz"[c1], eq[0][0][1], "xyz"[c2])) irreducible = tuplify(irreducible) todo = [] for eq, irr in zip(equivalences, irreducible): a1, a2 = eq[0][0] for i in irr: print("a1", a1, "a2", a2, "i", np.unravel_index(i, (3, 3))) todo += [dof2dof(a1, a2, i, natoms) for i in irr] todo = tuplify(todo) with open('out_sym', 'a') as file: file.write("2nd order todo list before acoustic sum rule: " + str(todo) + "\n") file.write( "number of irreducible elements before acoustic sum rule: " + str(len(todo)) + "\n") return [natoms, crotations, equivalences, kernels, irreducible, todo]