def download(file, to_file): if header.ssh_object: exist = file_exists_on_server(file, addr) # try: if exist: printlog('Using paramiko: ssh_object.get(): from to ', file, to_file) header.ssh_object.get(file, to_file) out = '' # except FileNotFoundError: else: out = 'file not found' else: # print(addr,file,to_file) out = runBash('rsync -uaz ' + addr + ':' + file + ' ' + to_file) if 'error' in out: res = out else: res = 'OK' out = '' printlog('Download result is ', res) return out
def gunzip_file(filename): printlog('unzipping file', filename) with open(filename.replace('.gz', ''), 'wb') as f_out: with gzip.open(filename, 'rb') as f_in: shutil.copyfileobj(f_in, f_out) return
def find_moving_atom(st1, st2): """ find moving atom The cells should have the same rprimd! return number of atom which moves between two cell """ for r1, r2 in zip(st1.rprimd, st2.rprimd): if np.linalg.norm(r1 - r2) > 0.001: printlog( 'Attention! find_moving_atom(): st1 and st2 have different rprimd' ) st1 = st1.return_atoms_to_cell() st2 = st2.return_atoms_to_cell() # diffv = np.array(st1.xcart) - np.array(st2.xcart) # diffn = np.linalg.norm(diffv, axis = 1) diffn = [] for x1, x2 in zip(st1.xcart, st2.xcart): d1, d2 = image_distance(x1, x2, st1.rprimd) diffn.append(d1) # print('max', max(diffn)) return np.argmax(diffn) # number of atom moving along the path
def run_on_server(command, addr): printlog('Running', command, 'on server ...') command = command.replace('\\', '/') # make sure is POSIX # sys.exit() if header.ssh_object: # printlog('Using paramiko ...', imp = 'y') out = header.ssh_object.run(command) elif header.sshpass: com = 'sshpass -f /home/aksenov/.ssh/p ssh ' + addr + ' "' + command + '"' # sys.exit() out = runBash(com) # sys.exit() else: bash_comm = 'ssh ' + addr + ' "' + command + '"' # print(bash_comm) out = runBash(bash_comm) out = out.split('#')[-1].strip() printlog(out) # sys.exit() return out
def push_to_server(files = None, to = None, addr = None): """ if header.ssh_object then use paramiko to (str) - path to remote folder ! """ if not is_list_like(files): files = [files] to = to.replace('\\', '/') # make sure is POSIX files_str = ' '.join(np.array(files )) printlog('push_to_server(): uploading files ', files, 'to', addr, to) command = ' mkdir -p {:}'.format( to ) run_on_server(command, addr) if header.ssh_object: for file in files: # print(file, to) header.ssh_object.put(file, to+'/'+os.path.basename(file) ) out = '' else: out = runBash('rsync -uaz '+files_str+ ' '+addr+':'+to) printlog(out) return out
def write_occmatrix(occs, folder): #create OCCMATRIX makedir(folder) printlog('I create OCCMATRIX in ', folder, imp='y') filename = folder + '/OCCMATRIX' with open(filename, 'w', newline='') as f: numat = len(occs) f.write(str(numat) + ' #num of atoms to be specified\n') at_nums = occs.keys() at_spin = [] # # 2 or 1 at_ltyp = [] # l - orbital type, 1 - s, 2 - d, 3 - f for key in occs: occ = occs[key] if len(occ) == 10: # spin polarized, d orbital at_spin.append(2) at_ltyp.append(2) else: raise RuntimeError # please write by yourself for other cases for i, l, s in zip(at_nums, at_spin, at_ltyp): f.write(list2string([i + 1, l, s]) + ' #i, l, s\n') # for sp in range(s): f.write('spin 1\n') for row in occs[i][0:len(occs[i]) // s]: f.write(list2string(row) + '\n') if s == 2: f.write('spin 2\n') for row in occs[i][len(occs[i]) // s:]: f.write(list2string(row) + '\n') f.write('\n') return filename
def determine_symmetry_positions(st, element): """ determine non-equivalent positions for atoms of type *element* element (str) - name of element, for example Li return list of lists - atom numbers for each non-equivalent position """ from pymatgen.symmetry.analyzer import SpacegroupAnalyzer stp = st.convert2pymatgen() spg = SpacegroupAnalyzer(stp) info = spg.get_symmetry_dataset() positions = {} for i, (el, pos) in enumerate(zip(st.get_elements(), info['equivalent_atoms'])): if el == element and pos not in positions: positions[pos] = [] if el == element: positions[pos].append(i) printlog('I have found ', len(positions), 'non-equivalent positions for', element, ':',positions.keys(), imp = 'y', end = '\n') printlog('Atom numbers: ', positions, imp = 'y') sorted_keys = sorted(list(positions.keys())) pos_lists = [positions[key] for key in sorted_keys ] return pos_lists
def insert_atom( st, el, i_void=None, r_imp=1.6, ): """Simple Wrapper for inserting atoms """ r_impurity = r_imp st_pores, sums, avds = determine_voids(st, r_impurity) insert_positions = determine_unique_voids(st_pores, sums, avds) printlog('To continue please choose *i_void* from the list above', imp='y') if i_void == None: sys.exit() # st.name = st.name.split('+')[0] xc = insert_positions[i_void] st_new, i_add = st.add_atoms([xc], el, return_ins=True) st_new.name += '+' + el + str(i_void) st_new.des += ';Atom ' + el + ' added to ' + str(xc) printlog(st.des, imp='y') st_new.write_xyz() st_new.magmom = [None] return st_new, i_add
def remove_atoms(st, atoms_to_remove): """ remove atoms either of types provided in *atoms_to_remove* or having numbers provided in *atoms_to_remove* st (Structure) atoms_to_remove (list) - list of str or int """ st = copy.deepcopy(st) numbers = list(range(st.natom)) atom_exsist = True while atom_exsist: for i, (n, el) in enumerate( zip(numbers, st.get_elements()) ): # print(i) if el in atoms_to_remove or n in atoms_to_remove: # print(n) # atoms_to_remove.remove(i) st = st.del_atom(i) del numbers[i] break else: atom_exsist = False printlog('remove_atoms(): Atoms', atoms_to_remove, 'were removed') # print(st.get_elements()) return st
def download(file, to_file): if header.ssh_object: exist = file_exists_on_server(file, addr) # try: if exist: printlog('Using paramiko: ssh_object.get(): from to ', file, to_file) header.ssh_object.get(file, to_file ) out = '' # except FileNotFoundError: else: out = 'file not found' else: out = runBash('rsync -uaz '+addr+':'+file+ ' '+to_file) if out: res = out else: res = 'OK' printlog('Download result is ', res) return out
def chgsum(cll, el, site, silent = 1): """ calculate sum of Bader charges for particular atoms """ for cl in cll: # print(cl.id, end = ' ') try: cl.chgsum[(el, site)] = 0 except: pass if not hasattr(cl, 'charges') or len(cl.charges) == 0: cl.get_bader_ACF() # determine_symmetry_positions(cl.end, el, silent = 0) # print('') try: pos = determine_symmetry_positions(cll[0].end, el, silent = 1) except: printlog('chgsum() Warning!', cll[0].id, 'is broken!') return 0 for p in pos[site]: '' for cl in cll: if not hasattr(cl, 'chgsum'): cl.chgsum = {} cl.chgsum[(el, site)] = 0 cl.chgsum[(el, site)] += cl.charges[p] # print('{:5.3f}'.format(cl.charges[p]), end = ' ') # print('') if not silent: print('Sum of charges for ', el+str(site+1), ':') el_ind = cl.init.znucl.index(invert(el)) # index of element in znucl and zval and nznucl zval = cl.init.zval[el_ind] # number of electrons in chosen potential for cl in cll: cl.chgsum[(el, site)]/=len(pos[site]) chgsum = zval - cl.chgsum[(el, site)] if cl == cll[0]: chgsum_ref = chgsum if not silent: print('{:5.2f}({:4.2f})'.format(chgsum, chgsum_ref-chgsum), end = ' ') if not silent: print('\n') # print(cl.charges) return chgsum
def printme(self): for key in self.vasp_params: if self.vasp_params[key] == None: continue print_and_log( "{:30s} = {:s} ".format("s.vasp_params['"+key+"']", str(self.vasp_params[key]) ), imp = 'Y', end = '\n' ) printlog('ngkpt:', self.ngkpt, imp = 'Y') printlog('POTDIR:', self.potdir, imp = 'Y', end = '\n' )
def create_surface2(st, miller_index, min_slab_size=10, min_vacuum_size=10, surface_i=0, oxidation=None, suf='', primitive=None, symmetrize=False): """ INPUT: st (Structure) - Initial input structure. Note that to ensure that the miller indices correspond to usual crystallographic definitions, you should supply a conventional unit cell structure. miller_index ([h, k, l]): Miller index of plane parallel to surface. Note that this is referenced to the input structure. If you need this to be based on the conventional cell, you should supply the conventional structure. oxidation (dic) - dictionary of effective oxidation states, e. g. {'Y':'Y3+', 'Ba':'Ba2+', 'Co':'Co2.25+', 'O':'O2-'} allows to calculate dipole moment surface_i (int) - choose particular surface min_slab_size (float) - minimum slab size min_vacuum_size (float) - vacuum thicknes in A """ from pymatgen.core.surface import SlabGenerator from pymatgen.io.vasp.inputs import Poscar from geo import replic pm = st.convert2pymatgen(oxidation=oxidation) # pm = st.convert2pymatgen() slabgen = SlabGenerator(pm, miller_index, min_slab_size, min_vacuum_size, primitive=primitive) # print(slabgen.oriented_unit_cell) slabs = slabgen.get_slabs(symmetrize=symmetrize) printlog( len(slabs), 'surfaces were generated, choose required surface using *surface_i* argument\nWriting POSCARs to xyz', imp='y') for i, slab in enumerate(slabs): pos = Poscar(slab) pos.write_file('xyz/POSCAR_suf' + str(i) + str(suf)) return slabs
def det_gravity(dos, Erange = (-100, 0)): """Determine center of gravity for DOS and return values of energy for d6 orbitals in list INPUT: dos - ase dos type with added d6 - sum of d orbitals over neighbors to impurity atoms Erange - window of energy to determine center of gravity """ sum_dos_E = {} sum_dos = {} sum_dos['d6'] = 0 sum_dos_E['d6'] = 0 for i, E in enumerate(dos.energy): if E < Erange[0]: continue if E > Erange[1]: break sum_dos['d6'] += dos.d6[i] sum_dos_E['d6'] += dos.d6[i]*E d6_gc = sum_dos_E['d6']/sum_dos['d6'] if 0: #old nn =13 sum_dos_E = [0 for i in range(nn)] sum_dos = [0 for i in range(nn)] i=-1 for E in st.dos[0]: i+=1 if E < -6: continue if E >0: break l = 1 #s sum_dos_E[l] += st.dos[l][i] * E; sum_dos[l] += st.dos[l][i] l = 2 #p sum_dos_E[l] += st.dos[l][i] * E; sum_dos[l] += st.dos[l][i] l = 3 #d sum_dos_E[l] += st.dos[l][i] * E; sum_dos[l] += st.dos[l][i] l = 0 #p+d sum_dos_E[l] += (st.dos[2][i] + st.dos[3][i]) * E; sum_dos[l] += st.dos[2][i] + st.dos[3][i] l = 11 #full sum_dos_E[l] += st.dos[l][i] * E; sum_dos[l] += st.dos[l][i] l = 12 #s+p+d sum_dos_E[l] += (st.dos[1][i] + st.dos[2][i] + st.dos[3][i]) * E; sum_dos[l] += st.dos[1][i] + st.dos[2][i] + st.dos[3][i] #Determine center of DOS st.Ec = [0 for i in range(nn)] # if debug: print "Gravity Centers for s,p,d are (eV):" for l in 1,2,3,0,11,12: if sum_dos[l] <=0 : printlog('err 123'); sum_dos[l] = 0.00001 st.Ec[l] = sum_dos_E[l] / sum_dos[l] # if debug: print st.Ec[l] return d6_gc
def makedir(path): """ *path* - path to some file Make dirname(path) directory if it does not exist """ dirname = os.path.dirname(path) if dirname and not os.path.exists(dirname): os.makedirs(dirname) printlog("Directory", dirname, " was created", imp = 'y') return
def set_ngkpt(self,arg): if not is_list_like(arg): printlog("Error! set_ngkpt type error") old = copy.copy(self.ngkpt) self.ngkpt = copy.copy(arg) self.kpoints_file = True self.vasp_params['KSPACING'] = None if old == arg: print_and_log( "Warning! You did not change one of your parameters in new set", imp = 'y') return self.history += "ngkpt was changed from "+str(old)+" to "+str(arg) + " and KPOINTS file was swithed on\n" return
def update_var(st): if st.natom != len(st.xred) != len(st.xcart) != len(st.typat) or len( st.znucl) != max(st.typat): printlog("Error! write_xyz: check your arrays.\n\n") if st.xcart == [] or len(st.xcart) != len(st.xred): printlog( "Warining! write_xyz: len(xcart) != len(xred) making xcart from xred.\n" ) st.xcart = xred2xcart(st.xred, st.rprimd) #print xcart[1] return st.rprimd, st.xcart, st.xred, st.typat, st.znucl, len(st.xred)
def create_antisite_defect(st, cation_positions = None): """ exchange cation and transition metal st (Structure) cation_positions (list of numpy arrays) - reduced coordinates of deintercalated cation positions """ #1. Find first alkali ion def find_alkali_ion(st, j_need = 1): # return the number of found alk ion of *j_need* occurrence elements = st.get_elements_z() # print (elements) j = 0 for i, el in enumerate(elements): if el in header.ALKALI_ION_ELEMENTS: # print (i,el) j+=1 if j == j_need: return i i_alk = find_alkali_ion(st, 3) x_alk = st.xcart[i_alk] #2. Find closest transition metal sur = local_surrounding(x_alk, st, n_neighbours = 1, control = 'atoms', only_elements = header.TRANSITION_ELEMENTS, periodic = True) i_tr = sur[2][0] x_tr = st.xcart[i_tr] #3. Swap atoms write_xyz(st, file_name = st.name+'_antisite_start') st = st.mov_atoms(i_alk, x_tr) st = st.mov_atoms(i_tr, x_alk) write_xyz(st, file_name = st.name+'_antisite_final') printlog('Atom ',i_alk+1,'and', i_tr+1,'were swapped') printlog('The distance between them is ', sur[3][0]) st.magmom = [None] return st
def create_antisite_defect_old(st, cation_positions=None): """ exchange cation and transition metal st (Structure) cation_positions (list of numpy arrays) - reduced coordinates of deintercalated cation positions """ #1. Find first alkali ion def find_alkali_ion(st, j_need=1): # return the number of found alk ion of *j_need* occurrence elements = st.get_elements_z() # print (elements) j = 0 for i, el in enumerate(elements): if el in header.ALKALI_ION_ELEMENTS: # print (i,el) j += 1 if j == j_need: return i i_alk = find_alkali_ion(st, 3) x_alk = st.xcart[i_alk] #2. Find closest transition metal sur = local_surrounding(x_alk, st, n_neighbours=1, control='atoms', only_elements=header.TRANSITION_ELEMENTS, periodic=True) i_tr = sur[2][0] x_tr = st.xcart[i_tr] #3. Swap atoms st.write_xyz(file_name=st.name + '_antisite_start') st = st.mov_atoms(i_alk, x_tr) st = st.mov_atoms(i_tr, x_alk) st.write_xyz(file_name=st.name + '_antisite_final') printlog('Atom ', i_alk + 1, 'and', i_tr + 1, 'were swapped') printlog('The distance between them is ', sur[3][0]) st.magmom = [None] return st
def wrapper_cp_on_server(file, to): """ tries iterativly scratch and gz """ copy_to = to copy_file = file for s, gz in product([0, 1], ['', '.gz']): printlog('scratch, gz:', s, gz) out = server_cp(copy_file + gz, to=to, gz=gz, scratch=s) if out == '': printlog('Succesfully copied', imp='y') break return
def determine_symmetry_positions(st, element, silent=0): """ determine non-equivalent positions for atoms of type *element* element (str) - name of element, for example Li return list of lists - atom numbers for each non-equivalent position """ from pymatgen.symmetry.analyzer import SpacegroupAnalyzer stp = st.convert2pymatgen() spg = SpacegroupAnalyzer(stp) info = spg.get_symmetry_dataset() positions = {} for i, (el, pos) in enumerate(zip(st.get_elements(), info['equivalent_atoms'])): if el == element and pos not in positions: positions[pos] = [] if el == element: positions[pos].append(i) if not silent: printlog('I have found ', len(positions), 'non-equivalent positions for', element, ':', positions.keys(), imp='y', end='\n') positions_for_print = {} for key in positions: positions_for_print[key] = [p + 1 for p in positions[key]] if not silent: printlog('Atom numbers: ', positions_for_print, imp='y') sorted_keys = sorted(list(positions.keys())) pos_lists = [positions[key] for key in sorted_keys] return pos_lists
def server_cp(copy_file, to, gz=True, scratch=False): if scratch: copy_file = header.PATH2ARCHIVE + '/' + copy_file else: copy_file = header.project_path_cluster + '/' + copy_file if gz: command = 'cp ' + copy_file + ' ' + to + '/CHGCAR.gz' '; gunzip -f ' + to + '/CHGCAR.gz' else: command = 'cp ' + copy_file + ' ' + to + '/CHGCAR' printlog(command, imp='y') out = run_on_server(command, addr=header.cluster_address) printlog(out, imp='y') return out
def file_exists_on_server(file, addr): file = file.replace('\\', '/') # make sure is POSIX printlog('Checking existence of file', file, 'on server', addr) if header.ssh_object: exist = header.ssh_object.fexists(file) else: exist = runBash('ssh ' + addr + ' ls ' + file) if exist: res = True else: res = False printlog('File exist? ', res) return res
def scale_cell_by_matrix(st, scale_region=(-4, 4), n_scale_images=7, parent_calc_name=None, mul_matrix=None): """ Scale rprimd and xcart of structure() object *st* from *scale_region[0]* to *scale_region[1]* (%) using *n_scale_images* images and mul_matrix. *parent_calc_name* is added to st.des Return: list of scaled Structure() objects TODO: Take care of vol, recip and so on - the best is to create some method st.actual() that update all information """ scales = np.linspace(scale_region[0], scale_region[1], n_scale_images) printlog('Scales are', scales, imp='y') # print(np.asarray(st.rprimd)) scaled_sts = [] for j, s in enumerate(scales): st_s = copy.deepcopy(st) # print(s) mul_matrix_f = s * (np.asarray(mul_matrix) - np.identity(3)) + np.identity(3) st_s.rprimd = np.dot(mul_matrix_f, st_s.rprimd) # st_s.rprimd = np.dot(s/100*np.asarray(mul_matrix)+np.identity(3), st_s.rprimd) print(mul_matrix_f) print(np.asarray(st_s.rprimd)) alpha, beta, gamma = st_s.get_angles() print(alpha, beta, gamma) st_s.xred2xcart() st_s.des = 'obtained from ' + str( parent_calc_name) + ' by scaling by ' + str(s) + ' % ' + str( mul_matrix) st_s.name = str(j + 1) scaled_sts.append(st_s) # print st_s.rprimd # plt.plot([np.linalg.norm(st.rprimd) for st in scaled_sts]) # plt.show() # sys.exit() return scaled_sts
def file_exists_on_server(file, addr): file = file.replace('\\', '/') # make sure is POSIX printlog('Checking existence of file', file, 'on server', addr ) if header.ssh_object: exist = header.ssh_object.fexists(file) else: exist = runBash('ssh '+addr+' ls '+file) if exist: res = True else: res = False printlog('File exist? ', res) return res
def form_en(sources, products, norm_el = None): """ Calculate formation energy of reaction sources, products - list of tuples (x, cl), where x is multiplier and cl is calculation norm_el - which element to use for normalization 'all' - normalize by total number of atoms """ El = [] Nzl = [] for ls in [sources, products]: E = 0 Nz = {} for x, cl in ls: E += x*cl.e0 for i, z in enumerate(cl.end.znucl): if z not in Nz: Nz[z] = 0 Nz[z] += x*cl.end.nznucl[i] El.append(E) Nzl.append(Nz) for z in Nzl[0]: if abs(Nzl[0][z] - Nzl[1][z]) > 1e-5: printlog('Error! Number of', invert(z), 'atoms in source and product are different!') # norm = 1 if 'all' == norm_el: norm = sum(Nzl[0].values()) elif type(norm_el) == str: norm = Nzl[0][invert(norm_el)] elif norm_el != None: norm = norm_el else: norm = 1 # print('Normalizing by ', norm_el, norm, 'atoms') print('dE = {:4.2f} eV'.format((El[1]-El[0])/norm))
def create_replaced_structure(st, el1, el2, rep_pos=1, only_one=False): """ allow to replace symmetry non-equivalent positions structures rep_pos(int) - number of position starting from 1 only_one - replace only one first atom """ positions = determine_symmetry_positions(st, el1) # position_list = sorted(list(positions.keys())) printlog('Choose from the following list using *del_pos*:', end='\n', imp='y') for i, pos in enumerate(positions): printlog(' ', i + 1, '--->', pos[0], end='\n', imp='y') # pos = position_list[ del_pos - 1 ] pos = positions[rep_pos - 1] printlog('You have chosen position:', pos[0], imp='y') # print(st.get_elements()) if only_one: pos = pos[0:1] st1 = st.replace_atoms(atoms_to_replace=pos, el_new=el2) st1.name += '.' + el1 + str(pos) + el2 + 'rep' # print(st1.get_elements()) # sys.exit() return st1
def create_deintercalated_structure(st, element, del_pos = 1): """ returns deintercalated structures del_pos(int) - number of position starting from 1 """ positions = determine_symmetry_positions(st, element) # position_list = sorted(list(positions.keys())) printlog('Choose from the following list using *del_pos*:', end = '\n', imp = 'y') for i, pos in enumerate(positions): printlog(' ', i+1,'--->' , pos[0], end = '\n', imp = 'y') # pos = position_list[ del_pos - 1 ] pos = positions[ del_pos - 1 ] printlog('You have chosen position:', pos[0], imp = 'y') # print(st.get_elements()) st1 = remove_atoms(st, atoms_to_remove = pos) st1.name += '.'+element+str(pos)+'del' # print(st1.get_elements()) # sys.exit() return st1
def create_deintercalated_structure(st, element, del_pos=1): """ returns deintercalated structures del_pos(int) - number of position starting from 1 """ positions = determine_symmetry_positions(st, element) # position_list = sorted(list(positions.keys())) printlog('Choose from the following list using *del_pos*:', end='\n', imp='y') for i, pos in enumerate(positions): printlog(' ', i + 1, '--->', pos[0], end='\n', imp='y') # pos = position_list[ del_pos - 1 ] pos = positions[del_pos - 1] printlog('You have chosen position:', pos[0], imp='y') # print(st.get_elements()) st1 = remove_atoms(st, atoms_to_remove=pos) st1.name += '.' + element + str(pos) + 'del' # print(st1.get_elements()) # sys.exit() return st1
def calc_k_point_mesh(rprimd, kspacing): """ rprimd (list of lists 3x3 of floats) - vectors of cell (Angstroms) kspacing (float) - required spacing between k-points in reciprocal space (A-1); paramter KSPACING in VASP the provided optimal k-mesh has the smallest sum of squared deviations of kspacings returns k-point mesh (list of int) """ N = [] recip = calc_recip_vectors(rprimd) # print(recip) for i in 0, 1, 2: n = (np.linalg.norm(recip[i])) / kspacing N.append(math.ceil(n)) N_options = [ ng for ng in itertools.product(*[(n - 1, n, n + 1) for n in N]) ] errors = [ np.sum(np.square(np.array(calc_kspacings(N, rprimd)) - kspacing)) for N in N_options ] # sum of squared deviation from kspacing for each option i_min = np.argmin(errors) N_opt = N_options[i_min] # k-mesh with smallest error printlog('I recommend k-point mesh:', N_opt, 'with k-spacings:', np.array(calc_kspacings(N_opt, rprimd)).round(2), end='\n', imp='y') printlog('Other options are:', end='\n', imp='y') printlog('{:13s} | {:20s}'.format('Mesh', 'k-spacings'), end='\n', imp='y') for ngkpt in itertools.product(*[(n - 1, n, n + 1) for n in N_opt]): printlog('{:13s} | {:26s}'.format( str(ngkpt), str(np.array(calc_kspacings(ngkpt, rprimd)).round(2))), end='\n', imp='y') return N_opt
def suf_en(cl1, cl2, silent = 0): """Calculate surface energy cl1 - supercell with surface cl2 - comensurate bulk supercell the area is determined from r[0] and r[1];- i.e they lie in surface """ st1 = cl1.end st2 = cl2.end # pm = st1.convert2pymatgen(oxidation = {'Y':'Y3+', 'Ba':'Ba2+', 'Co':'Co2.25+', 'O':'O2-'}) A = np.linalg.norm( np.cross(st1.rprimd[0] , st1.rprimd[1]) ) # print(A) if st1.natom%st2.natom > 0: printlog('Warning! check system sizes: natom1 = ', st1.natom, 'natom2 = ', st2.natom, st1.natom/st2.natom) mul = st1.natom/st2.natom gamma = (cl1.e0 - cl2.e0*mul)/2/A* header.eV_A_to_J_m if not silent: print('Surface energy = {:3.2f} J/m2 | {:} | {:} '.format(gamma, cl1.id, cl2.id)) return gamma
def set_potential(self,znucl, arg = ''): # print arg if not arg: arg = header.PATH2POTENTIALS+'/'+invert(znucl) printlog('Attention!, Default potentials is chosen from ',header.PATH2POTENTIALS, 'for',invert(znucl) , imp ='Y') if type(arg) not in (str,): # sys.exit("\nset_potential error\n") raise RuntimeError if znucl in self.potdir: if arg == self.potdir[znucl]: print_and_log( "Warning! You already have the same potential for "+str(znucl)+" element\n" ) # print type(self.potdir) self.potdir[znucl] = arg self.history += "Potential for "+str(znucl)+" was changed to "+arg+"\n" print_and_log( "Potential for "+str(znucl)+" was changed to "+arg+"\n" ) # self.update() return
def scale_cell_uniformly( st, scale_region=(-4, 4), n_scale_images=7, parent_calc_name=None, ): """ Scale uniformly rprimd and xcart of structure() object *st* from *scale_region[0]* to *scale_region[1]* (%) using *n_scale_images* images. *parent_calc_name* is added to st.des Return: list of scaled Structure() objects TODO: Take care of vol, recip and so on - the best is to create some method st.actual() that update all information """ # print scale_region scales = np.linspace(scale_region[0], scale_region[1], n_scale_images) printlog('Scales are', scales, imp='y') # print scales scaled_sts = [] for j, s in enumerate(scales): st_s = copy.deepcopy(st) for i in (0, 1, 2): st_s.rprimd[i] *= (1 + s / 100.) # print st_s.rprimd st_s.xred2xcart() st_s.des = 'obtained from ' + str( parent_calc_name) + ' by uniform scaling by ' + str(s) + ' %' st_s.name = str(j + 1) scaled_sts.append(st_s) # print st_s.rprimd # plt.plot([np.linalg.norm(st.rprimd) for st in scaled_sts]) # plt.show() return scaled_sts
def remove_one_atom(st, element, del_pos=None, iat=0): """ removes one atom of element type from position del_pos iat - number of atom inside subset """ # if not del_pos: # del_pos = 1 positions = determine_symmetry_positions(st, element) if not del_pos and len(positions) > 1: printlog( 'Error! More than one symmetry position is found, please choose del position starting from 1' ) elif len(positions) == 1: del_pos = 1 else: printlog('Position', del_pos, 'was chosen', imp='y') pos = positions[del_pos - 1] i_del = pos[iat] st = st.del_atom(i_del) # remove just iat atom st.name += '.' + element + str(i_del) + 'del' st.magmom = [None] return st, i_del
def ortho_vec(rprim, ortho_sizes=None): """ Function returns mul_mat - 3 vectors of integer numbers (ndarray) By calculating np.dot(mul_matrix, rprim) you will get rprim of orthogonal supercell (actually as close as possible to it) """ printlog( 'Calculating mul_matrix for ortho:', ortho_sizes, imp='y', ) printlog('rprim is;', rprim) vec_new = np.diag(ortho_sizes) # print(rprim) # t = rprim[1] # rprim[1] = rprim[0] # rprim[0] = t mul_matrix_float = np.dot(vec_new, np.linalg.inv(rprim)) # ortho_test = np.dot(mul_matrix_float, rprim ) # print(ortho_test) # print(mul_matrix_float) printlog('mul_matrix_float:\n', mul_matrix_float, imp='y', end='\n') mul_matrix = np.array(mul_matrix_float) mul_matrix = mul_matrix.round(0) mul_matrix = mul_matrix.astype(int) for i in [0, 1, 2]: if mul_matrix[i][i] == 0: # mul_matrix[i][i] = 1 '' printlog('mul_matrix:\n', mul_matrix, imp='y', end='\n') return mul_matrix
def calc_k_point_mesh(rprimd, kspacing): """ rprimd (list of lists 3x3 of floats) - vectors of cell (Angstroms) kspacing (float) - required spacing between k-points in reciprocal space (A-1); paramter KSPACING in VASP the provided optimal k-mesh has the smallest sum of squared deviations of kspacings returns k-point mesh (list of int) """ N = [] recip = calc_recip_vectors(rprimd) # print(recip) for i in 0, 1, 2: n = (np.linalg.norm(recip[i])) / kspacing N.append( math.ceil(n) ) N_options = [ng for ng in itertools.product( *[(n-1, n, n+1) for n in N] ) ] errors = [ np.sum( np.square( np.array(calc_kspacings(N, rprimd) ) - kspacing ) ) for N in N_options] # sum of squared deviation from kspacing for each option i_min = np.argmin(errors) N_opt = N_options[i_min] # k-mesh with smallest error printlog('I recommend k-point mesh:', N_opt, 'with k-spacings:', np.array( calc_kspacings(N_opt, rprimd) ).round(2), end = '\n', imp = 'y' ) printlog('Other options are:', end = '\n', imp = 'y' ) printlog('{:13s} | {:20s}'.format('Mesh', 'k-spacings'), end = '\n', imp = 'y' ) for ngkpt in itertools.product( *[(n-1, n, n+1) for n in N_opt] ): printlog('{:13s} | {:26s}'.format(str(ngkpt), str(np.array(calc_kspacings(ngkpt, rprimd) ).round(2))), end = '\n', imp = 'y' ) return N_opt
def determine_voids(st, r_impurity, fine=1, step_dec=0.05): if not r_impurity: printlog('add_neb(): Error!, Please provide *r_impurity* (1.6 A?)') sums = [] avds = [] printlog('Searching for voids', important='y') st_pores = find_pores(st, r_matrix=0.5, r_impurity=r_impurity, step_dec=step_dec, fine=fine, calctype='all_pores') printlog('List of found voids:\n', np.array(st_pores.xcart)) write_xyz(st.add_atoms(st_pores.xcart, 'H'), file_name=st.name + '_possible_positions') write_xyz(st.add_atoms(st_pores.xcart, 'H'), replications=(2, 2, 2), file_name=st.name + '_possible_positions_replicated') for x in st_pores.xcart: # summ = local_surrounding(x, st, n_neighbours = 6, control = 'sum', periodic = True) # avd = local_surrounding(x, st, n_neighbours = 6, control = 'av_dev', periodic = True) summ, avd = local_surrounding2(x, st, n_neighbours=6, control='sum_av_dev', periodic=True) # print (summ, avd) sums.append(summ) avds.append(avd[0]) # print sums = np.array(sums) avds = np.array(avds).round(0) print_and_log( 'Sum of distances to 6 neighboring atoms for each void (A):\n', sums, imp='y') print_and_log('Distortion of voids (0 - is symmetrical):\n', avds, imp='y') return st_pores, sums, avds
def push_to_server(files=None, to=None, addr=None): """ if header.ssh_object then use paramiko to (str) - path to remote folder ! """ if not is_list_like(files): files = [files] to = to.replace('\\', '/') # make sure is POSIX files_str = ' '.join(np.array(files)) command = ' mkdir -p {:}'.format(to) # print('asfsadfdsf', to) printlog('push_to_server():', command, run_on_server(command, addr)) # sys.exit() printlog('push_to_server(): uploading files ', files, 'to', addr, to) if header.ssh_object: for file in files: # print(file, to) header.ssh_object.put(file, to + '/' + os.path.basename(file)) out = '' elif header.sshpass: # if '@' not in addr: # printlog('Error! Please provide address in the form user@address') # l = addr.split('@') # print(l) # user = l[0] # ad = l[1] com = 'rsync --rsh=' + "'sshpass -f /home/aksenov/.ssh/p ssh' " + ' -uaz ' + files_str + ' ' + addr + ':' + to # print(com) # sys.exit() out = runBash(com) else: out = runBash('rsync -uaz ' + files_str + ' ' + addr + ':' + to) printlog(out) return out
def write_lammps(st, filename = '', charges = None): """Writes structure in lammps format charges (list of float) - list of charges for each atom type """ rprimd = st.rprimd xcart = st.xcart xred = st.xred typat = st.typat ntypat = st.ntypat znucl = st.znucl name = st.name natom = st.natom if natom != len(xred) != len(xcart) != len(typat) or len(znucl) != max(typat): print_and_log( "Error! write_xyz: check your structure" ) if name == '': name = 'noname' if xcart == [] or len(xcart) != len(xred): print_and_log( "Warining! write_xyz: len(xcart) != len(xred) making xcart from xred.\n", imp = 'y') xcart = xred2xcart(xred, rprimd) #print xcart[1] if not filename: filename = 'lammps/'+name filename+='.inp' makedir(filename) """Write lammps structure file; """ if 1: """ My version; valid only for octahedral cells""" printlog( "Warining! write_lammps(): this func supports only orthogonal cells", imp = 'Y') with open(filename+'','w') as f: f.write("Lammps format "+name+'\n') f.write(str(natom)+" atoms\n") f.write(str(ntypat)+" atom types\n") f.write("{:10.8f} {:10.8f} xlo xhi\n".format(0, rprimd[0][0])) f.write("{:10.8f} {:10.8f} ylo yhi\n".format(0, rprimd[1][1])) f.write("{:10.8f} {:10.8f} zlo zhi\n".format(0, rprimd[2][2])) f.write("0.00000000 0.00000000 0.00000000 xy xz yz\n") f.write("\nAtoms\n\n") for i, x in enumerate(xcart): f.write("{0:8d} {1:2d}".format(i+1, typat[i])) if charges: f.write(" {:6.3f}".format(charges[typat[i]-1] ) ) f.write(" {:12.6f} {:12.6f} {:12.6f}\n".format(x[0], x[1], x[2] )) f.write("\n") printlog('File', filename, 'was written', imp = 'y') else: """Write poscar and convert from poscar to lammps using external script; Valid for arbitary cells""" cl.write_structure('POSCAR', 'dir', path = 'voronoi_analysis/', state = state) runBash("voronoi_analysis/VASP-poscar2lammps.awk voronoi_analysis/POSCAR > "+filepath) if 0: """Write lammps.in file """ with open('voronoi_analysis/voronoi.in','w') as f: f.write("""units metal atom_style atomic boundary p p p\n""") f.write("read_data /home/aksenov/programs/Simulation_wrapper/siman1/voronoi_analysis/structure.lammps\n") # f.write('lattice custom 1 ') # for i, a in enumerate(rprimd): # f.write(' a'+str(i+1)) # for x in a: # f.write(' '+str(x)) # f.write(' &\n') # for x in xred: # f.write(' basis {0:f} {1:f} {2:f}&\n '.format(x[0], x[1], x[2]) ) # f.write("""\n # region 1 prism 0 1 0 1 0 1 1 0 0 # create_box 1 prism # create_atoms 1 prism""") for i in range(ntypat): f.write('\nmass '+str(i+1)+' '+str(int(znucl[i]))+'\n') f.write('pair_style lj/cut 2.0\n') for i in range(ntypat): for j in range(i, ntypat): f.write('pair_coeff '+str(i+1)+' '+str(j+1)+' 0.0 1.0\n') f.write("""compute v1 all voronoi/atom dump d1 all custom 1 /home/aksenov/programs/Simulation_wrapper/siman1/voronoi_analysis/dump.voro id type x y z c_v1[1] c_v1[2] run 0 uncompute v1\n""") return
def calc_redox(cl1, cl2, energy_ref = None): """ Calculated average redox potential and change of volume cl1 (Calculation) - structure with higher concentration cl2 (Calculation) - structure with lower concentration energy_ref (float) - energy in eV per one alkali ion in anode; default value is for Li; -1.31 eV for Na, -1.02 eV for K """ if cl1 is None or cl2 is None: printlog('cl1 or cl2 is none; return') return energy_ref_dict = {3:-1.9, 11:-1.31, 19:-1.02} z_alk_ions = [3, 11, 19] #normalize numbers of atoms by some element except Li, Na, K alk1l = [] alk2l = [] # print cl1.end.znucl for i, z in enumerate(cl1.end.znucl): # print i, z if z in z_alk_ions: alk1l.append(i) # print 'i_alk is found' continue # print i, z for j, zb in enumerate(cl2.end.znucl): if zb in z_alk_ions: # j_alk = j alk2l.append(j) continue if z == zb: # print "I use ", z, " to normalize" i_n1 = i i_n2 = j n1 = cl1.end.nznucl[i_n1] n2 = cl2.end.nznucl[i_n2] nz1_dict = {} nz2_dict = {} n_alk1 = 0 n_alk2 = 0 for z in z_alk_ions: nz1_dict[z] = 0 nz2_dict[z] = 0 for i in alk1l: nz1_dict[ cl1.end.znucl[i] ] = cl1.end.nznucl[i] for i in alk2l: nz2_dict[ cl2.end.znucl[i] ] = cl2.end.nznucl[i] for z in z_alk_ions: mul = (nz1_dict[z] / n1 - nz2_dict[z] / n2) if abs(mul) > 0: #only change of concentration of one ion type is allowed; the first found is used if not energy_ref: #take energy ref from dict energy_ref = energy_ref_dict[ z ] break # print(energy_ref) # print(cl1.energy_sigma0, cl2.energy_sigma0, mul) if abs(mul) > 0: redox = -( ( cl1.energy_sigma0 / n1 - cl2.energy_sigma0 / n2 ) / mul - energy_ref ) else: redox = 0 dV = cl1.end.vol / n1 - cl2.end.vol / n2 vol_red = dV / (cl1.end.vol/n1) * 100 # % # final_outstring = ("{:} | {:.2f} eV \n1".format(cl1.id[0]+'.'+cl1.id[1], redox )) final_outstring = ("{:30} | {:10.2f} eV | {:10.1f} %".format(cl1.name, redox, vol_red )) printlog( final_outstring, end = '\n', imp = 'y' ) try: cl1.set.update() results_dic = {'is':cl1.id[0], 'redox_pot':redox, 'id_is':cl1.id, 'id_ds':cl2.id, 'kspacing':cl1.set.kspacing, 'time':cl1.time/3600., 'mdstep':cl1.mdstep, 'ecut':cl1.set.ecut, 'niter':cl1.iterat/cl1.mdstep, 'set_is':cl1.id[1], 'vol_red':vol_red } except: results_dic = {} return results_dic
def add_neb(starting_calc = None, st = None, it_new = None, ise_new = None, i_atom_to_move = None, up = 'up1', search_type = 'vacancy_creation', images = 3, r_impurity = None, corenum = 15, calc_method = ['neb'], inherit_option = None, mag_config = None, i_void_start = None, i_void_final = None, atom_to_insert = None, replicate = None, it_new_folder = None, inherit_magmom = False, x_start = None, xr_start = None, x_final = None, xr_final = None, upload_vts = False, run = False ): """ Prepare needed files for NEB Provides several regimes controlled by *search_type* flag: - existing_voids - search for voids around atom and use them as a final position - vacancy_creation - search for neighbors of the same type and make a vacancy as a start position - interstitial_insertion - search for two neighboring voids; use them as start and final positions by inserting atom *atom_to_insert* ###INPUT: - starting_calc (Calculation) - Calculation object with structure - st (Structure) - structure, can be used instead of Calculation - it_new (str) - name for calculation - i_atom_to_move (int) - number of atom for moving; - *mag_config* (int ) - choose magnetic configuration - allows to obtain different localizations of electron - *replicate* (tuple 3*int) - replicate cell along rprimd - i_void_start, i_void_final (int) - number of voids from the suggested lists - atom_to_insert (str) - element name of atom to insert - it_new_folder (str) - section folder - inherit_option (str) - passed only to add_loop - inherit_magmom (bool) - if True than magmom from starting_calc is used, else from set - calc_method (list) - 'neb' - 'only_neb' - run only footer - x_start, x_final (array) - explicit coordinates of moving atom for starting and final positions, combined with atom_to_insert - upload_vts (bool) - if True upload Vasp.pm and nebmake.pl to server - run (bool) - run on server ###RETURN: None ###DEPENDS: ###TODO please take care of manually provided i_atom_to_move in case of replicate flag using init_numbers """ calc = header.calc struct_des = header.struct_des varset = header.varset if not hasattr(calc_method, '__iter__'): calc_method = [calc_method] if starting_calc and st: printlog('Warning! both *starting_calc* and *st* are provided. I use *starting_calc*') st = copy.deepcopy(starting_calc.end) elif starting_calc: st = copy.deepcopy(starting_calc.end) printlog('I use *starting_calc*') elif st: '' printlog('I use *st*') else: printlog('Error! no input structure. Use either *starting_calc* or *st*') if corenum: # header.corenum = corenum '' else: corenum = header.CORENUM if corenum % images > 0: print_and_log('Error! Number of cores should be dividable by number of IMAGES') name_suffix = '' st_pores = [] name_suffix+='n'+str(images) """Replicate cell """ if replicate: print_and_log('You have chosen to replicate the structure by', replicate) st = replic(st, mul = replicate) name_suffix += str(replicate[0])+str(replicate[1])+str(replicate[2]) """1. Choose atom (or insert) for moving """ atoms_to_move = [] for i, typ, x in zip(range(st.natom), st.typat, st.xcart): #try to find automatically if st.znucl[typ-1] == 3: #Li atoms_to_move.append([i, 'Li', x]) if st.znucl[typ-1] == 11: # atoms_to_move.append([i, 'Na', x]) if st.znucl[typ-1] == 19: # atoms_to_move.append([i, 'K', x]) if is_list_like(xr_start): x_start = xred2xcart([xr_start], st.rprimd)[0] st1 = st.add_atoms([x_start], atom_to_insert) x_m = x_start name_suffix+='s' write_xyz(st1, file_name = st.name+'_manually_start') printlog('Start position is created manually by adding xr_start', xr_start, x_start) elif not atoms_to_move: print_and_log('No atoms to move found, you probably gave me intercalated structure', important = 'y') print_and_log('Searching for voids', important = 'y') st_pores = find_pores(st, r_matrix = 0.5, r_impurity = r_impurity, fine = 1, calctype = 'all_pores') print_and_log('List of found voids:\n', np.array(st_pores.xcart) ) write_xyz(st.add_atoms(st_pores.xcart, 'H'), file_name = st.name+'_possible_positions') write_xyz(st.add_atoms(st_pores.xcart, 'H'), replications = (2,2,2), file_name = st.name+'_possible_positions_replicated') sums = [] avds = [] for x in st_pores.xcart: summ = local_surrounding(x, st, n_neighbours = 6, control = 'sum', periodic = True) avd = local_surrounding(x, st, n_neighbours = 6, control = 'av_dev', periodic = True) # print sur, sums.append(summ) avds.append(avd[0]) # print sums = np.array(sums) avds = np.array(avds).round(0) print_and_log('Sum of distances to 6 neighboring atoms for each void (A):\n', sums, imp ='y') print_and_log('Distortion of voids (0 - is symmetrical):\n', avds, imp ='y') crude_prec = 1 sums_crude = np.unique(sums.round(crude_prec)) print_and_log('The unique voids based on the sums:', '\nwith 0.01 A prec:',np.unique(sums.round(2)), '\nwith 0.1 A prec:',sums_crude, imp ='y') print_and_log('Based on crude criteria only', len(sums_crude),'types of void are relevant') print_and_log('Please use *i_void_start* to choose the void for atom insertion from this Table:', end = '\n', imp = 'Y') insert_positions = [] start_table = [] for i, s in enumerate(sums_crude): index_of_first = np.where(sums.round(crude_prec)==s)[0][0] start_table.append([i, st_pores.xcart[index_of_first].round(2), index_of_first, avds[index_of_first], sums[index_of_first] ]) insert_positions.append( st_pores.xcart[index_of_first] ) print_and_log( tabulate(start_table, headers = ['Start void #', 'Cart.', 'Index', 'Dev.', 'Sum'], tablefmt='psql'), imp = 'Y' ) if i_void_start == None: sys.exit() st = st.add_atoms([insert_positions[i_void_start],], atom_to_insert) name_suffix+='i'+str(i_void_start) i_m = st.natom-1 x_m = st.xcart[i_m] search_type = 'existing_voids' type_atom_to_move = atom_to_insert el_num_suffix = '' else: print_and_log('I have found', len(atoms_to_move), ' anion atoms', important = 'n') print_and_log( 'Sums of bond lengths around these atoms:',) sums = [] for a in atoms_to_move: summ = local_surrounding(a[2], st, n_neighbours = 6, control = 'sum', periodic = True) sums.append(summ) # print( summ, end = '') print_and_log('\nAmong them only',len(set(sums)), 'unique' , important = 'n') # if print_and_log('Choosing the first' , important = 'n') type_atom_to_move = atoms_to_move[0][1] i_atom_to_move = atoms_to_move[0][0]+1 el_num_suffix = type_atom_to_move +str(i_atom_to_move) i_m = i_atom_to_move-1 x_m = st.xcart[i_m] #highlight the moving atom for user for double-check # st_new = st.change_atom_z(i_m, new_z = 100) # search_type = 'vacancy_creation' """2. Choose final position""" if is_list_like(xr_final): x_final = xred2xcart([xr_final], st.rprimd)[0] st2 = st.add_atoms([x_final], atom_to_insert) x_del = x_final search_type = 'manual_insertion' name_suffix+='f'+atom_to_insert write_xyz(st2, file_name = st.name+'_manually_final') printlog('Final position is created manually by adding xr_final', xr_final, x_del) elif search_type == 'existing_voids': #Search for voids around choosen atoms if not st_pores: st_pores = find_pores(st, r_matrix = 0.5, r_impurity = r_impurity, fine = 2, calctype = 'all_pores') sur = local_surrounding(x_m, st_pores, n_neighbours = len(st_pores.xcart), control = 'atoms', periodic = True) # print sur print_and_log( 'I can suggest you '+str (len(sur[0])-1 )+' end positions.' ) # The distances to them are : '+str(np.round(sur[3], 2) )+' A\n ', # 'Openning Jmol end positions are highlighted by inserting H ', important = 'y') # print x_m # print sur[0] print_and_log('Please choose *i_void_final* from the following Table:', end = '\n', imp = 'Y') final_table = [] for i, (x, d, ind) in enumerate( zip(sur[0], sur[3], sur[2])[1:] ): final_table.append([i, np.array(x).round(2), round(d, 2), avds[ind], sums[ind] ] ) print_and_log( tabulate(final_table, headers = ['Final void #', 'Cart.', 'Dist', 'Dev.', 'Sum'], tablefmt='psql'), imp = 'Y' ) if i_void_final == None: sys.exit() x_final = sur[0][i_void_final+1] # +1 because first element is x_m atom itself write_xyz(st.add_atoms([ x_final], 'H'), replications = (2,2,2), file_name = st.name+'_possible_positions2_replicated') # sys.exit() # write_xyz(st.add_atoms(sur[0][2:3], 'H'), analysis = 'imp_surrounding', show_around = 230,nnumber = 10, replications = (2,2,2), file_name = 'local230') # # write_xyz(st.add_atoms(sur[0][0:1], 'H'), analysis = 'imp_surrounding', show_around = 226,nnumber = 10, replications = (2,2,2), file_name = 'local') # run_jmol print_and_log('Choosing the closest position as end', important = 'n') # i_void_final = 0 st1 = st # print st1.natom # sys.exit() st2 = st.mov_atoms(i_m, x_final) name_suffix += el_num_suffix+'e'+str(i_void_final)+atom_to_insert st1 = return_atoms_to_cell(st1) st2 = return_atoms_to_cell(st2) write_xyz(st1, file_name = st1.name+name_suffix +'_start') write_xyz(st2, file_name = st2.name+name_suffix +'_final') elif search_type == 'vacancy_creation': #Create vacancy by removing some neibouring atom of the same type print_and_log('You have chosen vacancy_creation mode of add_neb tool', important = 'Y') print_and_log( 'Type of atom to move = ', type_atom_to_move, imp = 'y') # print 'List of left atoms = ', np.array(st.leave_only(type_atom_to_move).xcart) sur = local_surrounding(x_m, st.leave_only(type_atom_to_move) , n_neighbours = 4, control = 'atoms', periodic = False) # print 'xcart of moving atom', x_m # print 'Local surround = ', sur # print 'len', len(sur[0]) if len(sur[0]) < 3: # print 'rprimd = \n',np.array(st.rprimd) # print 'r lengths = \n',( [np.linalg.norm(r) for r in st.rprimd] ) # print 'xred = \n', np.array(st.xred) # print 'xcart = \n', np.array(st.xcart) print_and_log('The supercell is too small, I increase it 8 times!') st = replic(st, mul = (2,2,2) ) sur = local_surrounding(x_m, st.leave_only(type_atom_to_move) , n_neighbours = 4, control = 'atoms', periodic = False) # print 'xcart of moving atom', x_m write_xyz(st, file_name = st.name+'_replicated')#replications = (2,2,2)) # print 'Local surround = ', sur # sys.exit() print_and_log( 'I can suggest you '+str (len(sur[0]) )+' end positions. The distances to them are : '+str(np.round(sur[3], 2) )+' A\n ', 'They are all', type_atom_to_move, 'atoms', important = 'y') print_and_log('Choosing the closest position as end', important = 'n') neb_config = 1 #cause the first item in sur is moving atom itself x_del = sur[0][neb_config] i_del = st.find_atom_num_by_xcart(x_del) print_and_log('Making vacancy at end position for starting configuration', important = 'n') print_and_log( 'number of atom to delete = ', i_del) # print st.magmom st1 = st.del_atom(i_del) # print st1.magmom print_and_log('Making vacancy at start position for final configuration', important = 'n') st2 = st.mov_atoms(i_m, x_del) # i_m and sur[0][neb_config] should coincide st2 = st2.del_atom(i_del) # these two steps provide the same order name_suffix += el_num_suffix+'v'+str(neb_config) write_xyz(st1, file_name = st1.name+'_start')# replications = (2,2,2)) write_xyz(st2, file_name = st2.name+'_end')# replications = (2,2,2)) # sys.exit() # sys.exit() """ Determining magnetic moments """ if varset[ise_new].vasp_params['ISPIN'] == 2: print_and_log('Magnetic calculation detected. Preparing spin modifications ...', imp = 'y') cl_test = CalculationVasp(varset[ise_new]) cl_test.init = st1 # print 'asdfsdfasdfsadfsadf', st1.magmom if inherit_magmom and hasattr(st, 'magmom') and st.magmom and any(st.magmom): print_and_log('inherit_magmom=True: You have chosen MAGMOM from provided structure', imp = 'y') name_suffix+='mp' #Magmom from Previous else: cl_test.init.magmom = None print_and_log('inherit_magmom=False or no magmom in input structure : MAGMOM will be determined from set', imp = 'y') name_suffix+='ms' #Magmom from Set cl_test.actualize_set() #find magmom for current structure st1.magmom = copy.deepcopy(cl_test.init.magmom) st2.magmom = copy.deepcopy(cl_test.init.magmom) # sys.exit() # print_and_log('The magnetic moments from set:') # print cl_test.init.magmom #checking for closest atoms now only for Fe, Mn, Ni, Co sur = local_surrounding(x_m, st1, n_neighbours = 3, control = 'atoms', periodic = True, only_elements = header.TRANSITION_ELEMENTS) dist = np.array(sur[3]).round(2) numb = np.array(sur[2]) a = zip(numb, dist ) # a= np.array(a) # print a[1] # a = np.apply_along_axis(np.unique, 1, a) # print a def unique_by_key(elements, key=None): if key is None: # no key: the whole element must be unique key = lambda e: e return list ( {key(el): el for el in elements}.values() ) # print a mag_atoms_dists = unique_by_key(a, key=itemgetter(1)) # print (mag_atoms_dists) # a = unique_by_key(a, key=itemgetter(1)) print_and_log( 'I change spin for the following atoms:\ni atom dist\n', np.round(mag_atoms_dists, 2) , imp = 'y' ) # print 'I have found closest Fe atoms' muls = [(1.2, 0.6), (0.6, 1.2)] mag_moments_variants = [] for mm in muls: mags = copy.deepcopy(cl_test.init.magmom) # print mags for a, m in zip(mag_atoms_dists, mm): # print t[1] mags[a[0]] = mags[a[0]]*m mag_moments_variants.append(mags) print_and_log( 'The list of possible mag_moments:', imp = 'y' ) for i, mag in enumerate(mag_moments_variants): print_and_log( i, mag) print_and_log( 'Please use *mag_config* arg to choose desired config' , imp = 'y' ) if mag_config != None: st1.magmom = copy.deepcopy(mag_moments_variants[mag_config]) st2.magmom = copy.deepcopy(mag_moments_variants[mag_config]) name_suffix+='m'+str(mag_config) print_and_log('You have chosen mag configuration #',mag_config,imp = 'y') else: print_and_log('Non-magnetic calculation continue ...') """3. Add to struct_des, create geo files, check set, add_loop """ if starting_calc: it = starting_calc.id[0] it_new = it+'v'+str(starting_calc.id[2])+'.'+name_suffix if not it_new_folder: it_new_folder = struct_des[it].sfolder+'/neb/' obtained_from = str(starting_calc.id) if not ise_new: print_and_log('I will run add_loop() using the same set', important = 'Y') ise_new = cl.id[1] elif st: if not it_new: printlog('Error! please provide *it_new* - name for your calculation', important = 'Y') it = None it_new+='.'+name_suffix obtained_from = st.name if not ise_new: printlog('Error! please provide *ise_new*', important = 'Y') if not it_new_folder: printlog('Error! please provide *it_new_folder* - folder for your new calculation', important = 'Y') if it_new not in struct_des: add_des(struct_des, it_new, it_new_folder, 'Automatically created and added from '+obtained_from ) print_and_log('Creating geo files for starting and final configurations (versions 1 and 2) ', important = 'y') # if starting_calc: # cl = copy.deepcopy(starting_calc) # else: cl = CalculationVasp() #write start position struct_des[it_new].x_m_ion_start = x_m struct_des[it_new].xr_m_ion_start = xcart2xred([x_m], st1.rprimd)[0] cl.end = st1 ver_new = 1 cl.version = ver_new cl.path["input_geo"] = header.geo_folder + struct_des[it_new].sfolder + '/' + \ it_new+"/"+it_new+'.auto_created_starting_position_for_neb_'+search_type+'.'+str(ver_new)+'.'+'geo' cl.write_siman_geo(geotype = 'end', description = 'Starting conf. for neb from '+obtained_from, override = True) #write final position struct_des[it_new].x_m_ion_final = x_del struct_des[it_new].xr_m_ion_final = xcart2xred([x_del], st2.rprimd)[0] cl.end = st2 ver_new = 2 cl.version = ver_new cl.path["input_geo"] = header.geo_folder + struct_des[it_new].sfolder + '/' + \ it_new+"/"+it_new+'.auto_created_final_position_for_neb_'+search_type+'.'+str(ver_new)+'.'+'geo' cl.write_siman_geo(geotype = 'end', description = 'Final conf. for neb from '+obtained_from, override = True) #prepare calculations #Check if nebmake is avail # if int(runBash('ssh '+cluster_address+' test -e '+project_path_cluster+'/tools/vts/nebmake.pl; echo $?') ): # '' # print_and_log('Please upload vtsttools to ',cluster_address, project_path_cluster+'/tools/vts/') # raise RuntimeError # copy_to_server(path_to_wrapper+'/vtstscripts/nebmake.pl', to = project_path_cluster+'/tools/', addr = cluster_address) # if int(runBash('ssh '+cluster_address+' test -e '+project_path_cluster+'/tools/Vasp.pm; echo $?') ): # copy_to_server(path_to_wrapper+'/vtstscripts/Vasp.pm', to = project_path_cluster+'/tools/', addr = cluster_address) inherit_ngkpt(it_new, it, varset[ise_new]) add_loop(it_new, ise_new, verlist = [1,2], up = up, calc_method = calc_method, savefile = 'ov', inherit_option = inherit_option, n_neb_images = images, corenum = corenum, run =run ) if upload_vts: siman_dir = os.path.dirname(__file__) # print(upload_vts) push_to_server([siman_dir+'/cluster_tools/nebmake.pl', siman_dir+'/cluster_tools/Vasp.pm'], to = header.cluster_home+'/tools/vts', addr = header.cluster_address) else: print_and_log('Please be sure that vtsttools are at',header.cluster_address, header.cluster_home+'/tools/vts/', imp = 'Y') return it_new
def create_antisite_defect2(st_base, st_from, cation = None, trans = None, trans_pos = 1, mode = None): """ exchange cation and transition metal st_base (Structure) - basic structure in which defects are created st_from (Structure) - structure from which the positions of *cation* are chosen; st_from should be consistent with st_base cation (str) - element, position of which is extracted from st_from and added to st_base trans (str) - element name transition metal for exchange trans_pos (int) - number of non-equiv position of trans starting from 1 mode - 'add_alk' or 'a1' - add alkali cation 'mov_trs' or 'a2' - mov trans to alkali pos 'add_swp' or 'a3' - add alk and swap with trans """ printlog('create_antisite_defect2(): mode = ', mode, imp = 'y') st = st_base cation_xred = st_from.get_element_xred(cation) printlog('For cation ', cation, 'reduced coordinates:',cation_xred, ' were chosen', imp = 'y') positions = determine_symmetry_positions(st_from, trans) printlog('Transition atom ', trans, 'has ', len(positions), 'non-equiv positions', imp = 'y') transition_numbers = positions[trans_pos -1] #1. Insert cation cation_xcart = xred2xcart([cation_xred], st.rprimd)[0] st_i = st.add_atoms([cation_xcart], cation) st_i.write_xyz(filename = st.name+'_'+cation+'_added') #2. Find transition metal atoms close to cation_xcart and move it here sur = local_surrounding(cation_xcart, st, n_neighbours = 1, control = 'atoms', only_numbers = transition_numbers, periodic = True) i_trans = sur[2][0] x_trans = sur[0][0] st_m = st.mov_atoms(sur[2][0], cation_xcart) st_m.write_xyz(filename = st.name+'_trans_moved') #3. Put cation to empty trans metal pos st_s = st_m.add_atoms([x_trans], cation) st_s.write_xyz(filename = st.name+'_swapped') if 'add_alk' in mode or 'a1' in mode: st = st_i elif 'mov_trs' in mode or 'a2' in mode: st = st_m elif 'add_swp' in mode or 'a3' in mode: st = st_s st.magmom = [None] return st
def plot_dos(cl1, cl2 = None, dostype = None, iatom = 0, orbitals = ('s'), up = None, neighbors = 6, show = 1, path = 'dos', xlim = (None, None), ylim = (None,None) ): """ cl1 (CalculationVasp) - object created by add_loop() dostype (str) - control which dos to plot: 'total' - plot total dos 'diff_total' - difference of total dos, use cl2 for second calculation 'partial' - partial dos orbitals (list of str) - any from 's, p, d, py, pz, px, dxy, dyz, dz2, dxz, dx2' where 'p' and 'd' are sums of projections up - 'up2' allows to download the file once again iatom (int) - number of atom starting from 1 to plot DOS by default it is assumed that the last atom is used iatom ([float]*3) - cartesian coordinates of point around which atoms will be found show (bool) - whether to show the dos path (str) - path to folder with images neighbors - number of neighbours around iatom to plot dos on them xlim, ylim (tuple)- limits for plot #0 s 1 py 2 pz 3 px 4 dxy 5 dyz 6 dz2 7 dxz 8 dx2 #In all cases, the units of the l- and site projected DOS are states/atom/energy. """ iatom -= 1 """1. Read dos""" printlog("------Start plot_dos()-----", imp = 'Y') dos = [] for cl in cl1, cl2: if cl == None: continue if not hasattr(cl, "efermi"): cl.read_results('o') printlog(cl.name, 'e_fermi', cl.efermi, imp = 'Y') DOSCAR = cl.get_file('DOSCAR', update = up); printlog('DOSCAR file is ', DOSCAR) dos.append( VaspDos(DOSCAR, cl.efermi) ) #determine number of zero energy i_efermi = int(len(dos[0].energy) * -dos[0].energy[0] / (dos[0].energy[-1] - dos[0].energy[0])) # number of point with zero fermi energy if cl2: i_efermi_e = int(len(dos[1].energy) * -dos[1].energy[0] / (dos[1].energy[-1] - dos[1].energy[0])) # number of point with zero fermi energy """2. Plot dos for different cases""" if dostype == 'total': fit_and_plot(show = show, image_name = os.path.join(path, cl1.name+'.dosTotal'), xlabel = "Energy (eV)", ylabel = "DOS (states/eV)", xlim = xlim, ylim = ylim, Total = (dos[0].energy, smoother(dos[0].dos, 10), 'b-')) elif dostype == 'diff_total': if len(dos) > 1: #calculate dos diff dosd = [(d0 - d1)*e for d0, d1, e in zip(dos[0].dos, dos[1].dos, dos[0].energy)] #calculate difference area = trapz(dosd[:i_efermi], dx=1) printlog("area under dos difference = ", -area, imp = 'Y') fit_and_plot(show = show,image_name = cl1.name+'--'+cl2.name+'.dosTotal_Diff', xlabel = "Energy (eV)", ylabel = "DOS (states/eV)", xlim = xlim, ylim = ylim, Diff_Total = (dos[0].energy, smoother(dosd, 15), 'b-')) else: printlog('You provided only one calculation; could not use diff_total') elif 'partial' in dostype: #Partial dos #1 p carbon, d Ti #0 s 1 py 2 pz 3 px 4 dxy 5 dyz 6 dz2 7 dxz 8 dx2 try: dos[0].site_dos(0, 4) except: printlog('Error! No information about partial dxy dos in DOSCAR; use LORBIT 12 to calculate it') """Determine neighbouring atoms """ printlog("Number of considered neighbors is ", neighbors) if type(iatom) == int: #for the cases when we need to build surrounding around specific atom in this calculation - just use number of atom t = cl1.end.typat[iatom] z = cl1.end.znucl[t-1] el = element_name_inv(z) printlog('Typat of chosen imp atom in cl1 is ', el) surround_center = cl1.end.xcart[iatom] else: #for the case when coordinates of arbitary point are provided. surround_center = iatom el = 'undef' local_atoms = local_surrounding(surround_center, cl1.end, neighbors, control = 'atoms', periodic = True) numbers = local_atoms[2] # first atom is impurity if exist printlog("Numbers of local atoms:", [n+1 for n in numbers] ) printlog("List of distances", [round(d,2) for d in local_atoms[3]] ) iX = numbers[0] for j in range(len(dos)): dos[j].p = [] #central and and surrounding dos[j].d = [] #central atom and surrounding atoms dos[j].d6 = 0 #sum by six atoms for i in numbers: #Now for surrounding atoms in numbers list: plist = [dos[j].site_dos(i, l) for l in (1,2,3) ] dos[j].p.append( [ sum(x) for x in zip(*plist) ] ) dlist = [dos[j].site_dos(i, l) for l in (4,5,6,7,8) ] # For total d T96C dsum = [ sum(x) for x in zip(*dlist) ] dos[j].d.append( dsum ) dos[j].p6 = [ sum(pi) for pi in zip(*dos[j].p) ] #sum over neighbouring atoms dos[j].d6 = [ sum(di) for di in zip(*dos[j].d) ] #sum over neighbouring atoms # t2g = [dos[0].site_dos(iTi, l) for l in 4,5,7] # Now only for first Ti atom # dos[0].t2g = [ sum(x) for x in zip(*t2g) ] # eg = [dos[0].site_dos(iTi, l) for l in 8, 6] # Now only for first Ti atom # dos[0].eg = [ sum(x) for x in zip(*eg) ] """Plotting""" nsmooth = 15 # smooth of dos d1 = dos[0] energy1 = dos[0].energy args = {} i_orb = {'s':0, 'py':1, 'pz':2, 'px':3, 'dxy':4, 'dyz':5, 'dz2':6, 'dxz':7, 'dx2':8} color = {'s':'k-', 'p':'g-', 'd':'b-', 'py':'r-', 'pz':'b-', 'px':'c-', 'dxy':'m-', 'dyz':'c-', 'dz2':'m-', 'dxz':'r-', 'dx2':'g-'} for orb in orbitals: if orb == 'p': args[orb] = (d1.energy, smoother(d1.p[0], nsmooth), color[orb]) elif orb == 'd': args[orb] = (d1.energy, smoother(d1.d[0], nsmooth), color[orb]) else: args[orb] = (d1.energy, smoother(d1.site_dos(iX, i_orb[orb]), nsmooth), color[orb]) image_name = os.path.join(path, cl1.name+'.'+''.join(orbitals)+'.'+el+str(iX)) fit_and_plot(show = show, image_name = image_name, figsize = (4,6), xlabel = "Energy (eV)", ylabel = "DOS (states/eV)", # title = cl1.name.split('.')[0]+'; V='+str(round(cl1.vol) )+' $\AA^3$; Impurity: '+el, xlim = xlim, ylim = ylim, legend = 2, **args ) # printlog("Writing file", image_name, imp = 'Y') """Additional dos analysis; to be refined""" if 0: """Calculate d DOS at Fermi level""" nn = 50 #number to integrate in both directions x1 = dos[0].energy[i_efermi-nn:i_efermi+nn] y1 = smoother(dos[0].d6, nsmooth)[i_efermi-nn:i_efermi+nn] x2 = dos[1].energy[i_efermi_e-nn:i_efermi_e+nn] y2 = smoother(dos[1].d6, nsmooth)[i_efermi_e-nn:i_efermi_e+nn] f1 = interp1d(x1, y1, kind='cubic') f2 = interp1d(x2, y2, kind='cubic') # if debug: print '\n' # if debug: print dos[0].d6[i_efermi] - dos[1].d6[i_efermi_e], " - by points; change of d Ti DOS at the Fermi level due to the carbon" # if debug: print f2(0), f1(0) e_at_Ef_shift = f1(0) - f2(0) printlog("{:5.2f} reduction of d dos at Fermi level; smoothed and interpolated".format( e_at_Ef_shift ), imp = 'Y' ) if 0: """Calculate second derivative of d at the Fermi level""" # tck1 = interpolate.splrep(x1, y1, s=0) # tck2 = interpolate.splrep(x2, y2, s=0) # e_at_Ef_shift_spline = interpolate.splev(0, tck1, der=0) - interpolate.splev(0, tck2, der=0) # if debug: print "{:5.2f} smoothed and interpolated from spline".format( e_at_Ef_shift_spline ) # # if debug: print type(interpolate.splev(0, tck1, der=2)) # if debug: print "{:5.2f} {:5.2f} gb and bulk second derivative at Fermi from spline".format( float(interpolate.splev(0, tck1, der=2)), float(interpolate.splev(0, tck2, der=2)) ) if 0: """Calculate shift of d orbitals after adding impurity""" d_shift = det_gravity(dos[0], Erange = (-2.8, 0)) - det_gravity(dos[1], Erange = (-2.8, 0) ) #negative means impurity shifts states to negative energies, which is favourable printlog( "{:5.2f} Shift of Ti d center of gravity".format( d_shift ), imp = 'Y' ) # if debug: print det_gravity(dos[0], Erange = (-2.8, 0)), det_gravity(dos[1], Erange = (-2.8, 0)) """Calculate correlation between imp p and matrix d""" def rmsdiff(a, b): # rms difference of vectors a and b: #Root-mean-square deviation rmsdiff = 0 for (x, y) in zip(a, b): rmsdiff += (x - y) ** 2 # NOTE: overflow danger if the vectors are long! return math.sqrt(rmsdiff / min(len(a), len(b))) pd_drms = 1/rmsdiff(dos[0].p, dos[0].d6) # the higher the number the higher hybridization printlog("{:5.2f} p-d hybridization estimate".format( pd_drms ) , imp = 'Y') # if debug: print "sqeuclidean", sqeuclidean(dos[0].p, dos[0].d6)/len(dos[0].d6) # if debug: print "pearsonr", pearsonr(dos[0].p, dos[0].d6) #Pearson correlation coefficient; only shape; the larger number means more similarity in shape # def autocorr(x): # result = np.correlate(x, x, mode='full') # return result[result.size/2:] printlog("------End plot_dos()-----\n\n") return {'name':cl1.name}
def write_xyz(st, path = None, repeat = 1, shift = 1.0, gbpos2 = None, gbwidth = 1 , imp_positions = [], specialcommand = None, analysis = None, show_around = None, replications = None, nnumber = 6, topview = True, filename = None, file_name = None, full_cell = False, orientation = None, boundbox = 2, withgb = False, include_boundary = 2, rotate = None, imp_sub_positions = None, jmol = None, show_around_x = None, ): """Writes st structure in xyz format in the folder xyz/path if repeat == 2: produces jmol script shift - in rprimd[1][1] - shift of the second view gbpos2 - position of grain boundary in A gbwidth - atoms aroung gbpos2 will be colored differently imp_positions - type and xcart coordinates additionally to be added to structure; to visulaze all impurity positions: for jmol imp_sub_positions - list of atom numbers; the typat of these atoms is changed: not used now specialcommand - any command at the end of script analysis - additional processing, allows to show only specifice atoms, 'imp_surrounding' - shows Ti atoms only around impurity nnumber - number of neighbours to show show_around - choose atom number around which to show show_around_x - show atoms around point, has higher priority replications - list of replications, (2,2,2) full_cell - returns atoms to cell and replicate boundary atoms jmol - 1,0 - allow to use jmol """ if replications: st = replic(st, mul = replications, inv = 1 ) def update_var(): return st.rprimd, st.xcart, st.xred, st.typat, st.znucl, len(st.xred) rprimd, xcart, xred, typat, znucl, natom = update_var() if file_name: name = file_name elif filename: name = filename else: name = st.name if natom != len(xred) != len(xcart) != len(typat) or len(znucl) != max(typat): print_and_log( "Error! write_xyz: check your arrays.\n\n" ) # print st.natom, len(st.xred), len(st.xcart), len(st.typat), len(st.znucl), max(st.typat) print_and_log("write_xyz(): Name is", name, important = 'n') if name == '': name = 'noname' if xcart == [] or len(xcart) != len(xred): print_and_log( "Warining! write_xyz: len(xcart) != len(xred) making xcart from xred.\n") xcart = xred2xcart(xred, rprimd) #print xcart[1] if path: basepath = path else: basepath = 'xyz/' xyzfile = os.path.join(basepath, name+".xyz") makedir(xyzfile) """Processing section""" if analysis == 'imp_surrounding': lxcart = [] ltypat = [] i=0 for t, x in zip(typat, xcart): condition = False # print show_around, 'show' if show_around: # print i, condition condition = (i + 1 == show_around) # print i, condition else: condition = (t > 1) # compat with prev behav # print 'se', condition if condition: # lxcart.append(x) # ltypat.append(t) # print x, ' x' x_t = local_surrounding(x, st, nnumber, control = 'atoms', periodic = True) # print x_t[1] lxcart+=x_t[0] ltypat+=x_t[1] i+=1 if show_around_x: x = show_around_x x_t = local_surrounding(x, st, nnumber, control = 'atoms', periodic = True) # print x_t[1] lxcart+=x_t[0] ltypat+=x_t[1] xcart = lxcart typat = ltypat natom = len(typat) # print natom, 'nat' """Include atoms on the edge of cell""" if full_cell: # print xred # print natom # st = return_atoms_to_cell(st) # print xred st = replic(st, mul = (1,1,2), inv = 0, cut_one_cell = 1, include_boundary = include_boundary) # print natom, st.natom # print st.xred rprimd, xcart, xred, typat, znucl, natom = update_var() # asdegf """Writing section""" # print_and_log("Writing xyz: "+xyzfile, imp = 'y') #analyze imp_positions if imp_sub_positions == None: imp_sub_positions = [] nsub = 0 for pos in imp_positions: if 's' not in pos[4]: continue # skip interstitial positions xs = np.asarray([pos[0],pos[1],pos[2]]) nsub+=1 # print xs for i, x in enumerate(xcart): # print np.linalg.norm( x-xs) if np.linalg.norm( x-xs) < 1: imp_sub_positions.append(i) if imp_sub_positions : print_and_log( imp_sub_positions, ': numbers of found atoms to be changed ' ) # for i in sorted(indices, reverse=True): # del somelist[i] with open(xyzfile,'w') as f: for i in range(repeat): f.write(str(natom + len(imp_positions)-nsub + 3)+"\n") #+3 vectors f.write(name+"\n") if imp_positions: for i, el in enumerate(imp_positions): # if len(el) != 4: continue f.write( "%s %.5f %.5f %.5f \n"%( el[3], el[0], el[1], el[2] ) ) # print 'composite -pointsize 60 label:{0:d} -geometry +{1:d}+{2:d} 1.png 2.png'.format(i, el[0], el[1]) for i in range(natom): typ = typat[i] - 1 z = int ( znucl[ typ ] ) if i in imp_sub_positions: # f.write( "Be " ) continue else: el = element_name_inv(z) f.write( el+" " ) f.write( "%.5f %.5f %.5f \n"%( xcart[i][0], xcart[i][1], xcart[i][2] ) ) for r in st.rprimd: f.write('Tv {:.10f} {:.10f} {:.10f}\n'.format(*r) ) # os._exit(1) printlog('File', xyzfile, 'was written', imp = 'y') if jmol: """ script mode for jmol. Create script file as well for elobarate visualization """ """Choose gb atoms to change their color""" print_and_log( 'position of boundary 2', gbpos2) atomselection = '' #create consistent xcart_new list like it will be in Jmol xcart_new = [] for i, x in enumerate(xcart): if i in imp_sub_positions: continue xcart_new.append(x) if gbpos2: gbpos1 = gbpos2 - rprimd[0][0]/2. gbatoms = [] for i, x in enumerate(xcart_new): # print i # if x[0] > gbpos1 - gbwidth/2. and x[0] < gbpos1 + gbwidth/2.: if abs(x[0] - gbpos1) < gbwidth/2.: gbatoms.append(i) # print i, x[0], abs(x[0] - gbpos1) if abs(x[0] - gbpos2) < gbwidth/2.: # if x[0] > gbpos2 - gbwidth/2. and x[0] < gbpos2 + gbwidth/2.: # print i, x[0], abs(x[0] - gbpos2) gbatoms.append(i) print_and_log( 'Atoms at GB:', gbatoms) atomselection = '' for i in gbatoms: atomselection +='Ti'+str(i+1+len(imp_positions))+',' atomselection = atomselection[:-1] # elif withgb: # color half of cell # else: # color half of cell # # pass # atomselection = 'atomno>'+str(0+len(imp_positions) )+' and atomno<'+str(( natom + len(imp_positions) )/2-1) xyzfile = os.getcwd()+'/'+xyzfile scriptfile = basepath+name+".jmol" pngfile = os.getcwd()+'/'+basepath+name+".png" print_and_log( 'imp_positions = ',imp_positions) write_jmol(xyzfile, pngfile, scriptfile, atomselection, topview = topview, rprimd =rprimd, shift = shift, label = [(pos[3], pos[4]) for pos in imp_positions], specialcommand = specialcommand, orientation = orientation, boundbox =boundbox, rotate = rotate) return
def write_database(calc = None, conv = None, varset = None, size_on_start = None): """ The function writes main dictionaries to database file calc.s Also creates copy of calc.s INPUT: calc - dict, contains all calculations of the project conv - dict, convergence sequences varset - dict, parameter sets of the project size_on_start - not used now RETURN: None """ #size_on_finish = sys.getsizeof(dbase) #if size_on_finish != size_on_start: # runBash("cp calc.s calc_copy.s") #create copy before writing databasefile3 = 'calc.gdbm3' # if header.RAMDISK: # databasefile3 = header.RAMDISK+databasefile3 # shutil.copyfile(databasefile3, 'calc_copy.gdbm3') if 0: d = shelve.open('calc.s', protocol=1) #Write database of calculations d[calc_key] = calc d[conv_key] = conv d[varset_key] = varset d[history_key] = header.history d[struct_des_key] = header.struct_des d.close() python2 = False if python2: import gdbm# use in python2 d = shelve.Shelf(gdbm.open('calc.gdbm', 'c'), protocol=1) #Write dbm database for python3 d[unicode(calc_key)] = calc d[unicode(conv_key)] = conv d[unicode(varset_key)] = varset d[unicode(history_key)] = header.history d[unicode(struct_des_key)] = header.struct_des d.close() else: #python3 import dbm # d = shelve.Shelf(dbm.open('calc.gdbm', 'c'), protocol=1) #Write dbm database for python3 # d[calc_key] = calc # d[conv_key] = conv # d[varset_key] = varset # d[history_key] = header.history # d[struct_des_key] = header.struct_des # d.close() d = shelve.Shelf(dbm.open(databasefile3, 'n'), protocol = 3) #Write dbm database for python3 # d[calc_key] = calc d[conv_key] = header.conv d[varset_key] = header.varset d[history_key] = header.history d[struct_des_key] = header.struct_des d.close() with shelve.Shelf(dbm.open(header.calc_database, 'w'), protocol = 3) as d: for key in header.calc: d[str(key)] = header.calc[key] # with dbm.open(header.calc_database, 'w') as d: # d.reorganize() printlog("\nEnd of work at "+str(datetime.datetime.now())+'\n') try: header.log.close() except: pass #Update history file with open('history','w') as his: #print history for i in header.history: #print i his.write(i+"\n") print("\nDatabase has been successfully updated\n") return
def read_database(scratch = False): """ Read database of calculations INPUT: scratch - not used RETURN: calc - dict, contains all calculations of the project conv - dict, convergence sequences varset - dict, parameter sets of the project size_on_start, int - not used now """ # databasefile = 'calc.s' #was used with python2 # databasefile = 'calc.gdbm' databasefile3 = 'calc.gdbm3' # if header.RAMDISK: # databasefile3 = header.RAMDISK+databasefile3 # if scratch == True: databasefile = '/scratch/aksenov/calc.s' printlog("\nLaunch at "+str( datetime.datetime.today() )+'\n') # mod = __import__("gdbm") # d = shelve.Shelf(mod.open(databasefile, protocol=1)) # print(databasefile3) d = shelve.open(databasefile3, protocol = 3) try: # calc = d[calc_key]; # calc = {}; header.conv = d[conv_key]; header.varset = d[varset_key]; header.history = d[history_key] header.struct_des = d[struct_des_key] except KeyError: # try: calc = d[calc_key] #dictionary of calculations # except KeyError: # printlog( "There is no database of calculations. I create new"); calc = {} try: header.conv = d[conv_key] #dictionary of convergence lists except KeyError: printlog( "There is no dictionary of convergence lists. I create new"); conv = {} try: header.varset = d[varset_key] except KeyError: printlog( "There is no dictionary of inputsets. I create new"); varset = {} try: header.history = d[history_key] except KeyError: header.history = ['Project started on '+ str( datetime.date.today() ) ] printlog( "There is still no history in database. The list is in header module "); try: header.struct_des = d[struct_des_key] except KeyError: printlog( "There is no struct_des in database. The dict is in header module "); d.close() #print history init_default_sets() return header.conv, header.varset, sys.getsizeof(d)
def get_from_server(files = None, to = None, to_file = None, addr = None, trygz = True): """ Download files using either paramiko (higher priority) or rcync; For paramiko header.ssh_object should be defined files (list of str) - files on cluster to download to (str) - path to local folder ! to_file (str) - path to local file (if name should be changed); in this case len(files) should be 1 The gz file is also checked RETURN result of download TODO: now for each file new connection is opened, copy them in one connection """ def download(file, to_file): if header.ssh_object: exist = file_exists_on_server(file, addr) # try: if exist: printlog('Using paramiko: ssh_object.get(): from to ', file, to_file) header.ssh_object.get(file, to_file ) out = '' # except FileNotFoundError: else: out = 'file not found' else: out = runBash('rsync -uaz '+addr+':'+file+ ' '+to_file) if out: res = out else: res = 'OK' printlog('Download result is ', res) return out if not is_list_like(files): files = [files] files = [file.replace('\\', '/') for file in files] #make sure the path is POSIX files_str = ', '.join(np.array(files )) printlog('Trying to download', files_str, 'from server', imp = 'n') for file in files: if not to and not to_file: #use temporary file with tempfile.NamedTemporaryFile() as f: to_file_l = f.name #system independent filename elif not to_file: #obtain filename to_file_l = os.path.join(to, os.path.basename(file) ) else: to_file_l = to_file makedir(to_file_l) out = download(file, to_file_l) if out and trygz: printlog('File', file, 'does not exist, trying gz', imp = 'n') file+='.gz' to_file_l+='.gz' out = download(file, to_file_l) if out: printlog(' No gz either!', imp = 'n') else: gunzip_file(to_file_l) return out
def det_gravity(dos, Erange=(-100, 0)): """Determine center of gravity for DOS and return values of energy for d6 orbitals in list INPUT: dos - ase dos type with added d6 - sum of d orbitals over neighbors to impurity atoms Erange - window of energy to determine center of gravity """ sum_dos_E = {} sum_dos = {} sum_dos['d6'] = 0 sum_dos_E['d6'] = 0 for i, E in enumerate(dos.energy): if E < Erange[0]: continue if E > Erange[1]: break sum_dos['d6'] += dos.d6[i] sum_dos_E['d6'] += dos.d6[i] * E d6_gc = sum_dos_E['d6'] / sum_dos['d6'] if 0: #old nn = 13 sum_dos_E = [0 for i in range(nn)] sum_dos = [0 for i in range(nn)] i = -1 for E in st.dos[0]: i += 1 if E < -6: continue if E > 0: break l = 1 #s sum_dos_E[l] += st.dos[l][i] * E sum_dos[l] += st.dos[l][i] l = 2 #p sum_dos_E[l] += st.dos[l][i] * E sum_dos[l] += st.dos[l][i] l = 3 #d sum_dos_E[l] += st.dos[l][i] * E sum_dos[l] += st.dos[l][i] l = 0 #p+d sum_dos_E[l] += (st.dos[2][i] + st.dos[3][i]) * E sum_dos[l] += st.dos[2][i] + st.dos[3][i] l = 11 #full sum_dos_E[l] += st.dos[l][i] * E sum_dos[l] += st.dos[l][i] l = 12 #s+p+d sum_dos_E[l] += (st.dos[1][i] + st.dos[2][i] + st.dos[3][i]) * E sum_dos[l] += st.dos[1][i] + st.dos[2][i] + st.dos[3][i] #Determine center of DOS st.Ec = [0 for i in range(nn)] # if debug: print "Gravity Centers for s,p,d are (eV):" for l in 1, 2, 3, 0, 11, 12: if sum_dos[l] <= 0: printlog('err 123') sum_dos[l] = 0.00001 st.Ec[l] = sum_dos_E[l] / sum_dos[l] # if debug: print st.Ec[l] return d6_gc
def create_supercell(st, mul_matrix, test_overlap = False, mp = 2, bound = 0.01): """ st (Structure) - mul_matrix (3x3 ndarray of int) - for example created by *ortho_ vec()* bound (float) - shift (A) allows to correctly account atoms on boundaries mp (int) include additionall atoms before cutting supecell test_overlap (bool) - check if atoms are overlapping - quite slow """ sc = copy.deepcopy(st) sc.rprimd = list(np.dot(mul_matrix, st.rprimd )) printlog('New vectors (rprimd) of supercell:\n',np.round(sc.rprimd,1), imp = 'y', end = '\n') sc.vol = np.dot( sc.rprimd[0], np.cross(sc.rprimd[1], sc.rprimd[2]) ) st.vol = np.dot( st.rprimd[0], np.cross(st.rprimd[1], st.rprimd[2]) ) # sc_natom_i = int(sc.vol/st.vol*st.natom) # test sc_natom = sc.vol/st.vol*st.natom # test printlog('The supercell should contain', sc_natom, 'atoms ... ', imp = 'y', end = ' ') sc.xcart = [] sc.typat = [] sc.xred = [] #find range of multiplication mi = np.min(mul_matrix, axis = 0) ma = np.max(mul_matrix, axis = 0) mi[mi>0] = 0 # # print(mi, ma) # find bound values lengths = np.linalg.norm(sc.rprimd, axis = 1) bounds = bound/lengths # in reduced coordinates for uvw in itertools.product(*[range(*z) for z in zip(mi-mp, ma+mp)]): #loop over all ness uvw # print(uvw) xcart_mul = st.xcart + np.dot(uvw, st.rprimd) # coordinates of basis for each uvw # print(xcart_mul) xred_mul = xcart2xred(xcart_mul, sc.rprimd) for xr, xc, t in zip(xred_mul, xcart_mul, st.typat): if all([0-b <= r < 1-b for r, b in zip(xr, bounds)]): #only that in sc.rprimd box are needed sc.xcart.append( xc ) sc.xred.append ( xr ) sc.typat.append( t ) sc.natom = len(sc.xcart) sc.magmom = [None] if abs(sc.natom - sc_natom)>1e-5: #test 1, number of atoms printlog('Error! Supercell contains wrong number of atoms:', sc.natom , 'instead of', sc_natom, 'try to increase *mp* of change *bound* ') else: printlog('OK', imp = 'y') if test_overlap: #test 2: overlapping of atoms enx = list(enumerate(sc.xcart)) for (i1, x1), (i2, x2) in itertools.product(enx, enx): # print image_distance(x1, x2, sc.rprimd)[0] if i1 != i2 and image_distance(x1, x2, sc.rprimd)[0] < 0.1: #less than 0.1 Angstrom printlog('Error! Atoms in supercell are overlapping. Play with *bound*') return sc