def get_equivalent_smallest_vectors(atom_number_supercell, atom_number_primitive, supercell, primitive_lattice, symprec): distances = [] differences = [] reduced_bases = get_reduced_bases(supercell.get_cell(), symprec) positions = np.dot(supercell.get_positions(), np.linalg.inv(reduced_bases)) # Atomic positions are confined into the lattice made of reduced bases. for pos in positions: pos -= np.rint(pos) p_pos = positions[atom_number_primitive] s_pos = positions[atom_number_supercell] for i in (-1, 0, 1): for j in (-1, 0, 1): for k in (-1, 0, 1): # The vector arrow is from the atom in primitive to # the atom in supercell cell plus a supercell lattice # point. This is related to determine the phase # convension when building dynamical matrix. diff = s_pos + [i, j, k] - p_pos differences.append(diff) vec = np.dot(diff, reduced_bases) distances.append(np.linalg.norm(vec)) minimum = min(distances) smallest_vectors = [] for i in range(27): if abs(minimum - distances[i]) < symprec: relative_scale = np.dot(reduced_bases, np.linalg.inv(primitive_lattice)) smallest_vectors.append(np.dot(differences[i], relative_scale)) return smallest_vectors
def get_equivalent_smallest_vectors( atom_number_supercell, atom_number_primitive, supercell, primitive_lattice, symprec ): distances = [] differences = [] reduced_bases = get_reduced_bases(supercell.get_cell(), symprec) positions = np.dot(supercell.get_positions(), np.linalg.inv(reduced_bases)) # Atomic positions are confined into the lattice made of reduced bases. for pos in positions: pos -= np.rint(pos) p_pos = positions[atom_number_primitive] s_pos = positions[atom_number_supercell] for i in (-1, 0, 1): for j in (-1, 0, 1): for k in (-1, 0, 1): # The vector arrow is from the atom in primitive to # the atom in supercell cell plus a supercell lattice # point. This is related to determine the phase # convension when building dynamical matrix. diff = s_pos + [i, j, k] - p_pos differences.append(diff) vec = np.dot(diff, reduced_bases) distances.append(np.linalg.norm(vec)) minimum = min(distances) smallest_vectors = [] for i in range(27): if abs(minimum - distances[i]) < symprec: relative_scale = np.dot(reduced_bases, np.linalg.inv(primitive_lattice)) smallest_vectors.append(np.dot(differences[i], relative_scale)) return smallest_vectors
def __init__(self, primitive_vectors): self._primitive_vectors = primitive_vectors # column vectors self._tolerance = min(np.sum(primitive_vectors ** 2, axis=0)) * 0.01 self._reduced_bases = get_reduced_bases(primitive_vectors.T) self._tmat = np.dot(np.linalg.inv(self._primitive_vectors), self._reduced_bases) self._tmat_inv = np.linalg.inv(self._tmat) self._shortest_qpoints = None
def get_equivalent_smallest_vectors_np(atom_number_supercell, atom_number_primitive, supercell, primitive_lattice, symprec): distances = [] differences = [] reduced_bases = get_reduced_bases(supercell.get_cell(), symprec) positions = np.dot(supercell.get_positions(), np.linalg.inv(reduced_bases)) # Atomic positions are confined into the lattice made of reduced bases. positions -= np.rint(positions) p_pos = positions[atom_number_primitive] s_pos = positions[atom_number_supercell] sc_range_1 = np.array([-1, 0, 1])[:, None] * np.array([1, 0, 0])[None, :] sc_range_2 = np.array([-1, 0, 1])[:, None] * np.array([0, 1, 0])[None, :] sc_range_3 = np.array([-1, 0, 1])[:, None] * np.array([0, 0, 1])[None, :] # The vector arrow is from the atom in primitive to # the atom in supercell cell plus a supercell lattice # point. This is related to determine the phase # convension when building dynamical matrix. differences = (s_pos + sc_range_1[:, None, None] + sc_range_2[None, :, None] + sc_range_3[None, None, :] - p_pos) vecs = np.dot(differences, reduced_bases) distances = np.linalg.norm(vecs, axis=-1) relative_scale = np.dot(reduced_bases, np.linalg.inv(primitive_lattice)) minimum = np.min(distances) indices = np.where(np.abs(minimum - distances) < symprec) smallest_vectors = np.dot(differences[indices], relative_scale) smallest_vectors = smallest_vectors.reshape(-1, 3) return smallest_vectors
def cutoff_force_constants(force_constants, supercell, cutoff_radius, symprec=1e-5): num_atom = supercell.get_number_of_atoms() reduced_bases = get_reduced_bases(supercell.get_cell(), tolerance=symprec) positions = np.dot(supercell.get_positions(), np.linalg.inv(reduced_bases)) for i in range(num_atom): pos_i = positions[i] for j in range(num_atom): pos_j = positions[j] min_distance = _get_shortest_distance_in_PBC( pos_i, pos_j, reduced_bases) if min_distance > cutoff_radius: force_constants[i, j] = 0.0
def cutoff_force_constants(force_constants, supercell, cutoff_radius, symprec=1e-5): num_atom = supercell.get_number_of_atoms() reduced_bases = get_reduced_bases(supercell.get_cell(), symprec) positions = np.dot(supercell.get_positions(), np.linalg.inv(reduced_bases)) for i in range(num_atom): pos_i = positions[i] for j in range(num_atom): pos_j = positions[j] min_distance = _get_shortest_distance_in_PBC(pos_i, pos_j, reduced_bases) if min_distance > cutoff_radius: force_constants[i, j] = 0.0
def __init__(self, reciprocal_lattice, tolerance=0.01): """Init method. Parameters ---------- reciprocal_lattice : array_like Reciprocal primitive cell basis vectors given in column vectors. shape=(3,3) dtype=float tolerance : float, optional Default = 0.01 """ self._reciprocal_lattice = np.array(reciprocal_lattice) self._tolerance = min(np.sum(reciprocal_lattice**2, axis=0)) * tolerance self._reduced_bases = get_reduced_bases(reciprocal_lattice.T) self._tmat = np.dot(np.linalg.inv(self._reciprocal_lattice), self._reduced_bases.T) self._tmat_inv = np.linalg.inv(self._tmat) self.shortest_qpoints = None
def __init__(self, reciprocal_lattice, tolerance=0.01): """ Parameters ---------- reciprocal_lattice : array_like Reciprocal primitive cell basis vectors given in column vectors. shape=(3,3) dtype=float tolerance : float, optional Default = 0.01 """ self._reciprocal_lattice = np.array(reciprocal_lattice) self._tolerance = min( np.sum(reciprocal_lattice ** 2, axis=0)) * tolerance self._reduced_bases = get_reduced_bases(reciprocal_lattice.T) self._tmat = np.dot(np.linalg.inv(self._reciprocal_lattice), self._reduced_bases.T) self._tmat_inv = np.linalg.inv(self._tmat) self.shortest_qpoints = None
def get_phonon_tb( # phonopy_atoms=[], atoms=[], fc=[], out_file="phonopyTB_hr.dat", distance_to_A=1.0, scell=np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), factor=VaspToTHz, symprec=1e-05, displacement_distance=0.01, ): """Generate phonon TB Hamiltonia, along with WannierHamn.""" # Forked from Wannier-tools unitcell = atoms.phonopy_converter() # unitcell = phonopy_atoms prim_mat = np.array(PhonopyInputs(atoms).prim_axis().split("=")[1].split(), dtype="float").reshape(3, 3) # print("cell", unitcell.cell) num_atom = unitcell.get_number_of_atoms() num_satom = determinant(scell) * num_atom if fc.shape[0] != num_satom: print("Check Force constant matrix.") phonon = Phonopy( unitcell, scell, primitive_matrix=prim_mat, factor=factor, dynamical_matrix_decimals=None, force_constants_decimals=None, symprec=symprec, is_symmetry=True, use_lapack_solver=False, log_level=1, ) supercell = phonon.get_supercell() primitive = phonon.get_primitive() # Set force constants phonon.set_force_constants(fc) phonon._set_dynamical_matrix() dmat = phonon._dynamical_matrix # rescale fcmat by THZ**2 fcmat = dmat._force_constants * factor**2 # FORCE_CONSTANTS # fcmat = dmat._force_constants * factor ** 2 # FORCE_CONSTANTS smallest_vectors = dmat._smallest_vectors # mass = dmat._mass mass = dmat._pcell.get_masses() print("mass=", mass) multi = dmat._multiplicity reduced_bases = get_reduced_bases(supercell.get_cell(), symprec) positions = np.dot(supercell.get_positions(), np.linalg.inv(reduced_bases)) # for pos in positions: pos -= np.rint(pos) relative_scale = np.dot(reduced_bases, np.linalg.inv(primitive.get_cell())) super_pos = np.zeros((num_satom, 3), dtype=np.float64) for i in range(num_satom): super_pos[i] = np.dot(positions[i], relative_scale) p2s_map = dmat._p2s_map = primitive.get_primitive_to_supercell_map() s2p_map = dmat._s2p_map = primitive.get_supercell_to_primitive_map() num_satom = supercell.get_number_of_atoms() num_patom = primitive.get_number_of_atoms() get_phonon_hr( fcmat, smallest_vectors, mass, multi, super_pos, p2s_map, s2p_map, num_satom, num_patom, out_file, ) print("phonopy_TB.dat generated! ")
if len(symbols_with_no_mass) > 0: if log_level > 0: print_end() sys.exit(1) phonon.set_dynamical_matrix() dmat = phonon._dynamical_matrix # rescale fcmat by THZ**2 fcmat = dmat._force_constants * factor**2 # FORCE_CONSTANTS smallest_vectors = dmat._smallest_vectors #mass = dmat._mass mass = dmat._pcell.get_masses() multi = dmat._multiplicity reduced_bases = get_reduced_bases(supercell.get_cell(), options.symprec) positions = np.dot(supercell.get_positions(), np.linalg.inv(reduced_bases)) #for pos in positions: pos -= np.rint(pos) relative_scale = np.dot(reduced_bases, np.linalg.inv(primitive.get_cell())) super_pos = np.zeros((num_satom, 3), dtype=np.float64) for i in range(num_satom): super_pos[i] = np.dot(positions[i], relative_scale) p2s_map = dmat._p2s_map = primitive.get_primitive_to_supercell_map() s2p_map = dmat._s2p_map = primitive.get_supercell_to_primitive_map() num_satom = supercell.get_number_of_atoms() num_patom = primitive.get_number_of_atoms() # get hr
def _relocate_BZ_grid_address( D_diag, Q, reciprocal_lattice, # column vectors is_shift=None, store_dense_gp_map=False, ): """Grid addresses are relocated to be inside first Brillouin zone. Number of ir-grid-points inside Brillouin zone is returned. It is assumed that the following arrays have the shapes of bz_grid_address : (num_grid_points_in_FBZ, 3) Note that the shape of grid_address is (prod(mesh), 3) and the addresses in grid_address are arranged to be in parallelepiped made of reciprocal basis vectors. The addresses in bz_grid_address are inside the first Brillouin zone or on its surface. Each address in grid_address is mapped to one of those in bz_grid_address by a reciprocal lattice vector (including zero vector) with keeping element order. For those inside first BZ, the mapping is one-to-one. For those on the first BZ surface, more than one addresses in bz_grid_address that are equivalent by the reciprocal lattice translations are mapped to one address in grid_address. The bz_grid_address and bz_map are given in the following format depending on the choice of `store_dense_gp_map`. store_dense_gp_map = False -------------------------- Those grid points on the BZ surface except for one of them are appended to the tail of this array, for which bz_grid_address has the following data storing: |------------------array size of bz_grid_address-------------------------| |--those equivalent to grid_address--|--those on surface except for one--| |-----array size of grid_address-----| Number of grid points stored in bz_grid_address is returned. bz_map is used to recover grid point index expanded to include BZ surface from grid address. The grid point indices are mapped to (mesh[0] * 2) x (mesh[1] * 2) x (mesh[2] * 2) space (bz_map). bz_map[(prod(mesh) * 8):(prod(mesh) * 9 + 1)] contains equivalent information to bz_map[:] with `store_dense_gp_map=True`. shape=(prod(mesh * 9) + 1, ) store_dense_gp_map = True ------------------------- The translationally equivalent grid points corresponding to one grid point on BZ surface are stored in continuously. If the multiplicity (number of equivalent grid points) is 1, 2, 1, 4, ... for the grid points, ``bz_map`` stores the multiplicites and the index positions of the first grid point of the equivalent grid points, i.e., bz_map[:] = [0, 1, 3, 4, 8...] grid_address[0] -> bz_grid_address[0:1] grid_address[1] -> bz_grid_address[1:3] grid_address[2] -> bz_grid_address[3:4] grid_address[3] -> bz_grid_address[4:8] shape=(prod(mesh) + 1, ) """ import phono3py._phono3py as phono3c if is_shift is None: _is_shift = np.zeros(3, dtype="int_") else: _is_shift = np.array(is_shift, dtype="int_") bz_grid_addresses = np.zeros((np.prod(D_diag) * 8, 3), dtype="int_", order="C") bzg2grg = np.zeros(len(bz_grid_addresses), dtype="int_") if store_dense_gp_map: bz_map = np.zeros(np.prod(D_diag) + 1, dtype="int_") else: bz_map = np.zeros(np.prod(D_diag) * 9 + 1, dtype="int_") reclat_T = np.array(reciprocal_lattice.T, dtype="double", order="C") reduced_basis = get_reduced_bases(reclat_T) tmat_inv = np.dot(np.linalg.inv(reduced_basis.T), reclat_T.T) tmat_inv_int = np.rint(tmat_inv).astype("int_") assert (np.abs(tmat_inv - tmat_inv_int) < 1e-5).all() num_gp = phono3c.bz_grid_addresses( bz_grid_addresses, bz_map, bzg2grg, np.array(D_diag, dtype="int_"), np.array(np.dot(tmat_inv_int, Q), dtype="int_", order="C"), _is_shift, np.array(reduced_basis.T, dtype="double", order="C"), store_dense_gp_map * 1 + 1, ) bz_grid_addresses = np.array(bz_grid_addresses[:num_gp], dtype="int_", order="C") bzg2grg = np.array(bzg2grg[:num_gp], dtype="int_") return bz_grid_addresses, bz_map, bzg2grg