def set_vaspp(self, token, arg, des = "see manual"): """ Used for setting vasp parameters. """ if token in ("ISMEAR",): if type(arg) not in [int, None, ]: raise TypeError if token in ("KSPACING",): if type(arg) not in [float, None, ]: raise TypeError old = self.vasp_params[token] self.vasp_params[token] = arg if old == arg: print_and_log("Warning! You did not change "+token+" in "+self.ise+" set\n") else: self.history += " "+token+" was changed from "+str(old)+" to "+str(arg) + "\n" print_and_log(token+" was changed from "+str(old)+" to "+str(arg) +" - "+ des+" in set "+self.ise+" \n") self.update() return
def read_vectors(token, number_of_vectors, list_of_words): """Returns the list of numpy vectors for the last match""" number_of_matches = list_of_words.count(token) if number_of_matches == 0: #print_and_log("Warning token '"+token+"' was not found! return empty\n") return [None] if number_of_matches > 1: print_and_log("Warning token '" + token + "' was found more than one times\n") raise RuntimeError index = list_of_words.index(token, number_of_matches - 1) #Return the index of the last match #print list_of_words[index] list_of_vectors = [] vector = np.zeros((3)) for i in range(number_of_vectors): vector[0] = float(list_of_words[index + 1]) vector[1] = float(list_of_words[index + 2]) vector[2] = float(list_of_words[index + 3]) index += 3 list_of_vectors.append(vector.copy()) return list_of_vectors
def set_relaxation_type(self,type_of_relaxation): name = "Type of relaxation ISIF" if type(type_of_relaxation) not in [str, ]: raise TypeError old = self.vasp_params["ISIF"] if "ions" == type_of_relaxation: if int(self.ise[0]) != 9: print_and_log("Warning! The name of set is uncostintent with relaxation type\n") raise TypeError self.vasp_params["ISIF"] = 2 # self.set_nmdsteps(200) elif type_of_relaxation == "full": if int(self.ise[0]) != 2: print_and_log("Warning! The name of set is uncostintent with relaxation type\n") raise TypeError self.vasp_params["ISIF"] = 3 else: print_and_log("Error! Uncorrect type of relaxation\n") raise TypeError arg = self.vasp_params["ISIF"] if old == arg: print_and_log("Warning! You did not change "+name+" in "+self.ise+" set\n") return self.history += " "+name+" was changed from "+str(old)+" to "+str(arg) + "\n" print_and_log(name+" was changed from "+str(old)+" to "+str(arg) + " in set "+self.ise+" \n") self.update() #print self.history return
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 load(self, param, inplace=False): """ Update parameters of set from dict param """ # print(param) if inplace: s = self else: s = copy.deepcopy(self) for key in param: if key in vasp_keys: s.set_vaspp(key, param[key]) elif key == 'set_potential': for key2 in param[key]: # print key2, 'key2' s.set_potential(key2, param[key][key2]) elif key == 'add_nbands': # print param[key] s.set_add_nbands(param[key]) elif key == 'ngkpt': s.set_ngkpt(param[key]) elif key == 'bfolder': print_and_log('New blockfolder', param[key]) elif key in siman_keys: s.set_attrp(key, param[key]) elif key in aims_keys: s.set_vaspp(key, param[key]) else: print_and_log('Error! Uknown key: ' + key) raise RuntimeError if key == 'set_sequence': sets = [] for se in s.set_sequence: sets.append(copy.deepcopy(header.varset[se])) s.set_sequence = sets #put objects instead of names # if hasattr(s, 'set_sequence') and s.set_sequence: # sets = [] # for se in s.set_sequence: # if type(se) == str: # sets.append(copy.deepcopy(varset[se])) # else: # sets.append(copy.deepcopy(se)) # s.set_sequence = sets #put objects instead of names return s
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 add_conv_kpoint(self, arg): if type(arg) is not str: sys.exit("\nadd_conv_kpoint error\n") if arg in self.conv_kpoint: print_and_log("Warning! You already have this name in list") return self.conv_kpoint.append(arg) self.history += "Name " + arg + " was added to self.conv_kpoint\n" self.update()
def determine_unique_final(st_pores, sums, avds, x_m): final_table = [] insert_positions = [] """Please determine unique positions with similar distances taking into acc PBC!!! below is incorrect """ # 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', imp = 'y') # xcart_unique = [] # avds_unique = [] # sums_unique = [] # for i, s in enumerate(sums_crude): # index_of_first = np.where(sums.round(crude_prec)==s)[0][0] # xcart_unique.append(st_pores.xcart[index_of_first]) # avds_unique.append(avds[index_of_first] ) # sums_unique.append(sums[index_of_first] ) # st_pores_unique = copy.deepcopy(st_pores) # st_pores_unique.xcart = xcart_unique # st_pores_unique.xcart2xred() sur = local_surrounding(x_m, st_pores, n_neighbours=len(st_pores.xcart), control='atoms', periodic=True) # print('neb.determine_unique_final(): sur', sur) print_and_log('I can suggest you ' + str(len(sur[0])) + ' end positions.', imp='y') for i, (x, d, ind) in enumerate(zip(sur[0], sur[3], sur[2])): # if i == 0: # continue final_table.append( [i, np.array(x).round(2), round(d, 2), avds[ind], sums[ind]]) print_and_log(tabulate(final_table, headers=['void #', 'Cart.', 'Dist', 'Dev.', 'Sum'], tablefmt='psql'), imp='Y') return sur
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 add_conv_tsmear(self,arg): if type(arg) is not str: sys.exit("\nadd_conv_tsmear type error\n") try: self.conv_tsmear[0] except AttributeError: print_and_log( "Error! Set "+self.ise+" does not have conv_tsmear, I create new\n") self.conv_tsmear = [] if arg in self.conv_tsmear: print_and_log( "Warning! You already have this name in list", imp = 'y') return self.conv_tsmear.append(arg) self.history += "Name "+arg+" was added to self.conv_tsmear\n" self.update()
def add_conv(self, arg, type_of_conv): if type(arg) is not str: raise TypeError if type_of_conv not in [ "kpoint_conv", "tsmear_conv", "ecut_conv", "nband_conv", "npar_conv" ]: raise TypeError try: self.conv[type_of_conv][0] except AttributeError: print_and_log("Warning! Set " + self.ise + " does not have conv, I create new\n") self.conv = {} except KeyError: print_and_log( "Warning! Set " + self.ise + " does not have list for this key in conv, I add new\n") self.conv[type_of_conv] = [] except IndexError: pass if arg in self.conv[type_of_conv]: print_and_log( "Warning! You already have name %s in list of conv %s. Nothing done.\n" % \ (str(arg), str(self.conv[type_of_conv]) ) ) return self.conv[type_of_conv].append(arg) self.history += "Name " + arg + " was added to self.conv[" + type_of_conv + "]\n" print_and_log("Name " + arg + " was added to self.conv[" + type_of_conv + "] of set " + self.ise + " \n") self.update()
def gb_energy_volume(gb,bulk): if (gb.end.rprimd[1] != bulk.end.rprimd[1]).any() or (gb.end.rprimd[2] != bulk.end.rprimd[2]).any(): print_and_log("Warning! You are trying to calculate gb_energy from cells with different lateral sizes:"+str(gb.end.rprimd)+" "+str(bulk.end.rprimd)+"\n") #print bulk.vol V_1at = bulk.vol / bulk.natom #* to_ang**3 E_1at = bulk.energy_sigma0 / bulk.natom A = np.linalg.norm( np.cross(gb.end.rprimd[1], gb.end.rprimd[2]) ) #surface area of gb #print A gb.v_gb = ( gb.vol - V_1at * gb.natom) / A / 2. * 1000 gb.e_gb = ( gb.energy_sigma0 - E_1at * gb.natom) / A / 2. * eV_A_to_J_m * 1000 gb.e_gb_init = ( gb.list_e_sigma0[0] - E_1at * gb.natom) / A / 2. * eV_A_to_J_m * 1000 gb.bulk_extpress = bulk.extpress #print "Calc %s; e_gb_init = %.3f J/m^2; e_gb = %.3f J/m; v_gb = %.3f angstrom "%(gb.name, gb.e_gb_init, gb.e_gb, gb.v_gb ) outst = "%15s&%7.0f&%7.0f"%(gb.name, gb.e_gb, gb.v_gb) return outst
def calc_ac(a1, c1, a2, c2, a_b = 0.1, c_b = 0.1, type = "two_atoms"): """ Calculate values of hexagonal lattice parameters for cell with two different atoms. The used assumption is: 1. Provided lattice constants are for large enougth cells, in which excess volume (dV) of impurity does not depend on the size of cell. 2. Two atoms do not interact with each other, which allows to use dV(CO) = dV(C) + dV(O) Two regimes: two_atoms - calculate cell sizes if additional atom was added double_cell - if cell was doubled; only first cell and second_cell are needed Input: a1, c1 - lattice constants of cell with first impurity atom (first cell) a2, c2 - lattice constants of cell with second impurity atom (second cell) a_b, c_b - lattice constants of cell with pure hexagonal metall Output: a, c - lattice constants of cell with two atoms """ hstring = ("%s #on %s"% (traceback.extract_stack(None, 2)[0][3], datetime.date.today() ) ) if hstring != header.history[-1]: header.history.append( hstring ) A = (a1**2 * c1) + (a2**2 * c2) - (a_b**2 * c_b) B = 0.5 * (c1/a1 + c2/a2) C = ( (a1**2 * c1) + (a2**2 * c2) ) * 0.5 #sum of cell volumes divided by 2 since during the construction of new cell we will use multiplication by 2 # print "A,B=",A,B a = (A/B)**(1./3) c = a * B a = round(a,5) c = round(c,5) print_and_log( "a, c, c/a for cell with pure hcp ", a_b, c_b, round(c_b/a_b,4), imp ='y' ) print_and_log( "a, c, c/a for cell with first atom ", a1, c1, round(c1/a1,4), imp ='y' ) print_and_log( "a, c, c/a for cell with second atom ", a2, c2, round(c2/a2,4), imp ='y' ) #for double cell a3 = (C/B)**(1./3) c3 = a3 * B a3 = round(a3,5) c3 = round(c3,5) if type == "two_atoms": print_and_log( "a, c, c/a for cell with two atoms ", a, c, round(c/a,4), "# the same cell but with two atoms\n", imp ='y') elif type == "double_cell": print_and_log( "a, c, c/a for new cell ", a3, c3, round(c3/a3,4), "# for cell with V = V(first_cell) + V(second cell), but only for the case if V(second cell) == V(first_cell)", imp ='y') return a, c
def calculate_voronoi(self, state = 'end'): # By default two quantities per atom are calculated by this compute. # The first is the volume of the Voronoi cell around each atom. # Any point in an atom's Voronoi cell is closer to that atom than any other. # The second is the number of faces of the Voronoi cell, which # is also the number of nearest neighbors of the atom in the middle of the cell. # state - init or end; if init then saved in self.init.vorovol; if end than saved in self.vorovol write_lammps(self, state, filepath = 'voronoi_analysis/structure.lammps') #write structure for lammps runBash("rm voronoi_analysis/dump.voro; /home/aksenov/installed/lammps-1Feb14/src/lmp_serial < voronoi_analysis/voronoi.in > voronoi_analysis/log") if state == 'end': self.vorovol = [] self.vorofaces = [] vorovol = self.vorovol vorofaces = self.vorofaces elif state == 'init': self.init.vorovol = [] self.init.vorofaces = [] vorovol = self.init.vorovol vorofaces = self.init.vorofaces vsum=0 wlist = [] with open('voronoi_analysis/dump.voro','r') as volfile: #analyze dump.voro for line in volfile: if 'ITEM: ATOMS ' in line: break for line in volfile: ll = line.split() if int(ll[1]) > 1: wlist.append( [ll[0], ll[5], ll[6], ll[2]] ) # print 'Volume of atom ',ll[0],'is', ll[5] vsum= vsum+float(ll[5]) print_and_log( 'Check total volume ', vsum, self.end.vol) wlist.sort(key = itemgetter(0)) #sort according to the position of atoms print_and_log( "atom #, voronoi vol, voronoi faces, x coordinate: ", ) print_and_log( wlist) for w in wlist: vorovol.append(float(w[1])) vorofaces.append(int(w[2])) # print 'Voro vol ',self.end.vorovol # print 'Voro faces',self.end.vorofaces # print len(wlist) if hasattr(self, 'vorovol'): voro = '' if len(vorovol) == 2: #C and O voro = " {0:5.2f} & {1:2d} & {2:5.2f} & {3:2d} ".format(vorovol[0], vorofaces[0], vorovol[1], vorofaces[1] ).center(25) else: voro = " {0:5.2f} & {1:2d} ".format(vorovol[0], vorofaces[0] ).center(25) voro+='&' else: voro = "" print_and_log( "Voronoi volume = ", voro, imp = 'y') return voro
def read_vectors(token, number_of_vectors, list_of_words, type_func=None, lists=False): """Returns the list of numpy vectors for the last match""" # lists - return list of lists instead list of vectors if type_func is None: type_func = lambda a: float(a) number_of_matches = list_of_words.count(token) if number_of_matches == 0: #print_and_log("Warning token '"+token+"' was not found! return empty\n") return [None] if number_of_matches > 1: print_and_log("Warning token '" + token + "' was found more than one times\n") raise RuntimeError index = list_of_words.index(token, number_of_matches - 1) #Return the index of the last match #print list_of_words[index] list_of_vectors = [] list_of_lists = [] vector = np.zeros((3)) for i in range(number_of_vectors): vector[0] = type_func(list_of_words[index + 1]) vector[1] = type_func(list_of_words[index + 2]) vector[2] = type_func(list_of_words[index + 3]) list3 = [] for j in 1, 2, 3: list3.append(type_func(list_of_words[index + j])) index += 3 list_of_vectors.append(vector.copy()) list_of_lists.append(list3) if lists: out = list_of_lists else: out = list_of_vectors return out
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 element_name_inv(el): el_dict = header.el_dict nu_dict = header.nu_dict # print type(el), el, type(str('sdf') ) if is_string_like(el): try: elinv = el_dict[el] except: print_and_log("Error! Unknown element: " + str(el)) raise RuntimeError else: el = int(el) try: elinv = nu_dict[el] except: print_and_log("Error! Unknown element: " + str(el)) raise RuntimeError return elinv # inversed notion of element
def set_add_nbands(self,arg): name = "add_nbands" # print(type(arg)) if type(arg) not in [float, int, type(None) ]: raise TypeError try: self.add_nbands except AttributeError: self.add_nbands = None old = self.add_nbands self.add_nbands = arg if old == arg: print_and_log("Warning! You did not change "+name+" in "+self.ise+" set\n") return self.history += " "+name+" was changed from "+str(old)+" to "+str(arg) + "\n" print_and_log(" "+name+" was changed from "+str(old)+" to "+str(arg) + " in set "+self.ise+" \n") return
def determine_unique_voids(st_pores, sums, avds): crude_prec = 1 # number of signs after 0 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', 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=['void #', 'Cart.', 'Index', 'Dev.', 'Sum'], tablefmt='psql'), imp='Y') return insert_positions
def set_attrp(self, token, arg, des="see manual"): """ set any attribute. """ # print (token) if hasattr(self, token): old = getattr(self, token) if old == arg: print_and_log("Warning! You did not change " + token + " in " + self.ise + " set\n") else: setattr(self, token, arg) self.history += " " + token + " was changed from " + str( old) + " to " + str(arg) + "\n" print_and_log(token + " was changed from " + str(old) + " to " + str(arg) + " - " + des + " in set " + self.ise + " \n") else: setattr(self, token, arg) print_and_log("New attribute " + token + " added to " + self.ise + " set\n") self.history += " " + token + " was added as a new attr with " + str( arg) + " value \n" return
def inherit_iset(ise_new, ise_from, varset, override=False, newblockfolder=None): """ Create new set copying from existing and update some fields. If ise_from does not exist create new""" ise_new = ise_new.strip() ise_from = ise_from.strip() if ise_from not in varset: print_and_log("\nError! Set " + ise_from + " does not exist. I return new empty set\n") return InputSet(ise_new) old = varset[ise_from] for key in vasp_electronic_keys + vasp_ionic_keys + vasp_other_keys: #check if new keys was added if key not in old.vasp_params: old.vasp_params[key] = None if override: print_and_log("\nAttention! You have chosen to override set " + ise_new + "\n") elif ise_new in varset: print_and_log( "\nSet " + ise_new + " already exists. I return it without changes. Be carefull not to spoil it\n" ) return varset[ise_new] new = copy.deepcopy(old) new.ise = ise_new new.compare_with = ise_from + " " new.des = "no description for these set, see history" new.conv = {} print_and_log("New set " + ise_new + " was inherited from set " + ise_from + "\n") new.history = old.history + "\nSet " + ise_new + " was inherited from: " + ise_from + "\n" if newblockfolder: new.history += 'blockfolder changed from ' + new.blockfolder + ' to ' + newblockfolder + '\n' new.blockfolder = newblockfolder varset[ise_new] = new return new
def test_adding_of_impurities(added, init, v): """ Can be used only inside add_impurity() Replicates the structure and find again pores """ global natoms_v1 if added == None: return if v == 1: #TEST natoms_v1 = len(added.init.xcart) # for test st_rep_after = added.init.replic((1, 2, 1)) rep = copy.deepcopy(init) rep.init = rep.init.replic((1, 2, 1)) #print rep rep = add(znucl, "", rep, write_geo=False) #print rep #print "xcart of replic after adding ", st_rep_after.xcart #print "xcart of adding to replic ", rep.init.xcart if len(st_rep_after.xcart) != len(rep.init.xcart): raise RuntimeError p = 0 #for x2 in st_rep_after.xcart: # print x2 for x in rep.init.xcart: a = any((np.around(x2, p) == np.around(x, p)).all() for x2 in st_rep_after.xcart) #b = any( ( np.ceil(x2, p) == np.ceil(x, p) ).all() for x2 in st_rep_after.xcart ) #c = any( ( np.floor(x2, p) == np.floor(x, p) ).all() for x2 in st_rep_after.xcart ) #print a, b, c #np.concatenate(a, b, c): if not a: print_and_log("Error! Can't find ", np.around(x, 3), "in replic ") raise RuntimeError #assert all([ all( np.around(v1, 8) == np.around(v2, 8) ) for (v1, v2) in zip(st_rep_after.xcart, rep.init.xcart) ]) print_and_log("add_impurity: test succesfully done") if natoms_v1 != len(added.init.xcart): print_and_log( "You have different number of pores in different versions\n") raise RuntimeError return
def insert(it_ins, ise_ins, mat_path, it_new, calc, type_of_insertion="xcart"): """For insertion of atoms to cells with changed lateral sizes Input: 'type_of_insertion = xred' used to add xred coordinates mat_path - path to geo files which are supposed to be changed it_ins - already existed calculation; xred will be used from this calculation. it_new - new folder in geo folder for obtained structure This function finds version of calculation in folder mat_path and tries to use the same version of it_ins """ if not os.path.exists(mat_path): print_and_log("Error! Path " + mat_path + " does not exist\n\n") raise RuntimeError if it_ins not in mat_path and it_ins not in it_new: print_and_log('Cells are', it_ins, mat_path, it_new) print_and_log( "Error! you are trying to insert coordinates from cell with different name\n\n" ) #raise RuntimeError hstring = ("%s #on %s" % (traceback.extract_stack(None, 2)[0][3], datetime.date.today())) if hstring != header.history[-1]: header.history.append(hstring) geofilelist = runBash('find ' + mat_path + '/target -name "*.geo*" ').splitlines() if geofilelist == []: print_and_log( "Warning! Target folder is empty. Trying to find in root folder ..." ) geofilelist = runBash('find ' + mat_path + '/ -name "*.geo*" ').splitlines() ins = None for mat_geofile in geofilelist: mat = CalculationVasp() mat.name = mat_geofile mat.read_geometry(mat_geofile) #step = 0.27 #r_pore = 0.56 #r_mat = mat.hex_a / 2 - step #pores = find_pores(mat.init, r_mat, r_pore, step, 0.3, 'central') #octahedral #mat.xcart.append ( pores.xcart[0] ) #mat.typat.append(1) try: ins_working = ins ins = calc[(it_ins, ise_ins, mat.version)] except KeyError: print_and_log("No key", (it_ins, ise_ins, mat.version), "I use previous working version !!!", imp='y') ins = ins_working #return #ins.end.znucl = ins.znucl #ins.end.nznucl = ins.nznucl #ins.end.ntypat = ins.ntypat #ins.end.typat = ins.typat #print ins.xcart[-1] mat_geopath = geo_folder + struct_des[it_new].sfolder + '/' if type_of_insertion == "xcart": #Please update here! mat_filename = '/' + it_new + "." + "inserted." + str( mat.version) + '.' + 'geo' v = np.zeros(3) result = insert_cluster(ins.end, v, mat.init, v) mat.end = result mat.init = result # mat.znucl = mat.end.znucl # mat.nznucl = mat.end.nznucl # mat.ntypat = mat.end.ntypat # mat.typat = mat.end.typat # mat.natom = len(mat.end.xred) #mat.version = ins.version des = ins.name + " was inserted to " + mat_geofile elif type_of_insertion == "xred": mat_filename = '/from/' + it_new + ".xred." + str( mat.version) + '.' + 'geo' #mat.end.rprimd = mat.rprimd #mat.init.xred = copy.deepcopy(ins.end.xred) #mat.init.typat = copy.deepcopy(ins.end.) #print ins.end.xcart rprimd = copy.deepcopy(mat.init.rprimd) #build = mat.build mat.init = copy.deepcopy(ins.end) #mat.build = build mat.init.rprimd = rprimd #return initial rprimd mat.init.xred2xcart() #calculate xcart with new rprimd des = "atoms with reduced coord. from " + ins.name + " was fully copied to " + mat_geofile mat.init.name = 'test_insert_xred' + str(mat.version) write_xyz(mat.init) mat.path["input_geo"] = mat_geopath + it_new + mat_filename if not mat.write_geometry("init", des): continue print_and_log("Xred from " + it_ins + " was inserted in " + mat_geofile + " and saved as " + mat_filename + " \n\n") return
def insert_cluster(insertion, i_center, matrix, m_center): """ Take care of orientation; typat should be consistent Input: insertion - object of class Structure(), which is supposed to be inserted in matrix in such a way that i_center will be combined with m_center. matrix - object of class Structure(). i_center, m_center - numpy arrays (3) cartesian coordinates """ ins = copy.deepcopy(insertion) mat = copy.deepcopy(matrix) r = mat.rprimd hproj = [(r[0][i] + r[1][i] + r[2][i]) * 0.5 for i in (0, 1, 2)] #projection of vectors on three axis if 1: for i, x in enumerate(ins.xcart): ins.xcart[i] = x - i_center for i, x in enumerate(mat.xcart): mat.xcart[i] = x - m_center max_dis = 1 for i_x, ix in enumerate(ins.xcart): dv_min = max_dis print_and_log( "Insertion atom ", ix, ) if 1: for j, mx in enumerate(mat.xcart): dv = mx - ix for i in 0, 1, 2: if dv[i] > hproj[i]: dv = dv - mat.rprimd[ i] #periodic boundary conditions - can be not correct (in the sense that closest image can lie not 100 % in the neighbourhood image cell ) for oblique cells and large absolute values of dv if dv[i] < -hproj[i]: dv = dv + mat.rprimd[i] len1 = np.linalg.norm(dv) len2, second_len2 = mat.image_distance(mx, ix, r, 1) #check len1 #print "Lengths calculated with two methods ", len1, len2 len1 = len2 #just use second method #assert np.around(len1,1) == np.around(len2,1) if len1 < dv_min: dv_min = len1 j_r = j # number of matrix atom to replace if 1: #Modify to replace overlapping atoms if dv_min == max_dis: print_and_log(" is more far away from any matrix atom than ", dv_min, " A; I insert it") # mat.xcart.append( ix ) # print_and_log( 'type of added atom is ', ins.typat[i_x]) # mat.typat.append( ins.typat[i_x] ) mat = mat.add_atom(xc=ix, element=ins.get_elements()[i_x]) else: print_and_log("will replace martix atom", mat.xcart[j_r]) mat.xcart[j_r] = ix.copy() mat.rprimd = r mat.xcart2xred() mat.natom = len(mat.xcart) mat.name = 'test_of_insert' st = mat # print(st.natom, len(st.xcart), len(st.typat), len(st.znucl), max(st.typat) ) # write_xyz(mat) mat = mat.return_atoms_to_cell() mat.write_poscar() return mat
def add(znucl, xyzpath="", new=None, write_geo=True, put_exactly_to=None): "if put_exactly_to is True, then atom just added and nothing are searched" if write_geo and os.path.exists( new.path["input_geo"]) and not override: print_and_log("add: File '" + new.path["input_geo"] + "' already exists; continue\n", imp='Y') return new #new.init = return_atoms_to_cell(new.init) if replace_atom: #atom substitution if znucl not in new.init.znucl: new.init.znucl.append(znucl) new.init.ntypat += 1 new.init.typat[replace_atom] = new.init.ntypat else: ind = new.init.znucl.index(znucl) new.init.typat[replace_atom] = ind + 1 new.init.nznucl = [] for typ in range(1, new.init.ntypat + 1): new.init.nznucl.append(new.init.typat.count(typ)) else: new_before = copy.deepcopy(new) # new.init.xcart[-2][0]-=0.9 #was made once manually for c1gCOi10.1 # new.init.xcart[-2][2]+=0.2 # new.init.xred = xcart2xred(new.init.xcart, new.init.rprimd) write_xyz(new.init) #step = 0.042 step = 0.06 #r_pore = 0.56 #fine = 0.3 # for visualisation of pores #fine = 4 #controls small steps; the steps are smaller for larger numbers #r_pore = 0.54 prec = 0.004 # precision of center Angs if new.hex_a == None: r_mat = 1.48 - step else: r_mat = new.hex_a / 2 - step if put_exactly_to: pores_xred = [ np.array(put_exactly_to), ] print_and_log('Inmpurity just put in ', pores_xred, imp='Y') else: pores = find_pores(new.init, r_mat, r_pore, step, fine, prec, addtype, new.gbpos, find_close_to, check_pore_vol) #octahedral pores_xred = pores.xred npores = len(pores_xred) st = new.init #delete last oxygen; was made once manually for c1gCOi10.1 # st.natom-=1 # del st.xred[-1] # del st.typat[-1] st.natom += npores st.xred.extend(pores_xred) if znucl in st.znucl: print_and_log("znucl of added impurity is already in cell") ind = st.znucl.index(znucl) typat = ind + 1 st.nznucl[ind] += npores else: st.ntypat += 1 typat = st.ntypat st.znucl.append(znucl) st.nznucl.append(npores) for i in range(npores): st.typat.append(typat) st.xred2xcart() new.init = st #print "Add impurity: len(xred ", len(new.init.xred) #print "natom", new.init.natom #For automatisation of fit try: #new.build if new.build.nadded == None: new.build.nadded = npores else: new.build.nadded += npores if new.build.listadded == [None]: new.build.listadded = range( new.natom - npores, new.natom) #list of atoms which were added else: new.build.listadded.extend( range(new.natom - npores, new.natom)) #print "Warning!!! Information about added impurities rewritten" except AttributeError: pass #new.init.znucl = new.znucl #new.init.typat = new.typat #write_xyz(replic(new.init, (2,1,2)) , xyzpath) #test_adding_of_impurities(new, new_before, v) print_and_log("Impurity with Z=" + str(znucl) + " has been added to the found pore in " + new.name + "\n\n") if write_geo: write_xyz(new.init, xyzpath) new.write_geometry("init", new.des, override=override) print_and_log("\n") return new
def find_pores(st_in, r_matrix=1.4, r_impurity=0.6, step_dec=0.05, fine=0.3, prec=0.1, calctype='central', gbpos=0, find_close_to=(), check_pore_vol=0): """ st_in - input Structure() object r_impurity (A)- all pores smaller than this radius will be found r_matrix (A) - radius of matrix atoms disregarding to their type step_dec - scanning step of the cell in Angstroms fine - allows to change density of local points; local_step = step_dec/fine prec - precicion of pore center determination check_pore_vol - allows to estimate volume of pores; has problems for big cells 'find_close_to' - works in the cases of gb and grain_vol; allows to ignore all and find pore close to provided three reduced coordinates return - instance of Structure() class with coordinates of pores. Number and type of included pores depend on the argument of 'calctype'. """ xred = st_in.xred natom = len(xred) rprimd = st_in.rprimd name = st_in.name #print xred """Additional values""" # check_pore_vol = 1 #if calctype in ("pore_vol","gb","grain_vol","all_local" ): check_pore_vol = 1 #something wrong with this function, especially for big cells """----Conversions of types for C++""" r1 = create_c_array(rprimd[0], float) r2 = create_c_array(rprimd[1], float) r3 = create_c_array(rprimd[2], float) xred1 = (c_float * len(xred))(*[x[0] for x in xred]) xred2 = (c_float * len(xred))(*[x[1] for x in xred]) xred3 = (c_float * len(xred))(*[x[2] for x in xred]) max_npores = 10000 ntot = ctypes.c_int32() npores = ctypes.c_int32() l_pxred1 = (c_float * max_npores)(0) #make static arrays fol local points l_pxred2 = (c_float * max_npores)(0) l_pxred3 = (c_float * max_npores)(0) l_npores = (ctypes.c_int32 * max_npores)(0) pxred1 = (c_float * max_npores)(0) #make static arrays natoms + npore pxred2 = (c_float * max_npores)(0) pxred3 = (c_float * max_npores)(0) """----Run C++ function""" print_and_log("Starting C++ function lib.findpores()...\n") # print(r_matrix, r_impurity, step_dec, fine, prec) lib.findpores ( check_pore_vol, \ max_npores, \ byref(ntot), l_pxred1, l_pxred2, l_pxred3, l_npores, \ byref(npores), pxred1, pxred2, pxred3, \ natom, xred1, xred2, xred3, \ c_float(r_matrix), c_float(r_impurity), c_float(step_dec), c_float(fine), c_float(prec), \ r1, r2, r3 ) print_and_log("ntot is ", ntot.value) print_and_log("l_npores[0] is ", l_npores[0]) v = np.zeros((3)) l_pxred = [] shift1 = 0 shift2 = 0 for i_por in range(npores.value): l_pxred.append([]) shift2 += l_npores[i_por] for i in range(shift1, shift2): v[0] = l_pxred1[i] v[1] = l_pxred2[i] v[2] = l_pxred3[i] l_pxred[i_por].append(v.copy()) shift1 = shift2 if shift2 != ntot.value: print_and_log("Error! final shift2 not equal to ntot") #print l_pxred[0] pxred = [] # only coordinates of pores #print pxred1[natom] for i in range(npores.value): v[0] = pxred1[i + natom] v[1] = pxred2[i + natom] v[2] = pxred3[ i + natom] #with shift, because first natom elements are coordinates of atoms pxred.append(v.copy()) #print pxred """----End of C++; result is two lists: lpxred - local geometry of all pores, pxred - coordinates of all pores""" """ Analyse of pores """ # st_result = Structure() st_result = st_in.new() st_result.rprimd = rprimd targetp = np.array((0., 0., 0.)) if find_close_to: targetp = np.asarray(find_close_to) #targer point print_and_log("Target point is ", targetp) a = step_dec / fine #the side of little cube formed by the mesh which is used to find spheres inside the pore. aaa = a * a * a #find most central pore if calctype == 'central': #return coordinates of the most central pore st_result.name = "central_pore_from " + name center = np.array((0.5, 0.5, 0.5)) #center of cell d_min = 100 for x in pxred: d = np.linalg.norm(x - center) #print x, x-center, d if d < d_min and x[0] <= 0.5 and x[1] <= 0.5 and x[2] <= 0.5: d_min = d x_min = x print_and_log("The closest pore to the center has coordinates", x_min) st_result.xred.append(x_min) elif calctype == 'gb': #add impurity at gb st_result.name = "gb_pore_from " + name d_min = 100 #d2_min = 100 dt_min = 100 i_min = 0 x_min = np.zeros((3)) for i, x in enumerate(pxred): #print "l_npores ",l_npores[i] d = abs(x[0] - gbpos / rprimd[0][0]) # #print x[0], d if find_close_to: closer = (np.linalg.norm(targetp - x) < dt_min) else: closer = (d < d_min) # and x[1]>0.3 and x[2]>0.3: if closer: x_pre = x_min i_pre = i_min d_min = d dt_min = np.linalg.norm(targetp - x) x_min = x i_min = i #find and add impurity in bulk #d2 = abs( x[0] - (gbpos/rprimd[0][0] - 0.25) ) #if d2 < d2_min: # d2_min = d2 # x2_min = x # i2_min = i #print "rprimd[0][0]", rprimd[0][0] print_and_log("Position of boundary is ", gbpos / rprimd[0][0]) #x_min[0] = gbpos/rprimd[0][0] if find_close_to: print_and_log( "The closest pore to the target point is [ %.2f %.2f %.2f ]" % (x_min[0], x_min[1], x_min[2])) else: print_and_log("The closest pore to the gb has coordinates", x_min) st_result.xred.append(x_min) #st_result.xred.append( x_pre ) #Calculate volume of the pore using local balls: print_and_log("The number of pore is ", i_min, " ; It has ", l_npores[i_min], "local balls") print_and_log("Volume of pore is ", l_npores[i_min] * a * a * a, " A^3") #st_result.xred.extend( l_pxred[i_min] ) #st_result.xred.extend( l_pxred[i_pre] ) #print "The closest pore to the center of bulk has coordinates",x2_min #st_result.xred.append( x2_min ) #Calculate volume of the pore using local balls: #print "The number of bulk pore is ",i2_min," ; It has ",l_npores[i2_min], "local balls" #print "Volume of pore is ", l_npores[i2_min] * a*a*a, " A^3"; #st_result.xred.extend( l_pxred[i2_min] ) elif calctype == 'grain_vol': #add impurity to volume of grain st_result.name = "grain_volume_pore_from " + name d2_min = 100 dt_min = 100 i_min = 0 x_min = np.zeros((3)) for i, x in enumerate(pxred): #find and add impurity to the bulk d2 = abs(x[0] - (gbpos / rprimd[0][0] - 0.25)) if find_close_to: closer = (np.linalg.norm(targetp - x) < dt_min) else: closer = (d2 < d2_min) # and x[1]>0.3 and x[2]>0.3: if closer: dt_min = np.linalg.norm(targetp - x) d2_min = d2 x2_min = x i2_min = i if find_close_to: print_and_log( "The closest pore to the target point is [ %.2f %.2f %.2f ]" % (x2_min[0], x2_min[1], x2_min[2])) else: print_and_log( "The closest pore to the center of bulk has coordinates", x2_min) st_result.xred.append(x2_min) #Calculate volume of the pore using local balls: print_and_log("The number of bulk pore is ", i2_min, " ; It has ", l_npores[i2_min], "local balls") print_and_log("Volume of pore is ", l_npores[i2_min] * a * a * a, " A^3") st_result.xred.extend(l_pxred[i2_min]) elif calctype == 'all_local': st_result.name = "all_local_points_from " + name v_max = 0 i_max = 0 for i in range(npores.value): v_pore = l_npores[i] * aaa print_and_log("Volume of pore is ", l_npores[i] * aaa, " A^3") if v_pore > v_max: v_max = v_pore i_max = i print_and_log("Pore number ", i_max, "has the largest volume ", v_max, " A^3") # st_result.xred = l_pxred[i_max] # here coordinates of all local points to show geometry of pore with largerst volume st_result.xred = [x for group in l_pxred for x in group] # all pores elif calctype == 'all_pores': st_result.name = "all_local_pores_from " + name st_result.xred = pxred st_result.rprimd = rprimd st_result.xred2xcart() st_result.typat = [1 for x in st_result.xred] st_result.ntypat = 1 st_result.natom = len(st_result.typat) st_result.znucl = [200] st_ntypat = 1 return st_result
def add_impurity(it_new, impurity_type=None, addtype='central', calc=[], r_pore=0.5, it_to='', ise_to='', verlist_to=[], copy_geo_from="", find_close_to=(), add_to_version=0, write_geo=True, only_version=None, fine=4, put_exactly_to=None, check_pore_vol=0, replace_atom=None, override=False): """ Add impurities in pores. Input: it_new - name of new structure with impurity impurity_type - name of impurity from Mendeley table, for example 'C' addtype - type of adding: ['central',]; 'central' means that impurity will be placed as close to the geometrical center of cell as possible. it_to , ise_to , verlist_to - completed calculations in which impurity will be added if 'verlist_to' is empty, function will try to find geometry files in 'geo_folder + struct_des[it_to].sfolder' folder; even if 'it_to' is empty it will try to find files in 'geo_folder + struct_des[it_new].sfolder+'/from' ' folder. 'ise_to' also can be empty if 'copy_geo_from' is not empty, then programm copy all files from folder 'copy_geo_from' to folder 'geo_folder + struct_des[it_to].sfolder+"/"+it_to' or 'geo_folder + struct_des[it_new].sfolder+"/from" ' 'find_close_to' is tuple of three reduced coordinates of point close to which you want to find impurity. If empty - ignored; 'add_to_version' is integer number added to each 'verlist_to' number to produce ver_new. 'only_version' - if == [v,], then instertion will be provided only for v. If None insertion will be made in all found versions If you want to add impurity to relaxed structure ... 'fine' - integer number; allows to reduce number of small steps for defining center Possible addtype's: 'central' - add one atom to the pore which is most close to the center of the cell but with reduced coordinates less than 0.5 0.5 0.5 'all_pore' - add atoms in every found pore 'all_local' - add atoms to every local point which allows to visualise topology of pores. 'gb' - uses self.gbpos and places atom close to this value assuming that it will be at gb 'grain_vol' - uses self.gbpos and assuming that cell contains two gb and two equal grains, places atom close to the centre of grain; y and z can be arbiratry put_exactly_to - will add impurity to this point find_close_to - will try to find closest void and insert pore here. check_pore_vol - allows to estimate volume of pores; has problems for big cells replace_atom - if not None, than the specified atom is substituted Side effects: creates new geometry folder with input structures; """ struct_des = header.struct_des def test_adding_of_impurities(added, init, v): """ Can be used only inside add_impurity() Replicates the structure and find again pores """ global natoms_v1 if added == None: return if v == 1: #TEST natoms_v1 = len(added.init.xcart) # for test st_rep_after = added.init.replic((1, 2, 1)) rep = copy.deepcopy(init) rep.init = rep.init.replic((1, 2, 1)) #print rep rep = add(znucl, "", rep, write_geo=False) #print rep #print "xcart of replic after adding ", st_rep_after.xcart #print "xcart of adding to replic ", rep.init.xcart if len(st_rep_after.xcart) != len(rep.init.xcart): raise RuntimeError p = 0 #for x2 in st_rep_after.xcart: # print x2 for x in rep.init.xcart: a = any((np.around(x2, p) == np.around(x, p)).all() for x2 in st_rep_after.xcart) #b = any( ( np.ceil(x2, p) == np.ceil(x, p) ).all() for x2 in st_rep_after.xcart ) #c = any( ( np.floor(x2, p) == np.floor(x, p) ).all() for x2 in st_rep_after.xcart ) #print a, b, c #np.concatenate(a, b, c): if not a: print_and_log("Error! Can't find ", np.around(x, 3), "in replic ") raise RuntimeError #assert all([ all( np.around(v1, 8) == np.around(v2, 8) ) for (v1, v2) in zip(st_rep_after.xcart, rep.init.xcart) ]) print_and_log("add_impurity: test succesfully done") if natoms_v1 != len(added.init.xcart): print_and_log( "You have different number of pores in different versions\n") raise RuntimeError return def add(znucl, xyzpath="", new=None, write_geo=True, put_exactly_to=None): "if put_exactly_to is True, then atom just added and nothing are searched" if write_geo and os.path.exists( new.path["input_geo"]) and not override: print_and_log("add: File '" + new.path["input_geo"] + "' already exists; continue\n", imp='Y') return new #new.init = return_atoms_to_cell(new.init) if replace_atom: #atom substitution if znucl not in new.init.znucl: new.init.znucl.append(znucl) new.init.ntypat += 1 new.init.typat[replace_atom] = new.init.ntypat else: ind = new.init.znucl.index(znucl) new.init.typat[replace_atom] = ind + 1 new.init.nznucl = [] for typ in range(1, new.init.ntypat + 1): new.init.nznucl.append(new.init.typat.count(typ)) else: new_before = copy.deepcopy(new) # new.init.xcart[-2][0]-=0.9 #was made once manually for c1gCOi10.1 # new.init.xcart[-2][2]+=0.2 # new.init.xred = xcart2xred(new.init.xcart, new.init.rprimd) write_xyz(new.init) #step = 0.042 step = 0.06 #r_pore = 0.56 #fine = 0.3 # for visualisation of pores #fine = 4 #controls small steps; the steps are smaller for larger numbers #r_pore = 0.54 prec = 0.004 # precision of center Angs if new.hex_a == None: r_mat = 1.48 - step else: r_mat = new.hex_a / 2 - step if put_exactly_to: pores_xred = [ np.array(put_exactly_to), ] print_and_log('Inmpurity just put in ', pores_xred, imp='Y') else: pores = find_pores(new.init, r_mat, r_pore, step, fine, prec, addtype, new.gbpos, find_close_to, check_pore_vol) #octahedral pores_xred = pores.xred npores = len(pores_xred) st = new.init #delete last oxygen; was made once manually for c1gCOi10.1 # st.natom-=1 # del st.xred[-1] # del st.typat[-1] st.natom += npores st.xred.extend(pores_xred) if znucl in st.znucl: print_and_log("znucl of added impurity is already in cell") ind = st.znucl.index(znucl) typat = ind + 1 st.nznucl[ind] += npores else: st.ntypat += 1 typat = st.ntypat st.znucl.append(znucl) st.nznucl.append(npores) for i in range(npores): st.typat.append(typat) st.xred2xcart() new.init = st #print "Add impurity: len(xred ", len(new.init.xred) #print "natom", new.init.natom #For automatisation of fit try: #new.build if new.build.nadded == None: new.build.nadded = npores else: new.build.nadded += npores if new.build.listadded == [None]: new.build.listadded = range( new.natom - npores, new.natom) #list of atoms which were added else: new.build.listadded.extend( range(new.natom - npores, new.natom)) #print "Warning!!! Information about added impurities rewritten" except AttributeError: pass #new.init.znucl = new.znucl #new.init.typat = new.typat #write_xyz(replic(new.init, (2,1,2)) , xyzpath) #test_adding_of_impurities(new, new_before, v) print_and_log("Impurity with Z=" + str(znucl) + " has been added to the found pore in " + new.name + "\n\n") if write_geo: write_xyz(new.init, xyzpath) new.write_geometry("init", new.des, override=override) print_and_log("\n") return new """0.Begin----------------------------------------------------------------------------""" znucl = element_name_inv(impurity_type) if impurity_type != 'octa' and impurity_type not in it_new: print_and_log("add_impurity: Your name 'it_new' is incorrect!\n\n") raise RuntimeError #del header.history[-2] # #hstring = ("add_impurity('%s', '%s', '%s', calc, %.3f, '%s', '%s', %s, '%s') #at %s" % # (it_new, impurity_type, addtype, r_pore, # it_to, ise_to, verlist_to, copy_geo_from, # datetime.date.today() ) ) hstring = ("%s #on %s" % (traceback.extract_stack(None, 2)[0][3], datetime.date.today())) if hstring != header.history[-1]: header.history.append(hstring) #geo_exists = """1. The case of insertion to existing calculations--------------------------------------------------""" if verlist_to: for v in verlist_to: if only_version and v not in only_version: continue # only_version = None works for all versions id = (it_to, ise_to, v) new = copy.deepcopy(calc[id]) new.init = new.end #replace init structure by the end structure new.version = v + add_to_version new.name = it_new #+'.'+id[1]+'.'+str(id[2]) new.des = 'Obtained from ' + str( id) + ' by adding ' + impurity_type + ' impurity ' path_new_geo = struct_des[ it_new].sfolder + "/" + it_new + "/" + it_new + '.imp.' + addtype + '.' + str( new.version) + '.' + 'geo' new.init.name = it_new + ".init." + str(new.version) xyzpath = struct_des[it_new].sfolder + "/" + it_new new.path["input_geo"] = geo_folder + path_new_geo print_and_log("File '" + new.path["input_geo"] + "' with impurity will be created\n") #new.init.name = 'test_before_add_impurity' new = add(znucl, xyzpath, new, write_geo, put_exactly_to=put_exactly_to) """2. The case of insertion to geo files------------------------------------------------------------""" else: """ Please rewrite using new functions """ print_and_log( "You does not set 'id' of relaxed calculation. I try to find geometry files in " + it_new + " folder\n") if it_to: geo_path = geo_folder + struct_des[it_to].sfolder + "/" + it_to else: geo_path = geo_folder + struct_des[ it_new].sfolder + "/" + it_new + '/from' if copy_geo_from: print_and_log("You asked to copy geo files from " + copy_geo_from + " to " + geo_path + " folder\n") #if not os.path.exists(os.path.dirname(geo_path)): runBash("mkdir -p " + geo_path) runBash("cp " + copy_geo_from + "/* " + geo_path) if os.path.exists(geo_path): print_and_log("Folder '" + geo_path + "' was found. Trying to add impurity\n") else: print_and_log("Error! Folder " + geo_path + " does not exist\n") raise RuntimeError #geofilelist = glob.glob(geo_path+'/*.geo*') #Find input_geofile #geofilelist = runBash('find '+geo_path+' -name "*grainA*.geo*" ').splitlines() #geofilelist = runBash('find '+geo_path+' -name "*.geo*" ').splitlines() geofilelist = glob.glob(geo_path + '/*.geo*') print_and_log("There are several files here already: ", geofilelist, imp='y') #print 'find '+geo_path+' -name "*.geo*" ',geofilelist #return for input_geofile in geofilelist: v = int(runBash("grep version " + str(input_geofile)).split()[1]) if only_version and v not in only_version: continue # only_version = None works for all versions new = CalculationVasp() new.version = v new.name = input_geofile new.read_geometry(input_geofile) init = copy.deepcopy(new) igl = input_geofile.split("/") #new.name = igl[-3]+'/'+igl[-3] #+input_geofile new.name = struct_des[it_new].sfolder + "/" + it_new + "/" + it_new print_and_log("New path and part of name of file is ", new.name, imp='Y') #return new.des = 'Obtained from ' + input_geofile + ' by adding ' + impurity_type + ' impurity ' #new.init.xred = new.xred #new.init.rprimd = new.rprimd #print new.rprimd new.init.name = new.name + '.imp.' + addtype + '.' + str( new.version) #new.path["input_geo"] = geo_folder+it_new+"/"+new.end.name+'.'+'geo' new.path[ "input_geo"] = geo_folder + "/" + new.init.name + '.' + 'geo' #new.init.name = 'test_before_add_impurity' new = add(znucl, "", new, write_geo, put_exactly_to=put_exactly_to) return new.path["input_geo"] #return for last version
def determine_barrier(positions=None, energies=None): """ The sign of barrier determined by the curvuture at saddle point. Minimum at saddle point corresponds to negative barrier The saddle point is determined as maximum deviation from energy in initial position """ import scipy if positions is None: positions = range(len(energies)) if energies is None: printlog('Error! Please provide at least energies') spl = scipy.interpolate.PchipInterpolator(positions, energies) spl_der = spl.derivative() spl_der2 = spl_der.derivative() mi = min(positions) ma = max(positions) r = spl_der.roots() # print(r) r = r[np.logical_and( mi < r, r < ma)] # only roots inside the interval are interesting e_at_roots = spl(r) if len(e_at_roots) > 0: # diff_barrier = max( e_at_roots ) # the maximum value printlog('roots are at ', r, e_at_roots) #find r for saddle point. the energy at saddle point is most far away from the energy at initial position by definition de_s = np.abs(e_at_roots - energies[0]) i_r_de_max = np.argmax(de_s) # print(de_s) # print(i_r_de_max) r_de_max = r[i_r_de_max] e = spl(r_de_max) curvuture_at_saddle = spl_der2(r_de_max) sign = -np.sign(curvuture_at_saddle) if curvuture_at_saddle < 0: critical_point_type = 'maximum' elif curvuture_at_saddle > 0: critical_point_type = 'minimum' else: critical_point_type = 'undefined' # print(type(r_de_max), type(e), critical_point_type) print('Saddle point at {:.2f} {:.2f} is a local {:}'.format( r_de_max, float(e), critical_point_type)) else: print_and_log('Warning! no roots') # diff_barrier = 0 sign = 1 mine = min(energies) maxe = max(energies) de = abs(mine - maxe) # if de > diff_barrier: diff_barrier = de * sign print('Migration barrier is {:.2f}'.format(diff_barrier)) # plt.plot(spl(np.linspace(0, ma, 1000))) # plt.show() return diff_barrier
def neb_analysis(cl, show, up=None, push2archive=None, old_behaviour=None, results_dic=None, fitplot_args=None, style_dic=None, params=None): """ Analyse traectories and polarons params mep_shift_vector """ def determing_rms_for_surrounding_atoms(sts): # change of rms on each step compared to first structure #here first and last structures should correspond to first and last images st1 = sts[0] st_interp = interpolate(sts[0], sts[-1], 1)[0] rms_list = [] for st in sts: rms = rms_pos_diff(st_interp, st) rms_list.append(rms) print('rms is {:.3f}'.format(rms)) print('d rms is {:.3f}'.format(abs(rms_list[3] - rms_list[0]))) rms_change = abs(min(rms_list) - max(rms_list)) return rms_change def determing_born_barrier(sts): #here first and last structures should correspond to first and last images local_born_e = [] i = find_moving_atom(sts[0], sts[-1]) for st in sts: local_born_e.append(site_repulsive_e(st, i)) # import matplotlib.pyplot as plt # plt.plot(local_born_e) # plt.show() return abs(min(local_born_e) - max(local_born_e)) if params is None: params = {} if results_dic is None: results_dic = {} calc = header.calc path2mep_s = cl.project_path_cluster + '/' + cl.dir + '/mep.eps' itise = cl.id[0] + '.' + cl.id[1] # print(cl.ldauu) # sys.exit() name_without_ext = 'mep.' + itise + '.U' + str(max(cl.ldauu)) path2mep_l = cl.dir + name_without_ext + '.eps' # print(path2mep_l) if not os.path.exists(path2mep_l) or '2' in up: '' get_from_server( files=path2mep_s, to_file=path2mep_l, addr=cl.cluster_address, ) movie_to = cl.dir + '/movie.xyz' get_from_server( files=cl.project_path_cluster + '/' + cl.dir + '/movie.xyz', to_file=movie_to, addr=cl.cluster_address, ) if os.path.exists(movie_to): makedir('figs/' + name_without_ext + '.xyz') shutil.copyfile(movie_to, 'figs/' + name_without_ext + '.xyz') # trying to get one image closest to the saddle point if old_behaviour and cl.version == 2: #old behaviour, now created automatically in add callc im = cl.set.vasp_params['IMAGES'] # if im % 2 > 0: #odd # i = im//2 + 1 # else: # i = im/2 # if choose_image: # i = choose_image for i in range(im): i += 1 cl_i = copy.deepcopy(cl) cl_i.version += i cl_i.id = (cl.id[0], cl.id[1], cl_i.version) cl_i.name = str(cl_i.id[0]) + '.' + str(cl_i.id[1]) + '.' + str( cl_i.id[2]) # print cl_i.name cl_i.path["output"] = cl_i.dir + '0' + str(i) + "/OUTCAR" # for i in range(): cl_i.associated_outcars = [ aso[2:] for aso in cl_i.associated_outcars ] # print cl_i.path["output"] cl_i.state = '2. Ready to read outcar' # if not os.path.exists(cl_i.path["output"]): # load = 'o' outst2 = ("%s" % cl_i.name).ljust(name_field_length) if readfiles: print(outst2 + '|' + cl_i.read_results( loadflag, show=show, choose_outcar=choose_outcar)) else: print_and_log(outst2 + ' | File was not read') if cl_i.id in calc: #move creation of calcs with images to add_neb '' # print_and_log('Please test code below this message to save prev calcs') # if cl_i != calc[cl_i.id] # if hasattr(calc[cl_i.id], 'prev') and calc[cl_i.id].prev: # prevlist = calc[cl_i.id].prev # else: # prevlist = [calc[cl_i.id]] # cl_i.prev = prevlist # calc[cl_i.id] = cl_i else: calc[cl_i.id] = cl_i # print path2mep_l if 0: if os.path.exists(path2mep_l): # get_from_server(file = path2mep_s, to = path2mep_l, addr = cluster_address) runBash('evince ' + path2mep_l) else: a = glob.glob(cl.dir + '*mep*') if a: runBash('evince ' + a[0]) cl1 = calc[cl.id[0], cl.id[1], 1] cl2 = calc[cl.id[0], cl.id[1], 2] atom_num = find_moving_atom(cl1.end, cl2.end) # cl1.poscar() # cl2.poscar() # print('atom_num',atom_num) # sys.exit() #prepare lists ni = cl.set.vasp_params['IMAGES'] vlist = [1] + list(range(3, ni + 3)) + [2] # print( vlist) mep_energies = [] atom_pos = [] pols = [] sts = [] sts_loc = [] dAO2 = [] # A-(O,F) distance for each image dAO4 = [] # A-(O,F) distance for each image dAO6 = [] dAO6harm = [] dAO6dev = [] for v in vlist: cli = calc[cl.id[0], cl.id[1], v] # if v == 1: # cli = db['NaVP2O7_a.su.s101015v100.n5Na1v1ms.ifn.1mls.1'] # print(cl.id[0], cl.id[1], v, cli.state) if '4' not in cli.state and 'un' not in up: printlog('Attention! res_loop(): analys_type == neb, Calc', cli.id, 'is not finished; return') return {}, [] # print cli.id # cli.end = return_to_cell(cli.end) # mep_energies.append( min(cli.list_e_sigma0) ) #use minimum energy - not very good, sometimes unconverged energy could be lower! e0 = cli.energy_sigma0 if params and params.get( 'neb_penult_e' ): # allows to take e from the previous relaxation step in case the calculation was aborted e0 = cli.list_e_sigma0[-2] mep_energies.append(e0) #use last energy atom_pos.append(cli.end.xcart[atom_num]) # Find polaron positions if 'polaron' in show: # if 1 cause error for nomag calc pol, mag = find_polaron(cli.end, atom_num) if pol: for key in pol: if np.any(pol[key]): for n in pol[key]: if n not in pols: pols.append(n) else: '' # print('Mag_moments on trans,', mag.round(1)) if 0 or 'neb_geo' in show: #visualization of path # print(atom_num) st = copy.deepcopy(cli.end) # print('moving_atom', st.xcart[atom_num]) info = st.nn(atom_num, 15, from_one=False, silent=1) st.moving_atom_i = atom_num st_loc = info['st'] # print(st_loc.xcart) # st_loc = st_loc.shift if v == vlist[0]: st1 = copy.deepcopy(st) vec = st.center_on(atom_num) # vec = np.asarray([0.,0.,0.]) if params is not None and 'mep_shift_vector' in params: # vec += np.array([0.11,0.11,0]) # path4 # print(params['mep_shift_vector']) vec += np.array(params['mep_shift_vector']) # path4 # print(vec) st_loc = st_loc.shift_atoms(vec) if 0: st_loc.write_xyz() # st.write_cif('xyz/'+st.name) if 0: st.shift_atoms(vec).write_xyz() sts_loc.append(st_loc) st1 = st1.add_atom(st.xred[atom_num], 'Rb') sts.append(st.shift_atoms(vec)) if 0 or 'neb_geo2' in show: printlog('\n\nVersion {:}:'.format(v), imp='y') info1 = st.nn(atom_num, 2, from_one=False, silent=1, more_info=1) print('Av. dist A-2(O,F) {:.3f} A'.format( info1['av(A-O,F)'])) # print('Av. squared dist A-2(O,F) {:.3f} A'.format(info1['avsq(A-O,F)'])) dAO2.append(info1['av(A-O,F)']) info12 = st.nn(atom_num, 3, from_one=False, silent=1) print('Average distance A-3(O,F) {:.2f} A'.format( info12['av(A-O,F)'])) info2 = st.nn(atom_num, 4, from_one=False, silent=1) print('Average distance A-4(O,F) {:.2f} A'.format( info2['av(A-O,F)'])) dAO4.append(info2['av(A-O,F)']) info3 = st.nn(atom_num, 6, from_one=False, silent=1, more_info=1) print('Average_distance A-6(O,F) {:.2f} A '.format( info3['av(A-O,F)'])) print('Av. harm. dist A-6(O,F) {:.2f} A'.format( info3['avharm(A-O,F)'])) print('Average_deviation A-6(O,F) {:.1f} mA'.format( info3['avdev(A-O,F)'])) dAO6.append(info3['av(A-O,F)']) dAO6dev.append(info3['avdev(A-O,F)']) dAO6harm.append(info3['avharm(A-O,F)']) if 'neb_rms' in show: rms_change = determing_rms_for_surrounding_atoms(sts) results_dic['rms_change'] = rms_change if 'neb_born' in show: results_dic['born_barrier'] = determing_born_barrier(sts) print('Born barrier is {:.2f} eV '.format(results_dic['born_barrier'])) # print(results_dic['rms_change']) # print('show is', show) # sys.exit() # print('flag ', 'neb_noxyz' not in show, show) if 'neb_noxyz' not in show and sts: write_xyz(sts=sts) # write traectory write_xyz(sts=sts_loc) # write traectory if 'jmol' in params: write_xyz(sts=sts, jmol=1, jmol_args=params['jmol']) # write jmol st1 = st1.shift_atoms(vec) st1.name += '_all' # st1.write_cif('xyz/'+st1.name) st1.write_xyz() if dAO2: # find maximum change of distance during migration dAO2_change = abs(min(dAO2) - max(dAO2)) results_dic['dAO2_change'] = dAO2_change if dAO4: # find maximum change of distance during migration dAO4_change = abs(min(dAO4) - max(dAO4)) results_dic['dAO4_change'] = dAO4_change if dAO6: # dAO6_change = abs(min(dAO6) - max(dAO6)) results_dic['dAO6_change'] = dAO6_change if dAO6harm: # results_dic['dAO6harm_change'] = abs(min(dAO6harm) - max(dAO6harm)) if dAO6dev: # results_dic['dAO6dev_change'] = abs(min(dAO6dev) - max(dAO6dev)) results_dic[ 'sts_loc'] = sts_loc # list of local structures, each structure contains dlist - distances from central cation to anions, and ellist - types of elements results_dic[ 'sts'] = sts # list of mep structures, each structure contains moving_atom_i - number of moving atom if len(pols) > 0: print( 'During migration of alkali ions polarons are detected on atoms:', pols) elif len(pols) > 1: printlog( 'Attention! polaron is moving during migration! Obtained barrier is ambiguous' ) else: printlog( 'Compare magnetic moments above! In principle should be the same!') # print np.array(atom_pos) #test if the distances between points are not spoiled by PBC nbc = range(-1, 2) jj = 0 for x in atom_pos: x2 = atom_pos[jj + 1] # x = np.array(x) # x2 = np.array(x2) r = cl.end.rprimd d1, _ = image_distance(x, x2, r, order=1) #minimal distance x2_gen = (x2 + (r[0] * i + r[1] * j + r[2] * k) for i in nbc for j in nbc for k in nbc) #generator over PBC images x2c = copy.deepcopy(x2) ii = 0 while np.linalg.norm(x - x2c) > d1: #find the closest PBC image position if ii > 100: break ii += 1 x2c = next(x2_gen) atom_pos[jj + 1] = x2c jj += 1 if jj == len( atom_pos ) - 1: # the last point is not needed, we could not use slice since we need to use changed atom_pos in place break # print np.linalg.norm(x - x2c), d1 _, diff_barrier = plot_mep(atom_pos, mep_energies, plot=0, show=0, fitplot_args=fitplot_args, style_dic=style_dic) results_dic['barrier'] = diff_barrier middle_image = len(vlist) // 2 results_dic['dEm1'] = mep_energies[middle_image] - mep_energies[0] cl1.barrier = diff_barrier cl2.barrier = diff_barrier results_dic['atom_pos'] = [list(pos) for pos in atom_pos] results_dic['mep_energies'] = mep_energies if 'mep' in show: if 'mepp' in show: show_flag = True else: show_flag = False # sys.exit() plot_mep(atom_pos, mep_energies, image_name='figs/' + name_without_ext + '_my.eps', show=show_flag, fitplot_args=fitplot_args, style_dic=style_dic) if push2archive: path2saved, _ = plot_mep(atom_pos, mep_energies, image_name='figs/' + name_without_ext + '_my', fitplot_args=fitplot_args, style_dic=style_dic) push_figure_to_archive(local_figure_path=path2saved, caption=description_for_archive) if 0: #copy files according to chosen outcar to run nebresults locally wd = cl_i.dir out_i = cl_i.associated_outcars[choose_outcar - 1] out_1 = calc[cl.id[0], cl.id[1], 1].associated_outcars[choose_outcar - 1] out_2 = calc[cl.id[0], cl.id[1], 2].associated_outcars[choose_outcar - 1] # print out_1 # print out_2 shutil.copyfile(wd + out_1, wd + '00/OUTCAR') shutil.copyfile(wd + out_2, wd + '04/OUTCAR') for d in ['01/', '02/', '03/']: shutil.copyfile(wd + d + out_i, wd + d + 'OUTCAR') # print wd+d+out_i return results_dic
def add_neb(starting_calc=None, st=None, st_end=None, it_new=None, ise_new=None, i_atom_to_move=None, up='up2', search_type='vacancy_creation', images=None, r_impurity=None, calc_method=['neb'], inherit_option=None, mag_config=None, i_void_start=None, i_void_final=None, atom_to_insert=None, atom_to_move=None, rep_moving_atom=None, end_pos_types_z=None, replicate=None, it_new_folder=None, it_folder=None, inherit_magmom=False, x_start=None, xr_start=None, x_final=None, xr_final=None, upload_vts=False, center_on_moving=True, run=False, add_loop_dic=None, old_behaviour=None, params=None): """ 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* - None - just use st and st2 as initial and final ###INPUT: - starting_calc (Calculation) - Calculation object with structure - st (Structure) - structure, can be used instead of Calculation - it_new (str) - name for calculation - st_end (Structure) - final structure - i_atom_to_move (int) - number of atom for moving starting from 0; - *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) - position numbers of voids (or atoms) from the suggested lists - atom_to_insert (str) - element name of atom to insert - atom_to_move (str) - element name of atom to move - it_new_folder or it_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 - end_pos_types_z (list of int) - list of Z - type of atoms, which could be considered as final positions in vacancy creation mode - calc_method (list) - 'neb' - 'only_neb' - run only footer - x_start, x_final (array) - explicit xcart coordinates of moving atom for starting and final positions, combined with atom_to_insert - xr_start, xr_final (array) - explicit xred - rep_moving_atom (str)- replace moving atom by needed atom - can be useful than completly different atom is needed. - upload_vts (bool) - if True upload Vasp.pm and nebmake.pl to server - run (bool) - run on server - old_behaviour (str) - choose naming behavior before some date in the past for compatibility with your projects '020917' '261018' - after this moment new namig convention applied if end_pos_types_z is used - add_loop_dic - standart parameters of add() - params (dic) - provide additional parameters to add() # should be removed ###RETURN: None ###DEPENDS: ###TODO 1. Take care of manually provided i_atom_to_move in case of replicate flag using init_numbers 2. For search_type == None x_m and x_del should be determined for magnetic searching and for saving their coordinates to struct_des; now their just (0,0,0) """ naming_conventions209 = True # set False to reproduce old behavior before 2.09.2017 if old_behaviour == '020917': naming_conventions209 = False # # print('atom_to_insert', atom_to_insert) # sys.exit() calc = header.calc struct_des = header.struct_des varset = header.varset if not add_loop_dic: add_loop_dic = {} if not end_pos_types_z: end_pos_types_z = [] end_pos_types_z = sorted(end_pos_types_z) 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*') corenum = add_loop_dic.get('corenum') # print(corenum) # sys.exit() if corenum == None: if images == 3: corenum = 15 elif images == 5: corenum = 15 elif images == 7: corenum = 14 else: printlog('add_neb(): Error! number of images', images, 'is unknown to me; please provide corenum!') # print(corenum) # sys.exit() # print(atom_to_insert) # sys.exit() 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', images, corenum) if not ise_new: ise_new = starting_calc.id[1] printlog('I use', ise_new, 'as ise_new', imp='y') 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]) printlog('Search type is ', search_type) if search_type == None: if st_end == None: printlog( 'Error! You have provided search_type == None, st_end should be provided!' ) st1 = st st2 = st_end x_m = (0, 0, 0) x_del = (0, 0, 0) else: """1. Choose atom (or insert) for moving """ if is_list_like(xr_start): x_start = xred2xcart([xr_start], st.rprimd)[0] # print('atom_to_insert', atom_to_insert) # sys.exit() st1, i_m = st.add_atoms([x_start], atom_to_insert, return_ins=1) x_m = x_start # i_m = st1.find_atom_num_by_xcart(x_start) # print(st1.get_elements()[i_m]) # sys.exit() if i_atom_to_move: nn = str(i_atom_to_move + 1) else: nn = str(i_void_start) name_suffix += atom_to_insert + nn write_xyz(st1, file_name=st.name + '_manually_start') printlog('Start position is created manually by adding xr_start', xr_start, x_start) type_atom_to_move = atom_to_insert el_num_suffix = '' else: atoms_to_move = [] atoms_to_move_types = [] # print('d', i_atom_to_move) # sys.exit() if i_atom_to_move: typ = st.get_elements()[i_atom_to_move] printlog('add_neb(): atom', typ, 'will be moved', imp='y') atoms_to_move.append( [i_atom_to_move, typ, st.xcart[i_atom_to_move]]) atoms_to_move_types.append(typ) if naming_conventions209: name_suffix += typ + str(i_atom_to_move + 1) else: #try to find automatically among alkali - special case for batteries for i, typ, x in zip(range(st.natom), st.get_elements(), st.xcart): if typ in ['Li', 'Na', 'K', 'Rb', 'Mg']: atoms_to_move.append([i, typ, x]) if typ not in atoms_to_move_types: atoms_to_move_types.append(typ) if atoms_to_move: # print(atom_to_move) # sys.exit() if not atom_to_move: atom_to_move = atoms_to_move_types[ 0] # taking first found element if len(atoms_to_move_types) > 1: printlog( 'Error! More than one type of atoms available for moving detected', atoms_to_move_types, 'please specify needed atom with *atom_to_move*') type_atom_to_move = atom_to_move #atoms_to_move[0][1] # printlog('atom ', type_atom_to_move, 'will be moved', imp ='y') if i_atom_to_move: printlog('add_neb(): *i_atom_to_move* = ', i_atom_to_move, 'is used', imp='y') numbers = [[i_atom_to_move]] i_void_start = 1 else: printlog('add_neb(): determine_symmetry_positions ...', imp='y') numbers = determine_symmetry_positions(st, atom_to_move) # print(numbers) # sys.exit() if len(numbers) > 0: printlog('Please choose position using *i_void_start* :', [i + 1 for i in range(len(numbers))], imp='y') printlog('*i_void_start* = ', i_void_start) i_m = numbers[i_void_start - 1][0] printlog('Position', i_void_start, 'chosen, atom:', i_m + 1, type_atom_to_move, imp='y') else: i_m = numbers[0][0] x_m = st.xcart[i_m] el_num_suffix = type_atom_to_move + str(i_m + 1) atom_to_insert = atom_to_move st1 = st # elif atom_to_replace: # num = st.get_specific_elements(atom_to_replace) # if len(n)>0: # printlog('Please choose position using *i_void_start* :', [i+1 for i in range(len(num))],imp = 'y' ) # printlog('*i_void_start* = ', i_void_start) # i_m = num[i_void_start-1] # printlog('Position',i_void_start,'chosen, atom to replace:', i_m+1, atom_to_replace, imp = 'y' ) # sys.exit() else: print_and_log( 'No atoms to move found, you probably gave me deintercalated structure', important='y') st_pores, sums, avds = determine_voids(st, r_impurity, step_dec=0.1, fine=2) insert_positions = determine_unique_voids(st_pores, sums, avds) print_and_log( 'Please use *i_void_start* to choose the void for atom insertion from the Table above:', end='\n', imp='Y') if i_void_start == None: sys.exit() if atom_to_insert == None: printlog('Error! atom_to_insert = None') 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 = '' st1 = st """2. Choose final position""" if is_list_like(xr_final): x_final = xred2xcart([xr_final], st.rprimd)[0] #old #check if i_atom_to_move should be removed # st2 = st1.del_atom(i_m) # st2 = st2.add_atoms([x_final], atom_to_insert) #new st2 = st1.mov_atoms(i_m, x_final) # st1.printme() # st2.printme() # sys.exit() x_del = x_final search_type = 'manual_insertion' name_suffix += 'v' + str(i_void_final) 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, sums, avds = determine_voids(st, r_impurity) sur = determine_unique_final(st_pores, sums, avds, x_m) print_and_log('Please choose *i_void_final* from the Table above:', end='\n', imp='Y') if i_void_final == None: sys.exit() x_final = sur[0][i_void_final] # printlog('You chose:', np.array(x_final).round(2), end='\n', imp='Y') x_del = x_final #please compare with vacancy creation mode write_xyz(st.add_atoms([x_final], 'H'), replications=(2, 2, 2), file_name=st.name + '_possible_positions2_replicated') print_and_log('Choosing the closest position as end', important='n') st1 = st 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', imp='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) final_pos_z = end_pos_types_z or [ invert(type_atom_to_move) ] # by default only moving atom is considered end_pos_types_el = [invert(z) for z in end_pos_types_z] sur = local_surrounding(x_m, st, n_neighbours=14, control='atoms', only_elements=final_pos_z, periodic=True) #exclude the atom itself # print(x_m) # print(sur) # st.nn() end_pos_n = sur[2][1:] print_and_log( 'I can suggest you ' + str(len(end_pos_n)) + ' end positions. The distances to them are : ', np.round(sur[3][1:], 2), ' A\n ', 'They are ', [invert(z) for z in final_pos_z], 'atoms, use *i_void_final* to choose required: 1, 2, 3 ..', imp='y') i_sym_final_l = [] for j in end_pos_n: for i, l in enumerate(numbers): if j in l: i_sym_final_l.append(i + 1) printlog('Their symmetry positions are ', i_sym_final_l, imp='y') # sys.exit() if not i_void_final: printlog('Changing i_void_final: None -> 1', imp='y') i_void_final = 1 #since zero is itself chosen_dist = sur[3][i_void_final] print_and_log('Choosing position ', i_void_final, 'with distance', round(chosen_dist, 2), 'A', imp='y') # print(end_pos_n) i_sym_final = 0 n_final = sur[2][i_void_final] for i, l in enumerate(numbers): if n_final in l: i_sym_final = i + 1 printlog('It is symmetrically non-equiv position #', i_sym_final, imp='y') # sys.exit() header.temp_chosen_dist = chosen_dist if old_behaviour == '261018': name_suffix += el_num_suffix + 'v' + str(i_void_final) else: name_suffix += el_num_suffix + 'v' + str( i_void_final) + list2string(end_pos_types_el, joiner='') # print(name_suffix) # sys.exit() x_del = sur[0][i_void_final] printlog('xcart of atom to delete', x_del) i_del = st.find_atom_num_by_xcart(x_del) # print(x_del) # print(st.xcart) # for x in st.xcart: # if x[0] > 10: # print(x) print_and_log('number of atom to delete = ', i_del, imp='y') if i_del == None: printlog('add_neb(): Error! I could find atom to delete!') # print st.magmom # print st1.magmom # try: if is_list_like(xr_start): st2 = st1.mov_atoms( i_m, x_del) # i_m and sur[0][neb_config] should coincide # i_del = st1.find_atom_num_by_xcart(x_del) st1 = st1.del_atom(i_del) else: print_and_log( 'Making vacancy at end position for starting configuration', imp='y') st1 = st.del_atom(i_del) 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 # except: # st2 = st st2 = st2.del_atom(i_del) # these two steps provide the same order """Checking correctness of path""" #if start and final positions are used, collisions with existing atoms are possible if is_list_like(xr_start) and is_list_like(xr_final): printlog('Checking correctness') st1, _, _ = st1.remove_close_lying() stt = st1.add_atoms([ x_final, ], 'Pu') stt, x, _ = stt.remove_close_lying( rm_both=True ) # now the final position is empty for sure; however the order can be spoiled # print(st._removed) if stt._removed: st1 = stt # only if overlapping was found we assign new structure st2, _, _ = st2.remove_close_lying(rm_first=stt._removed) stt = st2.add_atoms([ x_start, ], 'Pu') stt, x, _ = stt.remove_close_lying( rm_both=True) # now the start position is empty for sure if stt._removed: st2 = stt print(st2.get_elements()) # sys.exit() elif is_list_like(xr_final) and not is_list_like(xr_start) or is_list_like( xr_start) and not is_list_like(xr_final): printlog( 'Attention! only start or final position is provided, please check that everything is ok with start and final states!!!' ) """ Determining magnetic moments """ vp = varset[ise_new].vasp_params if 'ISPIN' in vp and vp['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 if search_type != None: # for None not implemented; x_m should be determined first for this #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 and not it_folder: printlog( 'Error! please provide *it_new_folder* - folder for your new calculation', important='Y') if it_folder: it_new_folder = it_folder if rep_moving_atom: it_new += 'r' + rep_moving_atom 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 if search_type is not None: struct_des[it_new].x_m_ion_start = x_m struct_des[it_new].xr_m_ion_start = xcart2xred([x_m], st1.rprimd)[0] # st1, _, _ = st1.remove_close_lying() # st2, _, _ = st2.remove_close_lying() print('Trying to find x_m', x_m) i1 = st1.find_atom_num_by_xcart( x_m, prec=0.45, ) # sys.exit() print('Trying to find x_del', x_del) i2 = st2.find_atom_num_by_xcart( x_del, prec=0.45, ) if rep_moving_atom: #replace the moving atom by required st1 = st1.replace_atoms([i1], rep_moving_atom) st2 = st2.replace_atoms([i2], rep_moving_atom) else: #allows to make correct order for nebmake.pl st1 = st1.replace_atoms([i1], type_atom_to_move) st2 = st2.replace_atoms([i2], type_atom_to_move) i1 = st1.find_atom_num_by_xcart( x_m, prec=0.45) # the positions were changed # check if this is correct i2 = st2.find_atom_num_by_xcart(x_del, prec=0.45) 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_'+str(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_'+str(search_type)+'.'+str(ver_new)+'.'+'geo' cl.write_siman_geo(geotype='end', description='Final conf. for neb from ' + obtained_from, override=True) if not rep_moving_atom and search_type is not None: st1s = st1.replace_atoms([i1], 'Pu') st2s = st2.replace_atoms([i2], 'Pu') else: st1s = copy.deepcopy(st1) st2s = copy.deepcopy(st2) if center_on_moving and search_type is not None: vec = st1.center_on(i1) st1s = st1s.shift_atoms(vec) st2s = st2s.shift_atoms(vec) write_xyz(st1s, file_name=it_new + '_start') write_xyz(st2s, file_name=it_new + '_end') st1s.write_poscar('xyz/POSCAR1') st2s.write_poscar('xyz/POSCAR2') # print(a) # runBash('cd xyz; mkdir '+it_new+'_all;'+"""for i in {00..04}; do cp $i/POSCAR """+ it_new+'_all/POSCAR$i; done; rm -r 00 01 02 03 04') with cd('xyz'): a = runBash(header.PATH2NEBMAKE + ' POSCAR1 POSCAR2 3') print(a) dst = it_new + '_all' makedir(dst + '/any') for f in ['00', '01', '02', '03', '04']: shutil.move(f + '/POSCAR', dst + '/POSCAR' + f) shutil.rmtree(f) #prepare calculations # sys.exit() #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]) if run: add_loop_dic['run'] = run add_loop_dic['corenum'] = corenum # print(add_loop_dic) add_loop( it_new, ise_new, verlist=[1, 2], up=up, calc_method=calc_method, savefile='oc', inherit_option=inherit_option, n_neb_images=images, # params=params, **add_loop_dic) 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') printlog('add_neb finished') return it_new