class Poscar(object): ''' classdocs ''' def __init__(self, path, suffix="", supercell=None, title="", selective_dynamics=False, velocities=False): ''' Constructor ''' self.path = path self.suffix = suffix self.version = 0 self.title = title self.selective_dynamics = selective_dynamics self.velocities = velocities self.direct_coords = False self.counts = [] self.formula_unit = 0 self.symbols = [] if supercell == None: self.supercell=SuperCell() else: self.supercell = supercell self.surface_area = 0 if supercell == None: self._extract_data() if self.direct_coords == False: self._convert_to_direct_coordinates() def find_adatoms(self): # Mark adatoms nr_of_adatoms = self._count_adatoms() for i in range(1, 1 + nr_of_adatoms): self.supercell.atoms[-i].adatom = True def _count_adatoms(self): """ This function will count atoms as adatoms if there is less atoms on top surface than in the bottom layer. Accuracy of the rounding is set with decimals variable """ decimals = 5 hp = round(self.supercell.get_highest_position(), decimals) atoms_at_hp = 0 for atom in self.supercell.atoms: if round(atom.position[2], decimals) == hp: atoms_at_hp += 1 lp = round(self.supercell.get_lowest_position(), decimals) atoms_at_lp = 0 for atom in self.supercell.atoms: if round(atom.position[2], decimals) == lp: atoms_at_lp += 1 if atoms_at_hp < atoms_at_lp: return atoms_at_hp else: return 0 def _extract_data(self): def _float_list(lst): new_lst = [] for item in lst: new_lst.append(float(item)) return new_lst def _int_list(lst): new_lst = [] for item in lst: new_lst.append(int(item)) return new_lst if getline("%s/POSCAR%s" % (self.path, self.suffix), 6).strip().isdigit(): self.version = 4 self.counts = _int_list(getline("%s/POSCAR%s" % (self.path, self.suffix), 6).split()) self.symbols = ['None'] * len(self.counts) else: self.version = 5 self.symbols = getline("%s/POSCAR%s" % (self.path, self.suffix), 6).split() try: self.counts = _int_list(getline("%s/POSCAR%s" % (self.path, self.suffix), 7).split()) except: print getline("%s/POSCAR%s" % (self.path, self.suffix), 7) if len(self.counts) == 0: print "Error in POSCAR%s at: %s" % (self.suffix, self.path) exit() maximum = self.counts[0] for count in self.counts: if count > maximum: maximum = count self.formula_unit = maximum pos_starting_line = 0 if self.version >= 5: if getline("%s/POSCAR%s" % (self.path, self.suffix), 8)[0] in ['s', 'S']: self.selective_dynamics = True if getline("%s/POSCAR%s" % (self.path, self.suffix), 9)[0] in ['D', 'd']: self.direct_coords = True pos_starting_line = 10 else: if getline("%s/POSCAR%s" % (self.path, self.suffix), 8)[0] in ['D', 'd']: self.direct_coords = True pos_starting_line = 9 else: if getline("%s/POSCAR%s" % (self.path, self.suffix), 7)[0] in ['s', 'S']: self.selective_dynamics = True if getline("%s/POSCAR%s" % (self.path, self.suffix), 8)[0] in ['D', 'd']: self.direct_coords = True pos_starting_line = 9 else: if getline("%s/POSCAR%s" % (self.path, self.suffix), 7)[0] in ['D', 'd']: self.direct_coords = True pos_starting_line = 6 self.title = getline("%s/POSCAR%s" % (self.path, self.suffix), 1).rstrip() self.supercell.a0 = float(getline("%s/POSCAR%s" % (self.path, self.suffix), 2)) a1 = _float_list(getline("%s/POSCAR%s" % (self.path, self.suffix), 3).split()) a1 = array([a1[0], a1[1], a1[2]]) a2 = _float_list(getline("%s/POSCAR%s" % (self.path, self.suffix), 4).split()) a2 = array([a2[0], a2[1], a2[2]]) a3 = _float_list(getline("%s/POSCAR%s" % (self.path, self.suffix), 5).split()) a3 = array([a3[0], a3[1], a3[2]]) self.surface_area = self.supercell.a0 * 2 * norm(cross(a1, a2)) self.supercell.primitive_cell = PrimitiveCell(a1, a2, a3) f = open("%s/POSCAR%s" % (self.path, self.suffix)) for i in range(0, len(self.counts)): for j in range(pos_starting_line, pos_starting_line + self.counts[i]): position = getline("%s/POSCAR%s" % (self.path, self.suffix), j).split() if self.selective_dynamics: relax = position[3:6] position = _float_list(position[:3]) position = array([position[0], position[1], position[2]]) if self.selective_dynamics: self.supercell.add(self.symbols[i], position, relaxation=relax) else: self.supercell.add(self.symbols[i], position) pos_starting_line += self.counts[i] f.close() def _convert_to_direct_coordinates(self): print "Running convertion" new_sc = SuperCell() for atom in self.supercell.atoms: new_sc.add(atom.symbol, self.supercell.convert_to_direct(atom.position)) self.supercell.atoms = new_sc.atoms self.direct_coords = True def create_file(self): outfile = open(self.path + '/POSCAR', 'w') outfile.write(self.title) outfile.write(' - %s\n' % datetime.now()) outfile.write('%f\n' % self.supercell.a0) outfile.write(str(self.supercell.primitive_cell)) outfile.write(" ".join(self.symbols) + '\n') # Change this outfile.write(" ".join(str(x) for x in self.counts) + '\n') # and this if self.selective_dynamics: outfile.write('Selective dynamics\n') outfile.write("Direct\n") for atom in self.supercell.atoms: if self.selective_dynamics: outfile.write("%s\n" % atom.str_with_relaxation()) else: outfile.write("%s\n" % atom) if self.velocities: outfile.write(2 * '\n') for atom in self.supercell.atoms: outfile.write(" %.9f %.9f %.9f\n" % (atom.velocity[0], atom.velocity[1], atom.velocity[2])) outfile.close()
class Contcar(object): ''' classdocs ''' def __init__(self, path): ''' Constructor ''' self.path = path self.version = 0 self.title = '' self.selective_dynamics = False self.direct_coords = False self.counts = [] self.formula_unit = 0 self.symbols = [] self.supercell = SuperCell() self.surface_area = 0 self.coa = 0 try: self._extract_data() except: print "Error with CONTCAR in: %s" % self.path #print exc_info() def find_adatoms(self): # Mark adatoms nr_of_adatoms = self._count_adatoms() for i in range(1, 1 + nr_of_adatoms): self.supercell.atoms[-i].adatom = True def _count_adatoms(self): """ This function will count atoms as adatoms if there is less atoms on top surface than in the bottom layer. Accuracy of the rounding is set with decimals variable """ decimals = 5 hp = round(self.supercell.get_highest_position(), decimals) atoms_at_hp = 0 for atom in self.supercell.atoms: if round(atom.position[2], decimals) == hp: atoms_at_hp += 1 lp = round(self.supercell.get_lowest_position(), decimals) atoms_at_lp = 0 for atom in self.supercell.atoms: if round(atom.position[2], decimals) == lp: atoms_at_lp += 1 if atoms_at_hp < atoms_at_lp: return atoms_at_hp else: return 0 def _convert_to_direct_coordinates(self): print "Running convertion" new_sc = SuperCell() for atom in self.supercell.atoms: new_sc.add(atom.symbol, self.supercell.convert_to_direct(atom.position)) self.supercell.atoms = new_sc.atoms self.direct_coords = True def _extract_data(self): def _float_list(lst): new_lst = [] for item in lst: new_lst.append(float(item)) return new_lst def _int_list(lst): new_lst = [] for item in lst: new_lst.append(int(item)) return new_lst if getline("%s/CONTCAR" % self.path, 6).strip().isdigit(): self.version = 4 self.counts = _int_list(getline("%s/CONTCAR" % self.path, 6).split()) self.symbols = ['None'] * len(self.counts) else: self.version = 5 self.symbols = getline("%s/CONTCAR" % self.path, 6).split() self.counts = _int_list(getline("%s/CONTCAR" % self.path, 7).split()) maximum = self.counts[0] for count in self.counts: if count > maximum: maximum = count self.formula_unit = maximum pos_starting_line = 0 if self.version >= 5: if getline("%s/CONTCAR" % self.path, 8)[0] in ['s', 'S']: self.selective_dynamics = True if getline("%s/CONTCAR" % self.path, 9)[0] in ['D', 'd']: self.direct_coords = True pos_starting_line = 10 else: if getline("%s/CONTCAR" % self.path, 8)[0] in ['D', 'd']: self.direct_coords = True pos_starting_line = 9 else: if getline("%s/CONTCAR" % self.path, 7)[0] in ['s', 'S']: self.selective_dynamics = True if getline("%s/CONTCAR" % self.path, 8)[0] in ['D', 'd']: self.direct_coords = True pos_starting_line = 9 else: if getline("%s/CONTCAR" % self.path, 7)[0] in ['D', 'd']: self.direct_coords = True pos_starting_line = 6 self.title = getline("%s/CONTCAR" % self.path, 1).rstrip() self.supercell.a0 = float(getline("%s/CONTCAR" % self.path, 2).split()[0]) a1 = _float_list(getline("%s/CONTCAR" % self.path, 3).split()) a1 = array([a1[0], a1[1], a1[2]]) a2 = _float_list(getline("%s/CONTCAR" % self.path, 4).split()) a2 = array([a2[0], a2[1], a2[2]]) a3 = _float_list(getline("%s/CONTCAR" % self.path, 5).split()) a3 = array([a3[0], a3[1], a3[2]]) self.coa = norm(a3) self.supercell.primitive_cell = PrimitiveCell(a1, a2, a3) if self.supercell.a0 < 0: self.supercell.a0 = (self.supercell.a0/np.linalg.det(self.supercell.primitive_cell.matrix))**(1./3.) self.surface_area = self.supercell.a0**2 * norm(cross(a1, a2)) f = open("%s/CONTCAR" % self.path) for i in range(0, len(self.counts)): for j in range(pos_starting_line, pos_starting_line + self.counts[i]): position = getline("%s/CONTCAR" % self.path, j).split() if self.selective_dynamics: relax = position[3:6] position = _float_list(position[:3]) position = array([position[0], position[1], position[2]]) if self.selective_dynamics: self.supercell.add(self.symbols[i], position, relaxation=relax) else: self.supercell.add(self.symbols[i], position) pos_starting_line += self.counts[i] f.close() if not self.direct_coords: self._convert_to_direct_coordinates() def distance(self, r1, r2): delta = np.linalg.norm(self.supercell.convert_to_real(r1 - r2)) return delta def _calculate_sqs_repetitions(self, other): if abs(self.supercell.primitive_cell.matrix[1, 0]) > 1.1: return (4, 4, 2) elif abs(self.supercell.primitive_cell.matrix[1, 0]) > 0.51: return (4, 2, 4) else: return (1, 1, 1) def calculate_average_u(self, return_all=False): sqs_repetitions = self._calculate_sqs_repetitions('N') print sqs_repetitions u_list = [] cd_list = [] for atom1 in self.supercell.atoms: if atom1.symbol != 'N': d = 0.0 cd = 0.0 for atom2 in self.supercell.atoms: if atom2.symbol == 'N': for i in range(-1, 2): for j in range(-1, 2): if (atom2.position[2] > atom1.position[2] and self.distance(array([atom1.position[0] + i, atom1.position[1] + j, 0]), array([atom2.position[0], atom2.position[1], 0])) < 1.5): new_d = self.distance(atom1.position, atom2.position) new_cd = atom2.position[2] - atom1.position[2] if d == 0 or new_d < d: d = new_d if cd == 0 or new_cd < cd: cd = new_cd elif (atom2.position[2] + 1. > atom1.position[2] and self.distance(array([atom1.position[0] + i, atom1.position[1] + j, 0]), array([atom2.position[0], atom2.position[1], 0])) < 1.5 ): new_d = self.distance(atom1.position, atom2.position + array([0, 0, 1.])) new_cd = atom2.position[2] + 1 - atom1.position[2] if d == 0 or new_d < d: d = new_d if cd == 0 or new_cd < cd: cd = new_cd if d == 0 or cd == 0: print "Found no atom to compare with" else: u_list.append(d / (self.coa * self.supercell.a0) * sqs_repetitions[2]) cd_list.append(cd * sqs_repetitions[2]) # Change to u_list to get u parameter not only in c-direction if return_all: return cd_list else: return sum(cd_list) / len(cd_list)