def run(self, atom_pairs): s2p = self._primitive.get_supercell_to_primitive_map() p2p = self._primitive.get_primitive_to_primitive_map() dists = np.zeros((len(self._temperatures), len(atom_pairs)), dtype=float) for i, (atom1, atom2) in enumerate(atom_pairs): patom1 = p2p[s2p[atom1]] patom2 = p2p[s2p[atom2]] delta_r = get_equivalent_smallest_vectors( atom2, atom1, self._supercell, self._primitive.get_cell(), self._symprec)[0] self._project_eigenvectors(delta_r, self._primitive.get_cell()) for freqs, vecs, q in zip(self._frequencies, self._p_eigenvectors, self._qpoints): c_cross = 1.0 / np.sqrt( self._masses[patom1] * self._masses[patom2]) c1 = 1.0 / self._masses[patom1] c2 = 1.0 / self._masses[patom2] for f, v in zip(freqs, vecs.T): cross_term = self._get_cross(v, delta_r, q, patom1, patom2) v2 = abs(v)**2 if f > self._cutoff_frequency: for j, t in enumerate(self._temperatures): dists[j, i] += self.get_Q2(f, t) * ( v2[patom1] * c1 + cross_term * c_cross + v2[patom2] * c2) self._atom_pairs = atom_pairs self._distances = dists / len(self._frequencies)
def cutoff_fc3_by_zero(fc3, supercell, cutoff_distance, symprec=1e-5): num_atom = supercell.get_number_of_atoms() lattice = supercell.get_cell().T min_distances = np.zeros((num_atom, num_atom), dtype='double') for i in range(num_atom): # run in supercell for j in range(num_atom): # run in primitive min_distances[i, j] = np.linalg.norm( np.dot( lattice, get_equivalent_smallest_vectors(i, j, supercell, lattice.T, symprec)[0])) for i, j, k in np.ndindex(num_atom, num_atom, num_atom): for pair in ((i, j), (j, k), (k, i)): if min_distances[pair] > cutoff_distance: fc3[i, j, k] = 0 break
def get_third_order_displacements(cell, symmetry, is_plusminus='auto', is_diagonal=False): # Atoms 1, 2, and 3 are defined as follows: # # Atom 1: The first displaced atom. Third order force constant # between Atoms 1, 2, and 3 is calculated. # Atom 2: The second displaced atom. Second order force constant # between Atoms 2 and 3 is calculated. # Atom 3: Force is mesuared on this atom. positions = cell.get_scaled_positions() lattice = cell.get_cell().T # Least displacements for third order force constants in yaml file # # Data structure # [{'number': atom1, # 'displacement': [0.00000, 0.007071, 0.007071], # 'second_atoms': [ {'number': atom2, # 'displacements': [[0.007071, 0.000000, 0.007071], # [-0.007071, 0.000000, -0.007071] # ,...]}, # {'number': ... } ] }, # {'number': atom1, ... } ] # Least displacements of first atoms (Atom 1) are searched by # using respective site symmetries of the original crystal. disps_first = get_least_displacements(symmetry, is_plusminus=is_plusminus, is_diagonal=False) symprec = symmetry.get_symmetry_tolerance() dds = [] for disp in disps_first: atom1 = disp[0] disp1 = disp[1:4] site_sym = symmetry.get_site_symmetry(atom1) dds_atom1 = {'number': atom1, 'direction': disp1, 'second_atoms': []} # Reduced site symmetry at the first atom with respect to # the displacement of the first atoms. reduced_site_sym = get_reduced_site_symmetry(site_sym, disp1, symprec) # Searching orbits (second atoms) with respect to # the first atom and its reduced site symmetry. second_atoms = get_least_orbits(atom1, cell, reduced_site_sym, symprec) for atom2 in second_atoms: dds_atom2 = get_next_displacements(atom1, atom2, reduced_site_sym, lattice, positions, symprec, is_diagonal) min_distance = np.linalg.norm( np.dot(lattice, get_equivalent_smallest_vectors( atom1, atom2, cell, lattice.T, symprec)[0])) dds_atom2['distance'] = min_distance dds_atom1['second_atoms'].append(dds_atom2) dds.append(dds_atom1) return dds