def write(st): rprimd, xcart, xred, typat, znucl, natom = update_var(st) f.write(str(natom + len(imp_positions) - nsub + nvect) + "\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) if el == 'void': el = 'Pu' f.write(el + " ") f.write("%.5f %.5f %.5f \n" % (xcart[i][0], xcart[i][1], xcart[i][2])) if include_vectors: for r in st.rprimd: f.write('Tv {:.10f} {:.10f} {:.10f}\n'.format(*r))
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 plot_dos( cl1, cl2=None, dostype=None, iatom=None, iatom2=None, orbitals=('s'), up=None, neighbors=6, show=1, labels=None, path='dos', xlim=(None, None), ylim=(None, None), savefile=True, plot_param={}, suf2='', fontsize=8, nsmooth=12, lts2='--', split_type='octa', plot_spin_pol=1, show_gravity=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 also to sum around neigbours use p6 and d6 and neighbors parameter up - 'up2' allows to download the file once again labels - two manual labels for cl1 and cl2 instead of auto iatom (int) - number of atom starting from 1 to plot DOS; 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 using p6 or d6; only p6 is implemented to the moment in plot section xlim, ylim (tuple)- limits for plot plot_param - dict of parameters to fit_and_plot dashes - control of dahsed lines suf2 - additional suffix # nsmooth = 15 # smooth of dos lts2 - style of lines for cl2 split_type - octa - the names are t2g and eg tetra - the names are t2 and e plot_spin_pol - 0 - spin-polarized components are summed up show_gravity (list) - print gravity centers (i, type, range, ); i - 1 or 2 cl type (str) 'p6' - for p orbitals of neighbors 'p' #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. """ if fontsize: header.mpl.rcParams.update({'font.size': fontsize + 4}) header.mpl.rc('legend', fontsize=fontsize) if dostype == 'partial': eld1, eld2 = {}, {} for i, el in enumerate(cl1.end.get_elements()): eld1[i + 1] = el if cl2: for i, el in enumerate(cl2.end.get_elements()): eld2[i + 1] = el if not iatom: printlog( 'Warning! Please choose atom number *iatom* from the following list:\n' ) printlog(eld) sys.exit() else: printlog('cl1: Atom', iatom, 'of type', eld1[iatom], 'is choosen', imp='y') printlog('cl1: Atom numbers:', eld1, imp='y') printlog('cl1:', determine_symmetry_positions(cl1.end, eld1[iatom]), imp='y') # print(cl2) if cl2: if not iatom2: printlog('Error! provide iatom2!') printlog('cl2: Atom', iatom2, 'of type', eld2[iatom2], 'is choosen', imp='y') printlog('cl2:', determine_symmetry_positions(cl2.end, eld2[iatom2]), imp='y') if iatom: iatom -= 1 if cl2: if not iatom2: printlog('Error!, provide *iatom2*!') iatom2 -= 1 if 'figsize' not in plot_param: plot_param['figsize'] = (4, 6) if 'legend' not in plot_param: plot_param['legend'] = 'best' """1. Read dos""" printlog("------Start plot_dos()-----", imp='Y') dos = [] # main list for cl1 and cl2 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', nametype='asoutcar') 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 if len(dos[0].dos) == 2: spin_pol = True else: spin_pol = False gc = None """2. Plot dos for different cases""" if dostype == 'total': # print(dos[0].dos) ylabel = "DOS (states/eV)" if spin_pol: dosplot = { 'Tot up': { 'x': dos[0].energy, 'y': smoother(dos[0].dos[0], 10), 'c': 'b', 'ls': '-' }, 'Tot down': { 'x': dos[0].energy, 'y': -smoother(dos[0].dos[1], 10), 'c': 'r', 'ls': '-' } } else: dosplot = { 'Total': { 'x': dos[0].energy, 'y': smoother(dos[0].dos, 10), 'c': 'b', 'ls': '-' } } # args[nam_down] = {'x':d.energy, 'y':-smoother(d.site_dos(iat, i_orb_down[orb]), nsmooth), 'c':color[orb], 'ls':l, 'label':None} # xlabel = "Energy (eV)", ylabel = "DOS (states/eV)" # print(plot_param) image_name = os.path.join(path, cl1.name + '.dosTotal') fit_and_plot(show=show, image_name=image_name, hor=True, **plot_param, **dosplot) elif dostype == 'diff_total': #no spin-polarized!!!! ylabel = "DOS (states/eV)" 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)", hor=True, **plot_param, 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 ylabel = "PDOS (states/atom/eV)" 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, imp = 'y') 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, imp='y') 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] els = cl1.end.get_elements() el_sur = els[numbers[1]] # element of surrounding type printlog("Numbers of local atoms:", [n + 1 for n in numbers], imp='Y') printlog("Elements of local atoms:", [els[i] for i in numbers], imp='Y') printlog("List of distances", [round(d, 2) for d in local_atoms[3]], imp='Y') iX = numbers[0] # first atom is impurity if exist # printlog numbers_list = [numbers] # numbers_list is list of lists calcs = [cl1] if cl2: numbers_list.append([iatom2]) # for cl2 only one atom is supported calcs.append(cl2) for cl, d, numbers in zip(calcs, dos, numbers_list): d.p = [] #central and surrounding d.d = [] d.p_up = [] d.p_down = [] d.p_down = [] #central and and surrounding d.d_up = [] #central atom and surrounding atoms d.d_down = [] #central atom and surrounding atoms d.t2g_up = [] d.t2g_down = [] d.eg_up = [] d.eg_down = [] d.p_all = [] #sum over all atoms d.d_all = [] #sum over all atoms d.p_all_up = [] #sum over all atoms d.d_all_up = [] #sum over all atoms d.p_all_down = [] #sum over all atoms d.d_all_down = [] #sum over all atoms if 'p_all' in orbitals or 'd_all' in orbitals: #sum over all atoms p = [] p_up = [] p_down = [] dd = [] d_up = [] d_down = [] els = cl.end.get_elements() for i in range(cl.end.natom): # if 'O' not in els[i]: # continue if spin_pol: plist_up = [d.site_dos(i, l) for l in (2, 4, 6)] plist_down = [d.site_dos(i, l) for l in (3, 5, 7)] plist = plist_up + plist_down p_up.append([sum(x) for x in zip(*plist_up)]) p_down.append([sum(x) for x in zip(*plist_down)]) p.append([sum(x) for x in zip(*plist)]) else: plist = [d.site_dos(i, l) for l in (1, 2, 3)] p.append([sum(x) for x in zip(*plist)]) if spin_pol: dlist_up = [ d.site_dos(i, l) for l in (8, 10, 12, 14, 16) ] # dlist_down = [ d.site_dos(i, l) for l in (9, 11, 13, 15, 17) ] # dlist = dlist_up + dlist_down d_up.append([sum(x) for x in zip(*dlist_up)]) d_down.append([sum(x) for x in zip(*dlist_down)]) dd.append([sum(x) for x in zip(*dlist)]) else: dlist = [d.site_dos(i, l) for l in (4, 5, 6, 7, 8)] # dd.append([sum(x) for x in zip(*dlist)]) d.p_all = [sum(pi) for pi in zip(*p)] #sum over all atoms d.d_all = [sum(di) for di in zip(*dd)] if spin_pol: d.p_all_up = [sum(pi) for pi in zip(*p_up)] d.p_all_down = [sum(pi) for pi in zip(*p_down)] d.d_all_up = [sum(pi) for pi in zip(*d_up)] d.d_all_down = [sum(pi) for pi in zip(*d_down)] #sum by surrounding atoms atoms n_sur = len(numbers) for i in numbers: #Now for surrounding atoms in numbers list: if spin_pol: plist_up = [d.site_dos(i, l) for l in (2, 4, 6)] plist_down = [d.site_dos(i, l) for l in (3, 5, 7)] d.p_up.append([sum(x) for x in zip(*plist_up)]) d.p_down.append([sum(x) for x in zip(*plist_down)]) plist = plist_up + plist_down d.p.append([sum(x) for x in zip(*plist)]) else: plist = [d.site_dos(i, l) for l in (1, 2, 3)] d.p.append([sum(x) for x in zip(*plist)]) if spin_pol: dlist_up = [d.site_dos(i, l) for l in (8, 10, 12, 14, 16)] # dlist_down = [ d.site_dos(i, l) for l in (9, 11, 13, 15, 17) ] # dlist = dlist_up + dlist_down d.d.append([sum(x) for x in zip(*dlist)]) d.d_up.append([sum(x) for x in zip(*dlist_up)]) d.d_down.append([sum(x) for x in zip(*dlist_down)]) t2g_down = [d.site_dos(i, l) for l in (9, 11, 15)] eg_down = [d.site_dos(i, l) for l in (13, 17)] t2g_up = [d.site_dos(i, l) for l in (8, 10, 14)] eg_up = [d.site_dos(i, l) for l in (12, 16)] d.t2g_down.append([sum(x) for x in zip(*t2g_down)]) d.eg_down.append([sum(x) for x in zip(*eg_down)]) d.t2g_up.append([sum(x) for x in zip(*t2g_up)]) d.eg_up.append([sum(x) for x in zip(*eg_up)]) else: dlist = [d.site_dos(i, l) for l in (4, 5, 6, 7, 8)] # d.d.append([sum(x) for x in zip(*dlist)]) d.p6 = [sum(pi) / n_sur for pi in zip(*d.p) ] #sum over neighbouring atoms now only for spin up if spin_pol: d.p6_up = [sum(pi) / n_sur for pi in zip(*d.p_up) ] #sum over neighbouring atoms now only for spin up d.p6_down = [ sum(pi) / n_sur for pi in zip(*d.p_down) ] #sum over neighbouring atoms now only for spin up d.d6 = [sum(di) for di in zip(*d.d)] #sum over neighbouring atoms """Plotting""" # nsmooth = 15 # smooth of dos d1 = dos[0] ds = [d1] names = [] names = [cl1.id[0] + '_at_' + eld1[iatom + 1] + str(iatom + 1)] atoms = [iatom] els = [eld1[iatom + 1]] lts = [ '-', ] #linetypes if cl2: ds.append(dos[1]) d2 = dos[1] # if labels: # names.append(labels[1]) # else: names.append(cl2.id[0] + '_at_' + eld2[iatom2 + 1] + str(iatom2 + 1)) lts.append(lts2) atoms.append(iatom2) els.append(eld2[iatom2 + 1]) if not spin_pol: plot_spin_pol = 0 # could not plot spin polarization for non-spin polarization plot if 'dashes' in plot_param: dashes = plot_param['dashes'] del plot_param['dashes'] else: dashes = (5, 1) energy1 = dos[0].energy args = {} if spin_pol: i_orb = { 's': 0, 'py': 2, 'pz': 4, 'px': 6, 'dxy': 8, 'dyz': 10, 'dz2': 12, 'dxz': 14, 'dx2': 16 } i_orb_down = { 's': 1, 'py': 3, 'pz': 5, 'px': 7, 'dxy': 9, 'dyz': 11, 'dz2': 13, 'dxz': 15, 'dx2': 17 } else: i_orb = { 's': 0, 'py': 1, 'pz': 2, 'px': 3, 'dxy': 4, 'dyz': 5, 'dz2': 6, 'dxz': 7, 'dx2': 8 } # color = {'s':'k', 'p':'#F14343', 'd':'#289191', 'py':'g', 'pz':'b', 'px':'c', 'dxy':'m', 'dyz':'c', 'dz2':'k', 'dxz':'r', 'dx2':'g', 't2g':'b', 'eg':'g', 'p6':'k'} color = { 's': 'k', 'p': '#FF0018', 'd': '#138BFF', 'py': 'g', 'pz': 'b', 'px': 'c', 'dxy': 'm', 'dyz': 'c', 'dz2': 'k', 'dxz': 'r', 'dx2': 'g', 't2g': '#138BFF', 'eg': '#8E12FF', 'p6': '#FF0018', 'p_all': 'r', 'd_all': 'b' } #http://paletton.com/#uid=54-100kwi++bu++hX++++rd++kX # color = {'s':'k', 'p':'r', 'd':'g', 'py':'g', 'pz':'b', 'px':'c', 'dxy':'m', 'dyz':'c', 'dz2':'m', 'dxz':'r', 'dx2':'g'} for orb in orbitals: i = 0 for n, l, iat, el, d in zip(names, lts, atoms, els, ds): if el in ['Fe', 'Co', 'V', 'Mn', 'Ni'] and orb in ['p', 's']: continue if el == 'O' and orb in ('d', 't2g', 'eg', 'dxy', 'dyz', 'dxz', 'dz2', 'dx2'): continue nam = orb nam_down = nam + '_down' # print('name', n) # print('lts', l) if labels: formula = labels[i] else: formula = latex_chem(n.split('.')[0]) i += 1 if spin_pol: nam += '' suf = '; ' + n nam += suf nam_down += suf if orb == 'p': if plot_spin_pol: args[nam] = { 'x': d.energy, 'y': smoother(d.p_up[0], nsmooth), 'c': color[orb], 'ls': l, 'label': formula + ' ' + el + suf2 + ' ' + orb, 'dashes': dashes } args[nam_down] = { 'x': d.energy, 'y': -smoother(d.p_down[0], nsmooth), 'c': color[orb], 'ls': l, 'label': None, 'dashes': dashes } color[orb] = 'c' else: args[nam] = { 'x': d.energy, 'y': smoother(d.p[0], nsmooth), 'c': color[orb], 'ls': l, 'label': formula + ' ' + el + suf2 + ' ' + orb, 'dashes': dashes } elif orb == 'p6': # now spin-polarized components could not be shown if plot_spin_pol: args[nam] = { 'x': d.energy, 'y': smoother(d.p6_up, nsmooth), 'c': color[orb], 'ls': l, 'label': formula + ' ' + el_sur + suf2 + ' p', 'dashes': dashes } args[nam_down] = { 'x': d.energy, 'y': -smoother(d.p6_down, nsmooth), 'c': color[orb], 'ls': l, 'label': None, 'dashes': dashes } else: args[nam] = { 'x': d.energy, 'y': smoother(d.p6, nsmooth), 'c': color[orb], 'ls': l, 'label': formula + ' ' + el_sur + suf2 + ' p', 'dashes': dashes } elif orb == 'd': if plot_spin_pol: args[nam] = { 'x': d.energy, 'y': smoother(d.d_up[0], nsmooth), 'c': color[orb], 'ls': l, 'label': formula + ' ' + el + suf2 + ' ' + orb } args[nam_down] = { 'x': d.energy, 'y': -smoother(d.d_down[0], nsmooth), 'c': color[orb], 'ls': l, 'label': None } color[orb] = 'm' else: args[nam] = { 'x': d.energy, 'y': smoother(d.d[0], nsmooth), 'c': color[orb], 'ls': l, 'label': formula + ' ' + el + suf2 + ' ' + orb } elif orb == 't2g': if split_type == 'octa': orb_name = orb elif split_type == 'tetra': orb_name = 't2' args[nam] = { 'x': d.energy, 'y': smoother(d.t2g_up[0], nsmooth), 'c': color[orb], 'ls': l, 'label': formula + ' ' + el + suf2 + ' ' + orb_name } if spin_pol: args[nam_down] = { 'x': d.energy, 'y': -smoother(d.t2g_down[0], nsmooth), 'c': color[orb], 'ls': l, 'label': None } elif orb == 'eg': if split_type == 'octa': orb_name = orb elif split_type == 'tetra': orb_name = 'e' args[nam] = { 'x': d.energy, 'y': smoother(d.eg_up[0], nsmooth), 'c': color[orb], 'ls': l, 'label': formula + ' ' + el + suf2 + ' ' + orb_name } if spin_pol: args[nam_down] = { 'x': d.energy, 'y': -smoother(d.eg_down[0], nsmooth), 'c': color[orb], 'ls': l, 'label': None } elif orb == 'p_all': if plot_spin_pol: args[nam] = { 'x': d.energy, 'y': smoother(d.p_all_up, nsmooth), 'c': color[orb], 'ls': l, 'label': formula + ' ' + el + suf2 + ' ' + orb } args[nam_down] = { 'x': d.energy, 'y': -smoother(d.p_all_down, nsmooth), 'c': color[orb], 'ls': l, 'label': None } # color[orb] = 'm' else: args[nam] = { 'x': d.energy, 'y': smoother(d.p_all, nsmooth), 'c': color[orb], 'ls': l, 'label': formula + ' ' + el + suf2 + ' ' + orb } elif orb == 'd_all': if plot_spin_pol: args[nam] = { 'x': d.energy, 'y': smoother(d.d_all_up, nsmooth), 'c': color[orb], 'ls': l, 'label': formula + ' ' + el + suf2 + ' ' + orb } args[nam_down] = { 'x': d.energy, 'y': -smoother(d.d_all_down, nsmooth), 'c': color[orb], 'ls': l, 'label': None } # color[orb] = 'm' else: args[nam] = { 'x': d.energy, 'y': smoother(d.d_all, nsmooth), 'c': color[orb], 'ls': l, 'label': formula + ' ' + el + suf2 + ' ' + orb } else: # args[nam] = (d.energy, smoother(d.site_dos(iat, i_orb[orb]), nsmooth), color[orb]+l) args[nam] = { 'x': d.energy, 'y': smoother(d.site_dos(iat, i_orb[orb]), nsmooth), 'c': color[orb], 'ls': l, 'label': formula + ' ' + el + suf2 + ' ' + orb } if spin_pol: args[nam_down] = { 'x': d.energy, 'y': -smoother(d.site_dos(iat, i_orb_down[orb]), nsmooth), 'c': color[orb], 'ls': l, 'label': None } # args[nam_down] = (d.energy, -smoother(d.site_dos(iat, i_orb_down[orb]), nsmooth), color[orb]+l) """Additional dos analysis; to be refined""" gc = None if show_gravity: if show_gravity[0] == 1: d = d1 elif show_gravity[0] == 2: d = d2 if show_gravity[2]: erange = show_gravity[2] else: erange = (-100, 0) mod = show_gravity[1] if mod == 'p6': gc = det_gravity2(d.energy, d.p6, erange) # gc = det_gravity2(d.energy, d.d[0], erange) # printlog('Gravity center for cl1 for d for {:} is {:5.2f}'.format(erange, gc), imp = 'Y') elif show_gravity[1] == 'p': gc = det_gravity2(d.energy, d.p[0], erange) # for first atom for cl2 elif show_gravity[1] == 'p_all': gc = det_gravity2(d.energy, d.p_all, erange) # for first atom for cl2 elif mod == 'd': gc = det_gravity2(d.energy, d.d[0], erange) # for first atom for cl2 printlog( 'Gravity center for cl1 for {:} for {:} is {:5.2f}'.format( mod, erange, gc), imp='Y') plot_param['ver_lines'] = [{'x': gc, 'c': 'k', 'ls': '--'}] """Plot everything""" image_name = os.path.join( path, '_'.join(names) + '.' + ''.join(orbitals) + '.' + el + str(iat + 1)) if 'xlabel' not in plot_param: plot_param['xlabel'] = "Energy (eV)" if 'ylabel' not in plot_param: plot_param['ylabel'] = ylabel fit_and_plot( show=show, image_name=image_name, hor=True, # title = cl1.name.split('.')[0]+'; V='+str(round(cl1.vol) )+' $\AA^3$; Impurity: '+el, **plot_param, **args) # printlog("Writing file", image_name, imp = 'Y') 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, 'filename': image_name, 'gc': gc}
def calc_redox(cl1, cl2, energy_ref=None, value=0, temp=None, silent=0, mode=None, scale=1): """ 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 temp(float) - potential at temperature, self.F is expected from phonopy calculations mode (str) - special electrostatic_only - use Ewald summation to obtain electrostatic energy ewald_vasp scale - experimental return dic {'redox_pot', 'vol_red', ...} """ if cl1 is None or cl2 is None: printlog('Warning! cl1 or cl2 is none; return') return if not hasattr(cl1.end, 'znucl') or not hasattr(cl2.end, 'znucl'): printlog('Warning! cl1 or cl2 is bad') return energy_ref_dict = {3: -1.9, 11: -1.31, 19: -1.02, 37: -0.93} z_alk_ions = [3, 11, 19, 37] #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] # print(n1,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) # print(mul) if abs( mul ) > 0: #only change of concentration of one ion type is allowed; the first found is used printlog('Change of concentration detected for ', element_name_inv(z)) 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 mode == 'electrostatic_only': # st1 = cl1.end.copy() # st2 = cl2.end.copy() st1 = cl1.end st2 = cl2.end # st1 = set_oxidation_states(st1) # st2 = set_oxidation_states(st2) # st1 = st1.remove_atoms(['Ti']) st1.charges = cl1.charges st2.charges = cl2.charges # sys.exit() stpm1 = st1.convert2pymatgen(chg_type='ox') stpm2 = st2.convert2pymatgen(chg_type='ox') ew1 = EwaldSummation(stpm1) ew2 = EwaldSummation(stpm2) e1 = ew1.total_energy e2 = ew2.total_energy # print(ew1.get_site_energy(0), ew1.get_site_energy(4), ew2.get_site_energy(9) ) elif mode == 'ewald_vasp': e1 = cl1.energy.ewald e2 = cl2.energy.ewald else: e1 = cl1.e0 e2 = cl2.e0 print(e1, e2) if temp != None: #temperature corrections e1 += cl1.F(temp) e2 += cl2.F(temp) # print(cl1.F(temp), cl2.F(temp)) # print(e1, cl1.energy_sigma0) # print(e2, cl2.energy_sigma0) if abs(mul) > 0: redox = -((e1 / n1 - e2 / n2) / mul - energy_ref) / scale else: redox = 0 # print(n1, n2) 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 = ( "{:45} | {:30} | {:10.2f} V | {:10.1f} % | {:6.2f}| {:6.2f}| {:6.0f}| {:6.0f} | {:3.0f}" .format(cl1.name, cl2.name, redox, vol_red, cl1.energy_sigma0, cl2.energy_sigma0, cl1.maxforce, cl2.maxforce, value)) if not silent: 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 = {'redox_pot': redox, 'vol_red': vol_red} return results_dic
def read_xyz(st, filename, rprimd=None): """ Read xyz file into st rprimd (list of lists) - if None or [None, ] then Tv are read; if Tv does not exist then create automatically """ with open(filename, 'r') as f: nlines = int(f.readline()) st.name = f.readline().strip() # try: if 'SG' in st.name: printlog( 'Error! Space group record detected in xyz, please finish code', imp='Y') # st.name.split('SG') elements = [] st.xcart = [] st.rprimd = [] for i in range(nlines): xc = f.readline().split() if len(xc) == 0: printlog('Warning! xyz file is broken, not enough lines') break if 'Tv' in xc[0]: st.rprimd.append(np.asarray(xc[1:], dtype=float)) else: elements.append(xc[0]) st.xcart.append(np.asarray(xc[1:], dtype=float)) st.natom = len(st.xcart) st.znucl = [element_name_inv(el) for el in unique_elements(elements)] elements_z = [element_name_inv(el) for el in elements] st.typat = [] for z in elements_z: st.typat.append(st.znucl.index(z) + 1) st.ntypat = len(st.znucl) # print(st.rprimd) if rprimd == None or None in rprimd or 0 in rprimd or len(rprimd) != 3: printlog('None detected in *rprimd*, I use vectors from xyz file') if len(st.rprimd) != 3: printlog('Only these primitive vectors were found in xyz :\n', np.round(st.rprimd, 3), '\nI take rest from *rprimd*', imp='y') if rprimd: for r in rprimd: if is_list_like(r): st.rprimd.append(r) else: printlog('Error! Please provide vector in *rprimd*') else: printlog('I use vectors from *rprimd*') st.rprimd = rprimd if len(st.rprimd) != 3: printlog('Error! Check *rprimd* or Tv in xyz') if st.get_volume() < 0: printlog( 'Warning! rprimd gives negative volume, I exchange vectors 2 and 3', imp='y') t = st.rprimd[1] st.rprimd[1] = st.rprimd[2] st.rprimd[2] = t if st.get_volume() < 0: printlog( 'Error! still negative volume, check your primitive vectors', imp='y') st.tmap = [1, 3] else: st.tmap = [1, 2] printlog('Final rprimd = \n', np.round(st.rprimd, 3), imp='y') st.nznucl = st.get_nznucl() st.recip = st.get_recip() st.update_xred() st.reorder_for_vasp(inplace=True) # print(st.perm) return st
def read_poscar(st, filename, new=True): # from classes import Structure #read poscar selective_dynamics = None elements_list = [] # st = Structure() if new: st.name = os.path.basename(filename).replace('POSCAR', '').replace( 'CONTCAR', '') try: if '.' in st.name[-1]: st.name = st.name[0:-1] except: pass with open(filename, 'r') as f: name = f.readline().strip() if new: st.des = name # print self.name, "self.name" # st.name = self.name # print(f.readline()) mul = float(f.readline().split('!')[0]) # print 'mul', mul st.rprimd = [] for i in 0, 1, 2: vec = f.readline().split() st.rprimd.append( np.asarray([ float(vec[0]) * mul, float(vec[1]) * mul, float(vec[2]) * mul ])) st.nznucl = [] ilist = f.readline().split() #nznucl of elements? try: int(ilist[0]) vasp5 = False except: vasp5 = True if vasp5: printlog('Vasp5 detected') for el in ilist: elements_list.append(el) printlog('elements_list:', elements_list) ilist = f.readline().split() else: printlog('Vasp4 detected') for z in ilist: st.nznucl.append(int(z)) temp_line = f.readline() if temp_line[0] in ['s', 'S']: printlog('selective dynamics detected') selective_dynamics = True temp_line = f.readline() type_of_coordinates = temp_line st.xred = [] coordinates = [] select = [] if len(elements_list) > 0: read_elements = 0 else: read_elements = 1 for nz in st.nznucl: for i in range(nz): vec = f.readline().split() coordinates.append( np.asarray([float(vec[0]), float(vec[1]), float(vec[2])])) if read_elements and len( vec) == 4: # elements may be added by pymatgen # printlog("Probably elements names are added at the end of coordinates, trying to read them") if vec[3] not in elements_list: elements_list.append(vec[3]) if selective_dynamics: # convert 'T'/'F' to True/False flagset = [True, True, True] for fi, flag in enumerate(vec[3:6]): if flag == 'F': flagset[fi] = False # print(flagset) select.append(flagset) st.select = select if "Car" in type_of_coordinates or 'car' in type_of_coordinates: st.xcart = coordinates st.update_xred() elif "dir" in type_of_coordinates or 'Dir' in type_of_coordinates: st.xred = coordinates st.update_xcart() elif 'None' in type_of_coordinates: pass else: printlog( "Error! The type of coordinates should be 'car' or 'dir' ") raise NameError if 'Species order:' in name: printlog('I detect that input file was generated by cif2cell\n') name = name.split(':')[-1] if not elements_list: elements_list = name.split('!')[0].strip().split() printlog('I take elements from the first line, The line is ' + str(name.split('!')) + ' you could use ! to add comment after name+\n') # print(elements_list) if 'i2a' in elements_list[0]: printlog('i2a list detected') el = elements_list[0].split('[')[-1].replace(']', '') elements_list = el.split(',') else: printlog( "Elements names have been taken from the end of coordinates, pymatgen file?\n" ) st.znucl = [] for elname in elements_list: st.znucl.append(element_name_inv(elname)) # printlog('znucl is ') st.natom = len(st.xred) st.ntypat = len(st.znucl) st.typat = [] for i, nz in enumerate(st.nznucl): for j in range(nz): st.typat.append(i + 1) #Determine reciprocal vectors st.recip = st.get_recip() # if hasattr(self.init, 'vel'): # print "I write to POSCAR velocity as well" # f.write("Cartesian\n") # for v in self.init.vel: # f.write( '%.12f %.12f %.12f\n'%(v[0]*to_ang, v[1]*to_ang, v[2]*to_ang) ) printlog('The following Z were read = ' + str(st.znucl) + '\n') printlog('VASP POSCAR format', filename, " was read\n") return st
def pairs(in_calc, xcart_pores, central_atoms, prec=2, max_dist=20, max_dist_from_gb=4, pairtyp='gvol'): """ Searhing for pairs and make list of distances and numbers of atoms prec - precision, allows to control which distances can be related to the same configurations max_dist - maximum distance between atoms in pair max_dist_from_gb - pairtyp - 'gvol' assumes that central_atoms are in the grain volume, 'gb' assumes that central_atoms are in the grain boundary region """ st = in_calc.init st_replic = replic(st, (2, 2, 2)) st_replic = replic(st_replic, (2, 2, 2), -1) #replic in negative direction also r1x = in_calc.rprimd[0][0] r3z = in_calc.rprimd[2][2] print("Half length of r1x is", r1x / 2) if segtyp in ['segreg', 'coseg', 'grainvol']: gbpos2 = in_calc.gbpos gbpos1 = gbpos2 - r1x / 2. print("\n\nPositions of boundaries gb1 and gb2", gbpos1, gbpos2) print("Maximum possible distance between boundary and impurity", r1x / 4) else: gbpos2 = 0 gbpos1 = 0 dlist = [] d1list = [] d2list = [] dgb2list = [] n_neighbours = 8 # number of atoms to calculate sums sumrulist = [] #list of sums (sumr1 or sumr2) of unique pores unique_pores = [] #the same list but also with coordinates of pores sumrlist = [] #list of sumr1+sumr2 k = 1 d2diff = 0 d1diff = 0 #z1 = 6 #charge of added impurity #z2 = 8 diffprec = 0.02 # print xcart_pores for i, x1 in enumerate(xcart_pores): if i not in central_atoms: continue #iz = z1 for j, x2 in enumerate(xcart_pores): if all(x1 == x2): continue d = abs(x2[0] - in_calc.gbpos) if pairtyp == 'gb' and d > max_dist_from_gb: continue #second atom is too far from grain boundary d1, d2 = image_distance( x1, x2, st.rprimd, 2) # the minimum distance and the next minimum dist if d1 > max_dist: continue if (d1, d2) != image_distance(x1, x2, st.rprimd, 3): raise RuntimeError #test, searching in father images #d1 = round(d1,prec) #d2 = round(d2,prec) dgb1 = round(x2[0] - gbpos1, prec) dgb2 = round(gbpos2 - x2[0], prec) sumr1 = local_surrounding( x1, st_replic, n_neighbours) # sum of distances to surrounding atoms sumr2 = local_surrounding(x2, st_replic, n_neighbours) sumr = sumr2 + sumr1 if sumr1 not in sumrulist: sumrulist.append(sumr1) unique_pores.append((sumr1, x1)) #determine unique pores if sumr2 not in sumrulist: sumrulist.append(sumr2) unique_pores.append((sumr2, x2)) #determine unique pores #if d1 in d1list: continue if sumr in sumrlist: # new condition based on sumr ind = sumrlist.index(sumr) i_min, smaller = min_diff(d1, d1list, diffprec) if smaller: continue # if 0:#d1list: # i_min, smaller = min_diff(d1, d1list, diffprec)# d1 has the smallest difference with di # #print "exist" # d2diff = abs(d2list[i_min]-d2) # #print abs(d2list[i_min]-d2) # #print central_atoms # if smaller and abs(d2list[i_min]-d2) < diffprec*2 : continue #and abs(dgb2list[i_min]-dgb2) < diffprec # i_min, smaller = min_diff(d2, d2list, diffprec)# d1 has the smallest difference with di # d1diff = abs(d1list[i_min]-d1) # if smaller and abs(d1list[i_min]-d1) < diffprec*2 : continue #print "skiped" #di, smaller = min_diff(d2, d2list, diffprec) #if di != None and smaller: continue #if min_diff(d2, d2list, diffprec): continue # be carefull here. this condition can pass some unique configrations; should make additional check like below #if d2 in d2list and dgb2list[d2list.index(d2)] == dgb2: continue #jz = z2 sumrlist.append(sumr) d1list.append(d1) # d2list.append(d2) # dgb2list.append(dgb2) sym = '' if 0: #mannualy switched off if abs(x1[1] - x2[1]) < diffprec: #Find symmetry if abs(x1[2] - x2[2]) < diffprec: sym = 'ms' # if y and z are the same, than mirror symmetry elif abs(x1[2] - x2[2]) - r3z < diffprec: sym = 'is' # inverse symmtry elif abs( x1[2] + x2[2] ) - 0.5 * r3z < diffprec: # only for t111g; should be extended for general case of existing periods along y or z sym = 'is' dlist.append([ round(d1, prec), round(d2, prec), sym, sumr1, sumr2, dgb1, dgb2, x1, x2, sumr1, sumr2 ]) #the first sumr1, sumr2 below replaced by their types k += 1 dlist.sort(key=itemgetter(0)) unique_pores.sort(key=itemgetter(0)) sumrulist.sort() print('Number of unique pores is', len(unique_pores)) print('Pores have the following sums: ', unique_pores) print("Searching for similar pairs but with different distances ...") print( "number, d1, d2, name, sumr1, sumr2, dgb1, dgb2; parallel pair with larger distances" ) bname = element_name_inv(target_znucl[1]) + element_name_inv( target_znucl[2]) for i, el1 in enumerate(dlist): typ1 = sumrulist.index(el1[3]) + 1 #typ of pore of the first atom typ2 = sumrulist.index(el1[4]) + 1 el1[3] = typ1 el1[4] = typ2 if pairtyp == 'gb': dlist[i][2] = bname + 'i' + str(i + 1) + '.' + str( el1[3]) + '-' + str(el1[4]) + dlist[i][2] elif pairtyp == 'gvol': dlist[i][2] = bname + '.v' + str(i + 1) + dlist[i][2] print(i + 1, el1[:3], el1[-2:], el1[-6], el1[-5], end=' ') #number, d1, d2, name, sumr1, sumr2, dgb1, dgb2 for el2 in dlist: #this loop looks for pairs which are parallel to the same direction as el1 but have larger interdistances if el1 == el2: continue mod = el2[0] / el1[0] % 1 if (mod < 0.005 or mod > 0.995 ) and abs(el1[0] - el2[0]) > dlist[0][ 0]: #only multiple distances and if difference is larger than smallest distance #if round(el1[2],prec-1) != round(el2[2],prec-1): continue #In either case the sum the distances should be the same for the same direction if el1[0] == el2[1]: continue print( el2[0] / el1[0], end=' ' ) # el2, this pair of atoms is analogus to el1 but have larger interdistance print() print('Total number of structures is', len(dlist)) if 0: print( "\n\nSearching for pairs with equal distances by periodic boundary conditions:" ) for el1 in dlist: if el1[0] == el1[1]: print(el1) print( "\nSearching for pairs with not equal distances by periodic boundary conditions:" ) for el1 in dlist: if el1[0] != el1[1]: print(el1) print("\nSearching for pairs with d2/d1>2:") for el1 in dlist: if el1[1] / el1[0] > 2: print(el1) dlist[0].append( unique_pores ) # last element of dlist[0] is sum and coordinates of unique pores return dlist
def calc_redox(cl1, cl2, energy_ref=None, value=0, temp=None, silent=0): """ 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 temp(float) - potential at temperature, self.F is expected from phonopy calculations """ if cl1 is None or cl2 is None: printlog('Warning! cl1 or cl2 is none; return') return if not hasattr(cl1.end, 'znucl') or not hasattr(cl2.end, 'znucl'): printlog('Warning! cl1 or cl2 is bad') return energy_ref_dict = {3: -1.9, 11: -1.31, 19: -1.02, 37: -0.93} z_alk_ions = [3, 11, 19, 37] #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] # print(n1,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) # print(mul) if abs( mul ) > 0: #only change of concentration of one ion type is allowed; the first found is used printlog('Change of concentration detected for ', element_name_inv(z)) 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) e1 = cl1.energy_sigma0 e2 = cl2.energy_sigma0 if temp != None: #temperature corrections e1 += cl1.F(temp) e2 += cl2.F(temp) # print(cl1.F(temp), cl2.F(temp)) # print(e1, cl1.energy_sigma0) # print(e2, cl2.energy_sigma0) if abs(mul) > 0: redox = -((e1 / n1 - e2 / n2) / mul - energy_ref) else: redox = 0 # print(n1, n2) 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 = ( "{:45} | {:30} | {:10.2f} V | {:10.1f} % | {:6.2f}| {:6.2f}| {:6.0f}| {:6.0f} | {:3.0f}" .format(cl1.name, cl2.name, redox, vol_red, cl1.energy_sigma0, cl2.energy_sigma0, cl1.maxforce, cl2.maxforce, value)) if not silent: 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 = {'redox_pot': redox, 'vol_red': vol_red} return results_dic