def get_born_OUTCAR(poscar_filename="POSCAR", outcar_filename="OUTCAR", primitive_axis=np.eye(3), is_symmetry=True, symmetrize_tensors=False): cell = read_vasp(poscar_filename) primitive = Primitive(cell, primitive_axis) p2p = primitive.get_primitive_to_primitive_map() symmetry = Symmetry(primitive, is_symmetry=is_symmetry) independent_atoms = symmetry.get_independent_atoms() prim_lat = primitive.get_cell().T outcar = open(outcar_filename) borns = [] while True: line = outcar.readline() if not line: break if "NIONS" in line: num_atom = int(line.split()[11]) if "MACROSCOPIC STATIC DIELECTRIC TENSOR" in line: epsilon = [] outcar.readline() epsilon.append([float(x) for x in outcar.readline().split()]) epsilon.append([float(x) for x in outcar.readline().split()]) epsilon.append([float(x) for x in outcar.readline().split()]) if "BORN" in line: outcar.readline() line = outcar.readline() if "ion" in line: for i in range(num_atom): born = [] born.append([float(x) for x in outcar.readline().split()][1:]) born.append([float(x) for x in outcar.readline().split()][1:]) born.append([float(x) for x in outcar.readline().split()][1:]) outcar.readline() borns.append(born) reduced_borns = [] for p_i, u_i in enumerate(p2p): if p_i in independent_atoms: if symmetrize_tensors: site_sym = [similarity_transformation(prim_lat, rot) for rot in symmetry.get_site_symmetry(p_i)] reduced_borns.append(symmetrize_tensor(borns[u_i], site_sym)) else: reduced_borns.append(borns[u_i]) if symmetrize_tensors: point_sym = [similarity_transformation(prim_lat, rot) for rot in symmetry.get_pointgroup_operations()] epsilon = symmetrize_tensor(epsilon, point_sym) else: epsilon = np.array(epsilon) return np.array(reduced_borns), epsilon
def get_born_OUTCAR(poscar_filename="POSCAR", outcar_filename="OUTCAR", primitive_axis=np.eye(3), is_symmetry=True, symmetrize_tensors=False): cell = read_vasp(poscar_filename) primitive = Primitive(cell, primitive_axis) p2p = primitive.get_primitive_to_primitive_map() symmetry = Symmetry(primitive, is_symmetry=is_symmetry) independent_atoms = symmetry.get_independent_atoms() prim_lat = primitive.get_cell().T outcar = open(outcar_filename) borns = [] while True: line = outcar.readline() if not line: break if "NIONS" in line: num_atom = int(line.split()[11]) if "MACROSCOPIC STATIC DIELECTRIC TENSOR" in line: epsilon = [] outcar.readline() epsilon.append([float(x) for x in outcar.readline().split()]) epsilon.append([float(x) for x in outcar.readline().split()]) epsilon.append([float(x) for x in outcar.readline().split()]) if "BORN" in line: outcar.readline() line = outcar.readline() if "ion" in line: for i in range(num_atom): born = [] born.append([float(x) for x in outcar.readline().split()][1:]) born.append([float(x) for x in outcar.readline().split()][1:]) born.append([float(x) for x in outcar.readline().split()][1:]) outcar.readline() borns.append(born) reduced_borns = [] for p_i, u_i in enumerate(p2p): if p_i in independent_atoms: if symmetrize_tensors: site_sym = [ similarity_transformation(prim_lat, rot) for rot in symmetry.get_site_symmetry(p_i) ] reduced_borns.append(symmetrize_tensor(borns[u_i], site_sym)) else: reduced_borns.append(borns[u_i]) if symmetrize_tensors: point_sym = [ similarity_transformation(prim_lat, rot) for rot in symmetry.get_pointgroup_operations() ] epsilon = symmetrize_tensor(epsilon, point_sym) else: epsilon = np.array(epsilon) return np.array(reduced_borns), epsilon
def _get_fc3_done(supercell: PhonopyAtoms, disp_dataset, symmetry: Symmetry, array_shape): num_atom = len(supercell) fc3_done = np.zeros(array_shape, dtype="byte") symprec = symmetry.tolerance lattice = supercell.cell.T positions = supercell.scaled_positions rotations = symmetry.symmetry_operations["rotations"] translations = symmetry.symmetry_operations["translations"] atom_mapping = [] for rot, trans in zip(rotations, translations): atom_indices = [ _get_atom_by_symmetry(lattice, positions, rot, trans, i, symprec) for i in range(num_atom) ] atom_mapping.append(atom_indices) for dataset_first_atom in disp_dataset["first_atoms"]: first_atom_num = dataset_first_atom["number"] site_symmetry = symmetry.get_site_symmetry(first_atom_num) direction = np.dot(dataset_first_atom["displacement"], np.linalg.inv(supercell.cell)) reduced_site_sym = get_reduced_site_symmetry(site_symmetry, direction, symprec) least_second_atom_nums = [] for second_atoms in dataset_first_atom["second_atoms"]: if "included" in second_atoms: if second_atoms["included"]: least_second_atom_nums.append(second_atoms["number"]) elif "cutoff_distance" in disp_dataset: min_vec = get_smallest_vector_of_atom_pair( first_atom_num, second_atoms["number"], supercell, symprec) min_distance = np.linalg.norm(np.dot(lattice, min_vec)) if "pair_distance" in second_atoms: assert abs(min_distance - second_atoms["pair_distance"]) < 1e-4 if min_distance < disp_dataset["cutoff_distance"]: least_second_atom_nums.append(second_atoms["number"]) positions_shifted = positions - positions[first_atom_num] least_second_atom_nums = np.unique(least_second_atom_nums) for red_rot in reduced_site_sym: second_atom_nums = [ _get_atom_by_symmetry( lattice, positions_shifted, red_rot, np.zeros(3, dtype="double"), i, symprec, ) for i in least_second_atom_nums ] second_atom_nums = np.unique(second_atom_nums) for i in range(len(rotations)): rotated_atom1 = atom_mapping[i][first_atom_num] for j in second_atom_nums: fc3_done[rotated_atom1, atom_mapping[i][j]] = 1 return fc3_done
def get_born_OUTCAR(poscar_filename="POSCAR", outcar_filename="OUTCAR", primitive_axis=np.eye(3), supercell_matrix=np.eye(3, dtype='intc'), is_symmetry=True, symmetrize_tensors=False): ucell = read_vasp(poscar_filename) scell = get_supercell(ucell, supercell_matrix) inv_smat = np.linalg.inv(supercell_matrix) pcell = get_primitive(scell, np.dot(inv_smat, primitive_axis)) u_sym = Symmetry(ucell, is_symmetry=is_symmetry) p_sym = Symmetry(pcell, is_symmetry=is_symmetry) lattice = ucell.get_cell().T outcar = open(outcar_filename) borns = [] while True: line = outcar.readline() if not line: break if "NIONS" in line: num_atom = int(line.split()[11]) if "MACROSCOPIC STATIC DIELECTRIC TENSOR" in line: epsilon = [] outcar.readline() epsilon.append([float(x) for x in outcar.readline().split()]) epsilon.append([float(x) for x in outcar.readline().split()]) epsilon.append([float(x) for x in outcar.readline().split()]) if "BORN" in line: outcar.readline() line = outcar.readline() if "ion" in line: for i in range(num_atom): born = [] born.append([float(x) for x in outcar.readline().split()][1:]) born.append([float(x) for x in outcar.readline().split()][1:]) born.append([float(x) for x in outcar.readline().split()][1:]) outcar.readline() borns.append(born) borns = np.array(borns, dtype='double') epsilon = np.array(epsilon, dtype='double') if symmetrize_tensors: borns_orig = borns.copy() point_sym = [similarity_transformation(lattice, r) for r in u_sym.get_pointgroup_operations()] epsilon = symmetrize_tensor(epsilon, point_sym) for i in range(num_atom): z = borns[i] site_sym = [similarity_transformation(lattice, r) for r in u_sym.get_site_symmetry(i)] borns[i] = symmetrize_tensor(z, site_sym) rotations = u_sym.get_symmetry_operations()['rotations'] map_atoms = u_sym.get_map_atoms() borns_copy = np.zeros_like(borns) for i, m_i in enumerate(map_atoms): count = 0 for j, r_j in enumerate(u_sym.get_map_operations()): if map_atoms[j] == m_i: count += 1 r_cart = similarity_transformation(lattice, rotations[r_j]) borns_copy[i] += similarity_transformation(r_cart, borns[j]) borns_copy[i] /= count borns = borns_copy sum_born = borns.sum(axis=0) / len(borns) borns -= sum_born if (np.abs(borns_orig - borns) > 0.1).any(): sys.stderr.write( "Born effective charge symmetrization might go wrong.\n") p2s = np.array(pcell.get_primitive_to_supercell_map(), dtype='intc') s_indep_atoms = p2s[p_sym.get_independent_atoms()] u2u = scell.get_unitcell_to_unitcell_map() u_indep_atoms = [u2u[x] for x in s_indep_atoms] reduced_borns = borns[u_indep_atoms].copy() return reduced_borns, epsilon
def get_third_order_displacements(cell: PhonopyAtoms, symmetry: Symmetry, is_plusminus="auto", is_diagonal=False): """Create dispalcement dataset. Note ---- 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. Parameters ---------- cell : PhonopyAtoms Supercell symmetry : Symmetry Symmetry of supercell is_plusminus : str or bool, optional Type of displacements, plus only (False), always plus and minus (True), and plus and minus depending on site symmetry ('auto'). is_diagonal : bool, optional Whether allow diagonal displacements of Atom 2 or not Returns ------- [{'number': atom1, 'direction': [1, 0, 0], # int 'second_atoms': [ {'number': atom2, 'directions': [ [1, 0, 0], [-1, 0, 0], ... ] 'distance': distance-between-atom1-and-atom2}, {'number': ... }, ... ] }, {'number': atom1, ... } ] """ positions = cell.scaled_positions lattice = cell.cell.T # Least displacements of first atoms (Atom 1) are searched by # using respective site symmetries of the original crystal. # 'is_diagonal=False' below is made intentionally to expect # better accuracy. disps_first = get_least_displacements(symmetry, is_plusminus=is_plusminus, is_diagonal=False) symprec = 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_vec = get_smallest_vector_of_atom_pair(atom1, atom2, cell, symprec) min_distance = np.linalg.norm(np.dot(lattice, min_vec)) dds_atom2["distance"] = min_distance dds_atom1["second_atoms"].append(dds_atom2) dds.append(dds_atom1) return dds