def _distribute_forces(supercell, disp, forces, filename, symprec): natom = supercell.get_number_of_atoms() lattice = supercell.get_cell() symbols = supercell.get_chemical_symbols() positions = supercell.get_positions() positions[disp[0]] += disp[1] cell = Atoms(cell=lattice, positions=positions, symbols=symbols, pbc=True) symmetry = Symmetry(cell, symprec) independent_atoms = symmetry.get_independent_atoms() # Rotation matrices in Cartesian rotations = [] for r in symmetry.get_symmetry_operations()["rotations"]: rotations.append(similarity_transformation(lattice.T, r)) map_operations = symmetry.get_map_operations() map_atoms = symmetry.get_map_atoms() atoms_in_dot_scf = _get_independent_atoms_in_dot_scf(filename) if len(forces) != len(atoms_in_dot_scf): print("%s does not contain necessary information." % filename) print('Plese check if there are "FGL" lines with') print('"total forces" are required.') return False if len(atoms_in_dot_scf) == natom: print("It is assumed that there is no symmetrically-equivalent " "atoms in ") print("'%s' at wien2k calculation." % filename) force_set = forces elif len(forces) != len(independent_atoms): print("Non-equivalent atoms of %s could not be recognized by phonopy." % filename) return False else: # 1. Transform wien2k forces to those on independent atoms indep_atoms_to_wien2k = [] forces_remap = [] for i, pos_wien2k in enumerate(atoms_in_dot_scf): for j, pos in enumerate(cell.get_scaled_positions()): diff = pos_wien2k - pos diff -= np.rint(diff) if (abs(diff) < symprec).all(): forces_remap.append(np.dot(rotations[map_operations[j]], forces[i])) indep_atoms_to_wien2k.append(map_atoms[j]) break if len(forces_remap) != len(forces): print("Atomic position mapping between Wien2k and phonopy failed.") print("If you think this is caused by a bug of phonopy") print("please report it in the phonopy mainling list.") return False # 2. Distribute forces from independent to dependent atoms. force_set = [] for i in range(natom): j = indep_atoms_to_wien2k.index(map_atoms[i]) force_set.append(np.dot(rotations[map_operations[i]].T, forces_remap[j])) return force_set
def _expand_borns(borns, primitive: PhonopyAtoms, prim_symmetry: Symmetry): # Expand Born effective charges to all atoms in the primitive cell rotations = prim_symmetry.symmetry_operations["rotations"] map_operations = prim_symmetry.get_map_operations() map_atoms = prim_symmetry.get_map_atoms() for i in range(len(primitive)): # R_cart = L R L^-1 rot_cartesian = similarity_transformation(primitive.cell.T, rotations[map_operations[i]]) # R_cart^T B R_cart^-T (inverse rotation is required to transform) borns[i] = similarity_transformation(rot_cartesian.T, borns[map_atoms[i]])
def get_born_parameters(f, primitive, is_symmetry): # Read unit conversion factor, damping factor, ... factors = [float(x) for x in f.readline().split()] if len(factors) < 1: print "BORN file format of line 1 is incorrect" return False if len(factors) < 2: factors = factors[0] # Read dielectric constant line = f.readline().split() if not len(line) == 9: print "BORN file format of line 2 is incorrect" return False dielectric = np.reshape([float(x) for x in line], (3, 3)) # Read Born effective charge symmetry = Symmetry(primitive, is_symmetry=is_symmetry) independent_atoms = symmetry.get_independent_atoms() born = np.zeros((primitive.get_number_of_atoms(), 3, 3), dtype=float) for i in independent_atoms: line = f.readline().split() if len(line) == 0: print "Number of lines for Born effect charge is not enough." return False if not len(line) == 9: print "BORN file format of line %d is incorrect" % (i + 3) return False born[i] = np.reshape([float(x) for x in line], (3, 3)) # Expand Born effective charges to all atoms in the primitive cell rotations = symmetry.get_symmetry_operations()['rotations'] map_operations = symmetry.get_map_operations() map_atoms = symmetry.get_map_atoms() for i in range(primitive.get_number_of_atoms()): # R_cart = L R L^-1 rot_cartesian = similarity_transformation( primitive.get_cell().transpose(), rotations[map_operations[i]]) # R_cart^T B R_cart^-T (inverse rotation is required to transform) born[i] = similarity_transformation(rot_cartesian.transpose(), born[map_atoms[i]]) non_anal = {'born': born, 'factor': factors, 'dielectric': dielectric } return non_anal
def parse_BORN( primitive, filename = "BORN" ): file = open( filename, 'r' ) # Read unit conversion factor, damping factor, ... factors = [ float( x ) for x in file.readline().split() ] if len( factors ) < 1: print "BORN file format of line 1 is incorrect" return None if len( factors ) < 2: factors.append( Damping_Factor ) # Read dielectric constant line = file.readline().split() if 9 < len( line ) or len( line ) < 9: print "BORN file format of line 2 is incorrect" return None dielectric = np.reshape( [ float( x ) for x in line ], ( 3, 3 ) ) # Read Born effective charge symmetry = Symmetry( primitive ) independent_atoms = symmetry.get_independent_atoms() born = np.zeros( ( primitive.get_number_of_atoms(), 3, 3 ), dtype=float ) for i in independent_atoms: line = file.readline().split() if 9 < len( line ) or len( line ) < 9: print "BORN file format of line %d is incorrect" % ( i + 3 ) return None born[ i ] = np.reshape( [ float( x ) for x in line ], ( 3, 3 ) ) # Expand Born effective charges to all atoms in the primitive cell rotations = symmetry.get_symmetry_operations()['rotations'] map_operations = symmetry.get_map_operations() map_atoms = symmetry.get_map_atoms() for i in range( primitive.get_number_of_atoms() ): # R_cart = L R L^-1 rot_cartesian = similarity_transformation( primitive.get_cell().transpose(), rotations[ map_operations[i] ] ) # R_cart^T B R_cart^-T ( inverse rotation is required to transform ) born[i] = similarity_transformation( rot_cartesian.transpose(), born[ map_atoms[ i ] ] ) non_anal = {'born': born, 'factor': factors, 'dielectric': dielectric } return non_anal
def get_born_parameters(f, primitive, is_symmetry): # Read unit conversion factor, damping factor, ... factors = [float(x) for x in f.readline().split()] if len(factors) < 1: print "BORN file format of line 1 is incorrect" return False if len(factors) < 2: factors = factors[0] # Read dielectric constant line = f.readline().split() if not len(line) == 9: print "BORN file format of line 2 is incorrect" return False dielectric = np.reshape([float(x) for x in line], (3, 3)) # Read Born effective charge symmetry = Symmetry(primitive, is_symmetry=is_symmetry) independent_atoms = symmetry.get_independent_atoms() born = np.zeros((primitive.get_number_of_atoms(), 3, 3), dtype=float) for i in independent_atoms: line = f.readline().split() if len(line) == 0: print "Number of lines for Born effect charge is not enough." return False if not len(line) == 9: print "BORN file format of line %d is incorrect" % (i + 3) return False born[i] = np.reshape([float(x) for x in line], (3, 3)) # Expand Born effective charges to all atoms in the primitive cell rotations = symmetry.get_symmetry_operations()['rotations'] map_operations = symmetry.get_map_operations() map_atoms = symmetry.get_map_atoms() for i in range(primitive.get_number_of_atoms()): # R_cart = L R L^-1 rot_cartesian = similarity_transformation( primitive.get_cell().transpose(), rotations[map_operations[i]]) # R_cart^T B R_cart^-T (inverse rotation is required to transform) born[i] = similarity_transformation(rot_cartesian.transpose(), born[map_atoms[i]]) non_anal = {'born': born, 'factor': factors, 'dielectric': dielectric} return non_anal
def test_get_map_operations(self): symprec = 1e-5 cell = read_cell_yaml(os.path.join(data_dir, "..", "NaCl.yaml")) scell = get_supercell(cell, np.diag([2, 2, 2]), symprec=symprec) symmetry = Symmetry(scell, symprec=symprec) # start = time.time() symmetry._set_map_operations() # end = time.time() # print(end - start) map_ops = symmetry.get_map_operations() map_atoms = symmetry.get_map_atoms() positions = scell.get_scaled_positions() rotations = symmetry.get_symmetry_operations()['rotations'] translations = symmetry.get_symmetry_operations()['translations'] for i, (op_i, atom_i) in enumerate(zip(map_ops, map_atoms)): r_pos = np.dot(rotations[op_i], positions[i]) + translations[op_i] diff = positions[atom_i] - r_pos diff -= np.rint(diff) self.assertTrue((diff < symprec).all())
def test_get_map_operations(self): symprec = 1e-5 cell = get_unitcell_from_phonopy_yaml("../NaCl.yaml") scell = get_supercell(cell, np.diag([2, 2, 2]), symprec=symprec) symmetry = Symmetry(scell, symprec=symprec) map_ops_cmp = [ 0, 2, 51, 53, 8, 1, 65, 98, 3, 14, 34, 24, 76, 69, 54, 110, 576, 198, 229, 208, 201, 192, 210, 294, 5, 67, 36, 57, 18, 90, 23, 114, 0, 9, 1, 96, 6, 323, 98, 326, 3, 42, 17, 293, 16, 130, 99, 337, 192, 194, 202, 199, 205, 196, 200, 193, 12, 5, 30, 108, 37, 128, 291, 302 ] start = time.time() symmetry._set_map_operations() end = time.time() # print(end - start) map_ops = symmetry.get_map_operations() self.assertTrue((map_ops_cmp == map_ops).all())
def test_get_map_operations(self): symprec = 1e-5 cell = get_unitcell_from_phonopy_yaml( os.path.join(data_dir,"../NaCl.yaml")) scell = get_supercell(cell, np.diag([2, 2, 2]), symprec=symprec) symmetry = Symmetry(scell, symprec=symprec) start = time.time() symmetry._set_map_operations() end = time.time() # print(end - start) map_ops = symmetry.get_map_operations() map_atoms = symmetry.get_map_atoms() positions = scell.get_scaled_positions() rotations = symmetry.get_symmetry_operations()['rotations'] translations = symmetry.get_symmetry_operations()['translations'] for i, (op_i, atom_i) in enumerate(zip(map_ops, map_atoms)): r_pos = np.dot(rotations[op_i], positions[i]) + translations[op_i] diff = positions[atom_i] - r_pos diff -= np.rint(diff) self.assertTrue((diff < symprec).all())
def test_get_map_operations(convcell_nacl): symprec = 1e-5 cell = convcell_nacl scell = get_supercell(cell, np.diag([2, 2, 2]), symprec=symprec) symmetry = Symmetry(scell, symprec=symprec) map_ops = symmetry.get_map_operations().copy() # start = time.time() # symmetry._set_map_operations() # end = time.time() # print(end - start) # map_ops_old = symmetry.get_map_operations().copy() # assert (map_ops == map_ops_old).all() map_atoms = symmetry.get_map_atoms() positions = scell.scaled_positions rotations = symmetry.symmetry_operations['rotations'] translations = symmetry.symmetry_operations['translations'] for i, (op_i, atom_i) in enumerate(zip(map_ops, map_atoms)): r_pos = np.dot(rotations[op_i], positions[i]) + translations[op_i] diff = positions[atom_i] - r_pos diff -= np.rint(diff) assert (diff < symprec).all()
def distribute_forces(supercell, disp, forces, filename, symprec): natom = supercell.get_number_of_atoms() lattice = supercell.get_cell() symbols = supercell.get_chemical_symbols() positions = supercell.get_positions() positions[disp[0]] += disp[1] cell = Atoms(cell=lattice, positions=positions, symbols=symbols, pbc=True) symmetry = Symmetry(cell, symprec) independent_atoms = symmetry.get_independent_atoms() # Rotation matrices in Cartesian rotations = [] for r in symmetry.get_symmetry_operations()['rotations']: rotations.append(similarity_transformation(lattice.T, r)) map_operations = symmetry.get_map_operations() map_atoms = symmetry.get_map_atoms() atoms_in_dot_scf = get_independent_atoms_in_dot_scf(filename) if not len(forces) == len(atoms_in_dot_scf): print "%s does not contain necessary information." % filename print "Plese check if there are \"FGL\" lines with" print "\"total forces\" are required." return False if len(atoms_in_dot_scf) == natom: print "It is assumed that there is no symmetrically-equivalent atoms in " print "\'%s\' at wien2k calculation." % filename print "" force_set = forces elif not len(forces) == len(independent_atoms): print "Non-equivalent atoms of %s could not be recognized by phonopy." % filename return False else: # 1. Transform wien2k forces to those on independent atoms indep_atoms_to_wien2k = [] forces_remap = [] for i, pos_wien2k in enumerate(atoms_in_dot_scf): for j, pos in enumerate(cell.get_scaled_positions()): diff = pos_wien2k - pos diff -= np.rint(diff) if (abs(diff) < 0.00001).all(): forces_remap.append( np.dot(forces[i], rotations[map_operations[j]].T)) indep_atoms_to_wien2k.append(map_atoms[j]) break if not len(forces_remap) == len(forces): print "Atomic position mapping between Wien2k and phonopy failed." print "If you think this is caused by a bug of phonopy" print "please report it in the phonopy mainling list." return False # 2. Distribute forces from independent to dependent atoms. force_set = [] for i in range(natom): force_set.append( np.dot(forces_remap[indep_atoms_to_wien2k.index(map_atoms[i])], rotations[map_operations[i]])) return force_set
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