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 = replic( added.init, (1,2,1) ) rep = copy.deepcopy(init) rep.init = replic( rep.init, (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 "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 "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 seg_energy_vs_voronoi(calc, conv, varset, plot = 0): """ Was used to calculate all segregation energies vs voronoi volume to find some dependence plot - if 1: than plot dependence """ aggregate_list = [] if 0: """1. Start processing of calculation specific information""" #base = 't111gCOv2' base = 't111gCvOvms' coseg_list = ['t111gCOi1.4-3', 't111gOCi1.4-3', 't111gCOi2.2-1', 't111gOCi2.2-1', 't111gCOi3.4-1', 't111gOCi3.4-1', \ 't111gCOi4.4-4is','t111gCOi5.2-2is', 't111gCOi6.1-1is', 't111gCOi7.3-3is','t111gCOi8.2-3','t111gOCi8.2-3', \ 't111gCOi9.4-4ms','t111gCOi10.2-2ms','t111gCOi11.4-3', 't111gOCi11.4-3', \ 't111gCOi12.1-3', 't111gOCi12.1-3', 't111gCOi13.4-2', 't111gOCi13.4-2', 't111gCOi14.2-1', 't111gOCi14.2-1', 't111gCOi15.4-4is','t111gCOi16.2-2is'] seg_list = ['t111gCi1Ov', 't111gCi2Ov','t111gCi3Ov','t111gCi4Ov','t111gOi1Cv','t111gOi2Cv','t111gOi3Cv','t111gOi4Cv',] bulk_list = ['t111gCOv2', 't111gCOv5' ] list = res_loop(base,'93kp9',range(2,3),calc,conv,varset, 'coseg', (base,) , voronoi = True ) aggregate_list.append(list) # os._exit(0) for key in seg_list: # print key # if 'Oi' in key: continue list = res_loop(key,'93kp9',range(2,3),calc,conv,varset, 'coseg', (base,) , voronoi = True ) aggregate_list.append(list) pass # res_loop('t112gCOi6.1-1is','93kp9',range(1,5),calc,conv,varset, 'coseg', ('t112gCvOvms',) ) base = 'c1gCvOvms' coseg_list = [ 'c1gCOi1.2-1', 'c1gCOi2.2-1', 'c1gCOi3.1-2', 'c1gCOi4.2-1', 'c1gCOi5.2-1', 'c1gCOi6.1-2', 'c1gCOi7.1-1', 'c1gCOi8.2-2', 'c1gOCi1.2-1', 'c1gOCi2.2-1', 'c1gOCi3.1-2', 'c1gOCi4.2-1', 'c1gOCi5.2-1', 'c1gOCi6.1-2', 'c1gOCi7.1-1', 'c1gOCi8.2-2', 'c1gCOi10.1' ] bulk_list = ['c1gCOv2', 'c1gCOv4', 'c1gCOv7',] seg_list = ['c1gCi1Ov', 'c1gCi2Ov', 'c1gOi1Cv', 'c1gOi2Cv', ] list = res_loop(base,'93kp7',range(2,3),calc,conv,varset, 'coseg', (base,), voronoi = True ) aggregate_list.append(list) for key in seg_list: # print key # if 'Oi' in key: continue list = res_loop(key,'93kp7',range(2,3),calc,conv,varset, 'coseg', (base,) , voronoi = True ) aggregate_list.append(list) pass base = 't111sgCvOvms' seg_list = ['t111sgCi1Ov', 't111sgCi2Ov', 't111sgCi3Ov', 't111sgCi4Ov', 't111sgCi5Ov', 't111sgCi6Ov', 't111sgCi7Ov', 't111sgOi1Cv', 't111sgOi2Cv', 't111sgOi3Cv', 't111sgOi4Cv', 't111sgOi5Cv', 't111sgOi6Cv', 't111sgOi7Cv', ] list = res_loop(base,'93kp9',range(2,3),calc,conv,varset, 'coseg', (base,) , voronoi = True ) aggregate_list.append(list) for key in seg_list: # print key # if 'Oi' in key: continue list = res_loop(key,'93kp9',range(2,3),calc,conv,varset, 'coseg', (base,) , voronoi = True ) aggregate_list.append(list) pass base = 't21gCvOvms' seg_list = ['t21gCi1Ov', 't21gCi2Ov', 't21gCi3Ov', 't21gCi4Ov', 't21gOi1Cv', 't21gOi2Cv', 't21gOi3Cv', 't21gOi4Cv', ] list = res_loop(base,'93',range(2,3),calc,conv,varset, 'coseg', (base,), voronoi = True ) aggregate_list.append(list) for key in seg_list: # print key # if 'Oi' in key: continue list = res_loop(key,'93',range(2,3),calc,conv,varset, 'coseg', (base,) , voronoi = True ) aggregate_list.append(list) write_xyz( replic(calc[(key, '93', 1)].end, (1,2,2)), ) pass base = 'csl71sgCvOvms' seg_list = ['csl71sgCi1Ov', 'csl71sgCi2Ov', 'csl71sgCi3Ov', 'csl71sgCi4Ov', 'csl71sgCi5Ov', 'csl71sgCi6Ov', 'csl71sgOi1Cv', 'csl71sgOi2Cv', 'csl71sgOi3Cv', 'csl71sgOi4Cv', 'csl71sgOi5Cv', 'csl71sgOi6Cv', ] list = res_loop(base,'93',range(2,3),calc,conv,varset, 'coseg', (base,) , voronoi = True ) aggregate_list.append(list) for key in seg_list: # print key # if 'Oi' in key: continue list = res_loop(key,'93',range(2,3),calc,conv,varset, 'coseg', (base,) , voronoi = True ) aggregate_list.append(list) pass calc['voronoi'] = aggregate_list else: aggregate_list = calc['voronoi'] pass if 1: # print res_loop('hs221C','83',101,calc,conv,varset, voronoi = True ) # # print res_loop('hs221.f','83',1,calc,conv,varset, voronoi = True ) # # print res_loop('csl71b_r','83kp8',1,calc,conv,varset, voronoi = True ) # print res_loop('hs221C.f','93',1,calc,conv,varset, voronoi = True ) #9.25 But the sum of Voronoi volume for hexagonal cell is wrong!!! # print res_loop('hs332C.f','93',1,calc,conv,varset, voronoi = True ) #9.18 But volume for internal atoms seems to be OK, # print res_loop('hs443C.f','93',1,calc,conv,varset, voronoi = True ) #9.13 But for edge atoms it is even zero. # print res_loop('hs554C.f','93',1,calc,conv,varset, voronoi = True ) #9.14 It seems that Voronoi module does not recognize oblique cell geometry. """2. Analysis""" esegC = [float(x[1]) for x in aggregate_list if 'Oi' not in x[0]] # C segregation including CvOvms vorovolC = [float(x[2]) for x in aggregate_list if 'Oi' not in x[0]] # print esegC, esegO = [float(x[1]) for x in aggregate_list if 'Ci' not in x[0]] # O segregation including CvOvms vorovolO = [float(x[4]) for x in aggregate_list if 'Ci' not in x[0]] """Plot dependence""" name = 'Voronoi volume - segregation energy' set = 'Eng' fig, (ax1, ax2) = plt.subplots(nrows=2, ncols=1) if set == 'Rus': matplotlib.rcParams.update({'font.size': 16}) xlabel = u'Энергия сегрегации (мэВ)' # print xlabel ylabel = u'Объем Вороного ($\AA^3$)' label1 = u'Рассчет' label2 = u'Аппроксимация' title1 = u'Углерод' title2 = u'Кислород' else: xlabel = 'Segregation energy (meV)' ylabel = 'Voronoi volume ($\AA^3$)' label1 = 'Calculated' label2 = 'Fitted' title1 = 'Carbon' title2 = 'Oxygen' # plt.figure() #plt.title(name) ax1.plot(esegC, vorovolC, 'o',label = label1) k, b = np.polyfit(esegC, vorovolC, 1) ax1.plot(esegC, np.asarray(esegC) * k + b, '-r',label = label2) ax1.set_title(title1) # ax1.legend(loc =4) # image_name = 'eseg_vorovol_C' # plt.savefig('images/'+str(image_name)+'.png',format='png', dpi = 300) # plt.cla() #plt.title(name) # plt.ylabel(ylabel) # plt.xlabel(xlabel) ax2.plot(esegO, vorovolO, 'o',label = label1) k, b = np.polyfit(esegO, vorovolO, 1) ax2.plot(esegO, np.asarray(esegO) * k + b, '-r',label = label2) ax2.set_title(title2) ax2.set_xlabel(xlabel) # ax2.legend(loc =4) # image_name = 'eseg_vorovol_O' plt.figtext(0.03, 0.5, ylabel, ha='center', va='center', rotation='vertical') # fig.set_ylabel(ylabel, va ='center') # plt.yaxis.set_label_coords(0, 0.5) # plt.xlabel(xlabel) plt.tight_layout() plt.subplots_adjust(left=0.15, bottom = 0.15) image_name = 'eseg_vorovol_CandO' plt.savefig('images/'+str(image_name)+'.png',format='png', dpi = 300) return
def find_pairs( base_name, segtyp, in_calc, central_atoms=[], xcart1imp=None, input_dlist_coseg=None, prec=2, gvolume_config_num=None, gbpos=None, take_final_rprimd_from=None, main_path=None, based_on=None, target_znucl=[22, 6, 8], max_dist_between_atoms=4.8, add_typat=[2, 3], ): """ Find uniq pairs of atoms and analyse them Input: segtyp - three regimes for cells with grain boundaries: 'segreg' assumes that in_calc contains carbon atom in grain volume, and creates all cases; 'coseg' assumes pure cell and creates only coseg cases. cosegregation cases of course should be the same for two regimes, however co-segregation configuations after 'coseg' is more easy to relax. 'grainvol' - searching for pairs in grain volume two regimes for bulk cells: 'bulk_triple' - used for bulk cells without grain boundaries; first step is searching for pairs, second step for triples. 'bulk_pairs' - used for bulk cells without grain boundaries; searching for pairs. new_name - name of created structures; at first should be added to struct_des[] in_calc - Calculation() type or path to geo file region - list of numbers which determine region central_atoms - list of atoms for which pairs are constructed (Warinig! numbers in new array xcart_pores!); - parameter to change mode; xcart1imp - coordinates of first interstitial in the grain interior input_dlist_coseg - list of configurations with cosegregation cases. Needed to construct corresponding segregation cases. the format is quiet tricky prec - precision of lengths used to determine unique positions. gvolume_config_num - number of configuration with two atoms in grain volume choosen by user (usually should be the most favourable) gbpos - position of grain boundary take_final_rprimd_from - path to geo file from which rprimd will be used target_znucl - numbers of target atoms max_dist_between_atoms - now at least used for 'bulk_pairs' and 'bulk_triple'; maximum length of found pairs. add_typat - mannualy set please update """ def write_geometry_files( dlist, in_calc, xcart_pores, segtyp, take_final_rprimd_from=None, add_name_before="", tlist=[], configver=False, add_typat=None, ): """Creating files dlist - list of pairs with distances and numbers in_calc - base calculation without pores tlist - list of additional atoms in the case of triples; list of structures configver - if True each configuration saved as a new version add_typat - manually determined; please automatize! """ print "Warning! add_typat", add_typat if tlist == []: # convert dlist to tlist - to do earlier for el in dlist: config = Structure() config.name = el[2] config.length = el[0] config.typat = add_typat config.xcart = [el[7], el[8]] tlist.append(config) for i, el in enumerate(tlist): # by all found structures print "el name is ", el.name stn = copy.deepcopy(in_calc.init) calc = copy.deepcopy(in_calc) stn.typat.extend(el.typat) stn.xcart.extend(el.xcart) stn.xred = xcart2xred(stn.xcart, stn.rprimd) xcart_check = xred2xcart(stn.xred, stn.rprimd) assert len(xcart_check) == len(stn.xcart) # test assert all( [all(np.around(v1, 8) == np.around(v2, 8)) for (v1, v2) in zip(stn.xcart, xcart_check)] ) # check if xcart2xred(stn.xcart,r) and xred2xcart(stn.xred,r) are working correctly up to the eight digits after stn.natom = len(stn.xcart) """Adapt new rprimd""" print "take final rprimd is ", take_final_rprimd_from if take_final_rprimd_from: # read final rprimd and version print "Start to read rprimd and version from " + take_final_rprimd_from in_calc_rprimd = CalculationVasp() in_calc_rprimd.name = "temp" in_calc_rprimd.read_geometry(take_final_rprimd_from) stn.rprimd = in_calc_rprimd.init.rprimd stn.xcart = xred2xcart(stn.xred, stn.rprimd) calc.version = in_calc_rprimd.version elif configver: calc.version = i + 1 calc.init = stn des = ( " was obtained by the insertion of C-O pair into " + in_calc_name + "; final vectors taken from corresponding ver" ) calc.build.ipairlen = el.length # Initial length of pair if not hasattr(calc.build, "nadded") or calc.build.nadded == None: calc.build.nadded = 2 else: calc.build.nadded += 2 if not hasattr(calc.build, "listadded") or calc.build.listadded == [None]: calc.build.listadded = range(stn.natom - 2, stn.natom) # list of atoms which were added else: calc.build.listadded.extend(range(stn.natom - 2, stn.natom)) structure_name = calc.name + el.name.split(".")[0] # calc.name = add_name_before+calc.name+ '.' +el[2]+'.'+str(calc.version) print "Structure_name", structure_name if structure_name in struct_des: if configver: fname = structure_name # calc.name+'C2O2' calc.path["input_geo"] = ( geo_folder + struct_des[fname].sfolder + "/" + fname + "/" + structure_name + "." + segtyp + "." + str(calc.version) + ".geo" ) else: calc.path["input_geo"] = ( geo_folder + struct_des[structure_name].sfolder + "/" + structure_name + "/" + structure_name + "." + segtyp + "." + str(calc.version) + ".geo" ) print "write geo to ", calc.path["input_geo"] calc.write_geometry("init", des) print "write_geometry_files(): name ", el.name stn.name = add_name_before + calc.name + "" + str(el.name) + "." + str(calc.version) # stn = replic(stn, (1,2,2)) write_xyz(stn) print "__________________________\n\n\n" return def min_diff(f, list, diffprec): """ calculates difference between one number and list of other numbers. return the index of number with smallest difference. if difference is smaller than diffprec returns true as the second argument. """ # print list if list == []: return 0, False mind = min([abs(f - l) for l in list]) with_i = np.asarray([abs(f - l) for l in list]).argmin() return with_i, (mind < diffprec) 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.0 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], # 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], # 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 """0. BEGIN-------------------------------------------------------------------------------""" hstring = "%s #on %s" % (traceback.extract_stack(None, 2)[0][3], datetime.date.today()) if hstring != header.history[-1]: header.history.append(hstring) print_and_log("\n\n------Starting find_pairs()-----------...\n") if type(central_atoms) == int: # not in [tuple, list]: central_atoms = [central_atoms] # transform to list if type(in_calc) == str: in_calc_name = in_calc in_calc = CalculationVasp() # in_calc.name = str(in_calc_name) in_calc.name = base_name print "in_calc name is ", in_calc.name in_calc.read_geometry(in_calc_name) if gbpos: in_calc.gbpos = gbpos # rewrite gbpos st = in_calc.init else: """End relaxed structure is used!!!""" st = copy.deepcopy(in_calc.end) in_calc_name = str(in_calc.id) """1. Create separate list of pores and remove them from xcart--------------------------------------------------------""" if "hcp_octa_xred": in_calc.init.name = segtyp + "_all_pores" rep = replic(in_calc.init, (2, 2, 2), -1) write_xyz(rep) # just to check """Coordinates of octapores provided in xcart; znucl = 200;""" xcart = st.xcart typat = st.typat st.typat = [] st.xcart = [] xcart_pores = [] # clean structure from pores with z == 200 and construct xcart_pores for i, x in enumerate(xcart): z = st.znucl[typat[i] - 1] if z == 200: xcart_pores.append(x) # print "Found pore" else: st.xcart.append(x) st.typat.append(typat[i]) st.natom = len(st.xcart) print "Number of found pores with znucl = 200 is ", len(xcart_pores) for n in central_atoms: if n >= len(xcart_pores): raise RuntimeError """2. Preprocess segreg and grainvol cases--------------------------------------------------------""" # in_calc can be of two types: pure and with C in grain volume; using pure we construct co-segregation cases; using carbon in volume we can construct segregation cases if segtyp in ("segreg", "grainvol"): if 2 in st.typat: # impurity in grain volume; (now assume that Carbon) iimp = st.typat.index(2) xcart1imp = st.xcart[iimp] # save coordinates of carbon atom del st.xcart[iimp] del st.typat[iimp] st.natom -= 1 # and remove it # del st.xred[iimp] st.ntypat -= 1 del st.znucl[1] print "Impurity atom was removed from cell" if xcart1imp: # for compatibility with previous cases; better not to use imp1 = len(xcart_pores) xcart_pores.append(xcart1imp) xcart2imp = ( xcart1imp - 0.5 * st.rprimd[0] ) # determine coordinates of second impurity assuming that we have mirror symmetry if xcart2imp[0] < 0: xcart2imp = xcart1imp + 0.5 * st.rprimd[0] imp2 = imp1 + 1 xcart_pores.append(xcart2imp) else: # new version; both central pores are found in the pure cell!!! # We have pure cell here; Find central pore in 1st grain and 2nd grain: xcen1 = in_calc.gbpos - 0.25 * st.rprimd[0][0] # x center of the first grain xcen2 = in_calc.gbpos - 0.75 * st.rprimd[0][0] # z center of the second grain # print "xcen", xcen1, xcen2 d1l = [] d2l = [] rpxx05 = st.rprimd[0][0] * 0.5 for x in xcart_pores: d1 = xcen1 - x[0] d2 = xcen2 - x[0] if d2 < -rpxx05: d2 += st.rprimd[0][0] # assuming that periodic boundary conditions needed only here d1l.append(abs(d1)) d2l.append(abs(d2)) # print d1,d2 imp1 = np.argmin(d1l) # needed numbers of pores imp2 = np.argmin(d2l) # print imp1, imp2 xcart1imp = xcart_pores[imp1] xcart2imp = xcart_pores[imp2] # print "xcartimp", xcart1imp, xcart2imp """3. Define central atoms for segregation and co-segregation cases--------------------------------------------------------""" max_dist_from_gb = 100 if segtyp in ("segreg", "coseg"): # central_atoms = [] max_dist_between_atoms = 4.8 max_dist_from_gb = 3 # main controls for i, x in enumerate(xcart_pores): # generate central atoms d = abs(x[0] - in_calc.gbpos) if d < max_dist_from_gb: central_atoms.append(i) """4. Assume that we always have target_znucl, but only three !!!--------------------------------------------------------""" st.znucl = target_znucl # Please make this part more general st.ntypat = len(set(st.znucl)) print "Warning! Found only ", st.ntypat, "of unique atoms in target_znucl" st.xred = xcart2xred(st.xcart, st.rprimd) """5. Find segreg and co-segreg cases--------------------------------------------------------""" in_calc.init = st dlist_coseg = [] if segtyp == "coseg": print "\nStart searching pairs in gb" # main_path = 'T2/CO/' #! please make more general dlist_coseg = pairs( in_calc, xcart_pores, central_atoms, prec, max_dist_between_atoms, max_dist_from_gb, pairtyp="gb" ) dlist_coseg_exc = [] for el in copy.deepcopy(dlist_coseg): # Exchange C and O only for unsymmetrical cases if "s" in el[2]: continue # not needed for symmetrical cases el[2] = el[2].replace("C", "x") el[2] = el[2].replace("O", "C") el[2] = el[2].replace("x", "O") el[7], el[8] = el[8], el[7] el[3], el[4] = el[4], el[3] dlist_coseg_exc.append(el) for el in dlist_coseg + dlist_coseg_exc: # Helper stname = base_name + el[2] path = main_path + base_name + "_coseg" print ( ( "struct_des['{0:s}'] = des('{1:s}', 'co-segregation configurations; made from " + based_on + "' )" ).format(stname, path) ) for el in dlist_coseg + dlist_coseg_exc: # Helper stname = base_name + el[2] path = main_path + base_name + "_coseg" print "add_loop('" + stname + "','" + based_on.split(".")[ 1 ] + "',range(1,5),calc,conv,varset, 'up1', inherit_option = 'inherit_xred')" write_geometry_files( dlist_coseg + dlist_coseg_exc, in_calc, xcart_pores, segtyp, take_final_rprimd_from, add_typat=add_typat ) elif segtyp == "segreg": """Produce segregation cases only in the case of segreg""" print "\nStart producing segragation cases" dlist_segreg = [] # dlist_segreg1 = copy.deepcopy(input_dlist_coseg) #in this case we use input_dlist with co-segragation cases from pure cell. # dlist_segreg2 = copy.deepcopy(input_dlist_coseg) #There is small error, because positions of pores at grain boundary # #differs in pure cell and cell with impurity in grain volume # for i, el in enumerate(input_dlist_coseg): # sym = '' # if 'is' in el[2]: sym = 'is' # elif 'ms' in el[2]: sym = 'ms' # dlist_segreg1[i][7] = xcart1imp # dlist_segreg1[i][2] = 'CvOi'+str(i+1)+sym # dlist_segreg2[i][8] = xcart1imp # dlist_segreg2[i][2] = 'CiOv'+str(i+1)+sym """new determination based on input_dlist_coseg[0][-1]""" el = copy.deepcopy(input_dlist_coseg[0]) unique = el[-1] # sums and coordinates of unique pores print "unique", unique for i, sx in enumerate(unique): el[2] = "Ci" + str(i + 1) + "Ov" el[7] = sx[1] d1, dnext = image_distance(sx[1], xcart1imp, st.rprimd, 2) d2, dnext = image_distance(sx[1], xcart2imp, st.rprimd, 2) if d1 > d2: el[8] = xcart1imp else: el[8] = xcart2imp # the farthest impurity in grain volume is used dlist_segreg.append(copy.deepcopy(el)) # dlist_segreg = dlist_segreg1 + dlist_segreg2 #Segregation of the first impurity and of the second dlist_segreg_exc = [] for el in copy.deepcopy(dlist_segreg): # Exchange C and O only for unsymmetrical cases if "s" in el[2]: continue # not needed for symmetrical cases el[2] = el[2].replace("C", "x") el[2] = el[2].replace("O", "C") el[2] = el[2].replace("x", "O") el[7], el[8] = el[8], el[7] el[3], el[4] = el[4], el[3] dlist_segreg_exc.append(el) # helper for el in dlist_segreg + dlist_segreg_exc: stname = base_name + el[2] path = main_path + base_name + "_segreg" print ( ( "struct_des['{0:s}'] = des('{1:s}', 'co-segregation configurations; made from " + based_on + "' )" ).format(stname, path) ) for el in dlist_segreg + dlist_segreg_exc: stname = base_name + el[2] path = main_path + base_name + "_segreg" print "add_loop('" + stname + "','" + based_on.split(".")[ 1 ] + "',range(1,5),calc,conv,varset, 'up1', inherit_option = 'inherit_xred')" write_geometry_files( dlist_segreg + dlist_segreg_exc, in_calc, xcart_pores, segtyp, take_final_rprimd_from, add_typat=add_typat ) """6. Find volume cases--------------------------------------------------------""" # this part for construction volume cases if segtyp == "grainvol": # take care that you have only one carbon atom in the grain print "\nStart searching pairs in the volume" central_atoms = [imp1] max_dist_between_atoms = 4.0 # gvolume_config_num = 0 #please choose manually dlist = pairs( in_calc, xcart_pores, central_atoms, prec, max_dist_between_atoms, max_dist_from_gb, pairtyp="gvol" ) # dlist = [dlist[0], copy.deepcopy(dlist[gvolume_config_num-1]) ] # dlist[0][4] = imp2 #no matter wht was dlist[0]; used for vv case dlist.append(copy.deepcopy(dlist[0])) dlist[-1][8] = xcart2imp # last element for both atoms in grain volumes dlist[-1][2] = "CvOvms" # helper for el in dlist: stname = base_name + el[2] path = main_path + base_name + "_gvol" # grain volume print "add_loop('" + stname + "','" + based_on.split(".")[ 1 ] + "',range(1,5),calc,conv,varset, 'up1', inherit_option = 'inherit_xred')" for el in dlist: stname = base_name + el[2] path = main_path + base_name + "_gvol" # grain volume print ( ( "struct_des['{0:s}'] = des('{1:s}', 'co-segregation configurations; made from " + based_on + "' )" ).format(stname, path) ) write_geometry_files(dlist, in_calc, xcart_pores, segtyp, take_final_rprimd_from, add_typat=add_typat) """. Triple cases--------------------------------------------------------""" def triples(addatom=("O", 3), dlist=[], tlist=[], in_calc=None, xcart_pores=[], max_dist_to_next_atom=3): """ Add addatom to all configurations in tlist; addatom[1] - type of atom in typat dlist - list of configurations with two impurity atoms; Used if tlist == []; the format of dlist is quiet special tlist - list of configurations with arbirtary number of atoms; RETURN: tlist - list of configurations with add atoms """ st = in_calc.init if dlist and tlist == []: for el in dlist: par = el print "pair 1", par, x1 = par[7] x2 = par[8] print "x1 = ", x1 print "x2 = ", x2 config = Structure() config.xcart = [x1, x2] config.typat = [2, 3] config.name = el[2] tlist.append(config) tlist_new = [] for config in tlist: xcart = config.xcart typat = config.typat name = config.name print "\n\n\nStart to adding atom to ", name i = 1 dlistlist = [] diffprec = 0.001 [dlistlist.append([]) for x in xcart] print len(dlistlist) for xpor in xcart_pores: skip = True for j, x in enumerate(xcart): # list of 2 or 3 initial atoms to which additional atom will be added if all(np.around(xpor, 5) == np.around(x, 5)): skip = True break d1, d2 = image_distance(x, xpor, st.rprimd, 2) # the minimum distance and the next minimum dist if d1 > max_dist_to_next_atom: skip = True break # if only one pore is larger from atom than limit, the pore is skiped # suml = d11+d21+par[0] # for dl in dlistlist: # print 'j is ', j i_min, smaller = min_diff( d1, dlistlist[j], diffprec ) # old condition - bad - removes unique configurations # if smaller: skip = True; continue # symmetrical pores deleted dlistlist[j].append(d1) skip = False # all conditions are fullfilled - this configuration is unique # else: # print 'List of distances to atoms' if skip: continue # # print "Pore can be used", xpor #sum of distances for triple new = Structure() new.name = name + addatom[0] + str(i) new.xcart = copy.deepcopy(xcart) new.xcart.append(xpor) new.typat = copy.deepcopy(typat) new.typat.append(addatom[1]) # print 'new.typat =', new.typat # calculate sum of lengths new.length = 0 new.lengthCO = 0 new.lengthCC = 0 new.lengthOO = 0 new.xcartC = [] new.xcartO = [] for m, x1 in enumerate(new.xcart): if new.typat[m] == 2: new.xcartC.append(x1) if new.typat[m] == 3: new.xcartO.append(x1) for x2 in new.xcart: d1, d2 = image_distance(x1, x2, st.rprimd, 2) new.length += d1 for xC in new.xcartC: for xO in new.xcartO: d1, d2 = image_distance(xC, xO, st.rprimd, 2) new.lengthCO += d1 for xC1 in new.xcartC: for xC2 in new.xcartC: d1, d2 = image_distance(xC1, xC2, st.rprimd, 2) new.lengthCC += d1 for xO1 in new.xcartO: for xO2 in new.xcartO: d1, d2 = image_distance(xO1, xO2, st.rprimd, 2) new.lengthOO += d1 skip = False n = len(new.xcart) """additional conditions to leave only unique configurations""" for config in tlist_new: if 1: nr = 0 for (v1, t1) in zip(new.xcart, new.typat): for (v2, t2) in zip(config.xcart, config.typat): if all(np.around(v1, 8) == np.around(v2, 8)) and t1 == t2: nr += 1 if nr == n: print "The configurations", new.name, "and", config.name, "consist of the same atoms, continue" skip = True break # print all([ all( np.around(v1, 8) == np.around(v2, 8) ) for (v1, v2) in zip(new.xcart, config.xcart) ]) # check identity using sum of distances # i_min, smaller = min_diff(config.length, [new.length], diffprec) # if smaller: # print "Configuration ", new.name, "has the same sum of lengths as", config.name i_min, smaller1 = min_diff(config.lengthCO, [new.lengthCO], diffprec) i_min, smaller2 = min_diff(config.lengthCC, [new.lengthCC], diffprec) i_min, smaller3 = min_diff(config.lengthOO, [new.lengthOO], diffprec) # print 'Compare', new.name, config.name, smaller1, smaller2, smaller3 if smaller1 and smaller2 and smaller3: print "\nConfiguration ", new.name, "has the same sum of C-O, C-C and O-O lengths as", config.name print skip = True break if skip: continue print "\nSum of CO lengths in :", new.name, new.lengthCC, new.lengthOO, new.lengthCO tlist_new.append(new) i += 1 return tlist_new if segtyp == "bulk_triple" or segtyp == "bulk_pairs": # max_dist_between_atoms = 4.8 print "\nSearching pairs ..." dlist = pairs(in_calc, xcart_pores, central_atoms, prec, max_dist_between_atoms, pairtyp="gvol") if segtyp == "bulk_pairs": write_geometry_files( dlist, in_calc, xcart_pores, segtyp, take_final_rprimd_from, configver=True, add_typat=add_typat ) if segtyp == "bulk_triple": max_dist_to_next_atom = 5.5 print "\nSearching triples ..." # , tlist tlist = [] tlist = triples(("O", 3), dlist, tlist, in_calc, xcart_pores, max_dist_to_next_atom) tlist = triples(("C", 2), dlist, tlist, in_calc, xcart_pores, max_dist_to_next_atom) write_geometry_files( dlist, in_calc, xcart_pores, segtyp, take_final_rprimd_from, tlist=tlist, configver=True, add_typat=add_typat, ) return dlist_coseg, xcart_pores
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.0 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], # 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], # 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 find_pairs(base_name, segtyp, in_calc, central_atoms=[], xcart1imp=None, input_dlist_coseg=None, prec=2, gvolume_config_num=None, gbpos=None, take_final_rprimd_from=None, main_path=None, based_on=None, target_znucl=[22, 6, 8], max_dist_between_atoms=4.8, add_typat=[2, 3]): """ Find uniq pairs of atoms and analyse them Input: segtyp - three regimes for cells with grain boundaries: 'segreg' assumes that in_calc contains carbon atom in grain volume, and creates all cases; 'coseg' assumes pure cell and creates only coseg cases. cosegregation cases of course should be the same for two regimes, however co-segregation configuations after 'coseg' is more easy to relax. 'grainvol' - searching for pairs in grain volume two regimes for bulk cells: 'bulk_triple' - used for bulk cells without grain boundaries; first step is searching for pairs, second step for triples. 'bulk_pairs' - used for bulk cells without grain boundaries; searching for pairs. new_name - name of created structures; at first should be added to struct_des[] in_calc - Calculation() type or path to geo file region - list of numbers which determine region central_atoms - list of atoms for which pairs are constructed (Warinig! numbers in new array xcart_pores!); - parameter to change mode; xcart1imp - coordinates of first interstitial in the grain interior input_dlist_coseg - list of configurations with cosegregation cases. Needed to construct corresponding segregation cases. the format is quiet tricky prec - precision of lengths used to determine unique positions. gvolume_config_num - number of configuration with two atoms in grain volume choosen by user (usually should be the most favourable) gbpos - position of grain boundary take_final_rprimd_from - path to geo file from which rprimd will be used target_znucl - numbers of target atoms max_dist_between_atoms - now at least used for 'bulk_pairs' and 'bulk_triple'; maximum length of found pairs. add_typat - mannualy set please update """ def write_geometry_files(dlist, in_calc, xcart_pores, segtyp, take_final_rprimd_from=None, add_name_before='', tlist=[], configver=False, add_typat=None): """Creating files dlist - list of pairs with distances and numbers in_calc - base calculation without pores tlist - list of additional atoms in the case of triples; list of structures configver - if True each configuration saved as a new version add_typat - manually determined; please automatize! """ print "Warning! add_typat", add_typat if tlist == []: #convert dlist to tlist - to do earlier for el in dlist: config = Structure() config.name = el[2] config.length = el[0] config.typat = add_typat config.xcart = [el[7], el[8]] tlist.append(config) for i, el in enumerate(tlist): #by all found structures print "el name is ", el.name stn = copy.deepcopy(in_calc.init) calc = copy.deepcopy(in_calc) stn.typat.extend(el.typat) stn.xcart.extend(el.xcart) stn.xred = xcart2xred(stn.xcart, stn.rprimd) xcart_check = xred2xcart(stn.xred, stn.rprimd) assert len(xcart_check) == len(stn.xcart) #test assert all( [ all(np.around(v1, 8) == np.around(v2, 8)) for (v1, v2) in zip(stn.xcart, xcart_check) ] ) #check if xcart2xred(stn.xcart,r) and xred2xcart(stn.xred,r) are working correctly up to the eight digits after stn.natom = len(stn.xcart) """Adapt new rprimd""" print "take final rprimd is ", take_final_rprimd_from if take_final_rprimd_from: #read final rprimd and version print "Start to read rprimd and version from " + take_final_rprimd_from in_calc_rprimd = CalculationVasp() in_calc_rprimd.name = 'temp' in_calc_rprimd.read_geometry(take_final_rprimd_from) stn.rprimd = in_calc_rprimd.init.rprimd stn.xcart = xred2xcart(stn.xred, stn.rprimd) calc.version = in_calc_rprimd.version elif configver: calc.version = i + 1 calc.init = stn des = ' was obtained by the insertion of C-O pair into ' + in_calc_name + '; final vectors taken from corresponding ver' calc.build.ipairlen = el.length # Initial length of pair if not hasattr(calc.build, 'nadded') or calc.build.nadded == None: calc.build.nadded = 2 else: calc.build.nadded += 2 if not hasattr(calc.build, 'listadded') or calc.build.listadded == [None]: calc.build.listadded = range( stn.natom - 2, stn.natom) #list of atoms which were added else: calc.build.listadded.extend(range(stn.natom - 2, stn.natom)) structure_name = calc.name + el.name.split('.')[0] #calc.name = add_name_before+calc.name+ '.' +el[2]+'.'+str(calc.version) print 'Structure_name', structure_name if structure_name in struct_des: if configver: fname = structure_name # calc.name+'C2O2' calc.path["input_geo"] = geo_folder + struct_des[ fname].sfolder + '/' + fname + '/' + structure_name + '.' + segtyp + '.' + str( calc.version) + '.geo' else: calc.path["input_geo"] = geo_folder + struct_des[ structure_name].sfolder + '/' + structure_name + '/' + structure_name + '.' + segtyp + '.' + str( calc.version) + '.geo' print "write geo to ", calc.path["input_geo"] calc.write_geometry('init', des) print "write_geometry_files(): name ", el.name stn.name = add_name_before + calc.name + '' + str( el.name) + '.' + str(calc.version) #stn = replic(stn, (1,2,2)) write_xyz(stn) print "__________________________\n\n\n" return def min_diff(f, list, diffprec): """ calculates difference between one number and list of other numbers. return the index of number with smallest difference. if difference is smaller than diffprec returns true as the second argument. """ #print list if list == []: return 0, False mind = min([abs(f - l) for l in list]) with_i = np.asarray([abs(f - l) for l in list]).argmin() return with_i, (mind < diffprec) 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], #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], # 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 """0. BEGIN-------------------------------------------------------------------------------""" hstring = ("%s #on %s" % (traceback.extract_stack(None, 2)[0][3], datetime.date.today())) if hstring != header.history[-1]: header.history.append(hstring) print_and_log("\n\n------Starting find_pairs()-----------...\n") if type(central_atoms) == int: #not in [tuple, list]: central_atoms = [central_atoms] #transform to list if type(in_calc) == str: in_calc_name = in_calc in_calc = CalculationVasp() #in_calc.name = str(in_calc_name) in_calc.name = base_name print "in_calc name is ", in_calc.name in_calc.read_geometry(in_calc_name) if gbpos: in_calc.gbpos = gbpos #rewrite gbpos st = in_calc.init else: """End relaxed structure is used!!!""" st = copy.deepcopy(in_calc.end) in_calc_name = str(in_calc.id) """1. Create separate list of pores and remove them from xcart--------------------------------------------------------""" if "hcp_octa_xred": in_calc.init.name = segtyp + '_all_pores' rep = replic(in_calc.init, (2, 2, 2), -1) write_xyz(rep) #just to check """Coordinates of octapores provided in xcart; znucl = 200;""" xcart = st.xcart typat = st.typat st.typat = [] st.xcart = [] xcart_pores = [] #clean structure from pores with z == 200 and construct xcart_pores for i, x in enumerate(xcart): z = st.znucl[typat[i] - 1] if z == 200: xcart_pores.append(x) #print "Found pore" else: st.xcart.append(x) st.typat.append(typat[i]) st.natom = len(st.xcart) print 'Number of found pores with znucl = 200 is ', len(xcart_pores) for n in central_atoms: if n >= len(xcart_pores): raise RuntimeError """2. Preprocess segreg and grainvol cases--------------------------------------------------------""" # in_calc can be of two types: pure and with C in grain volume; using pure we construct co-segregation cases; using carbon in volume we can construct segregation cases if segtyp in ('segreg', 'grainvol'): if 2 in st.typat: # impurity in grain volume; (now assume that Carbon) iimp = st.typat.index(2) xcart1imp = st.xcart[iimp] #save coordinates of carbon atom del st.xcart[iimp] del st.typat[iimp] st.natom -= 1 #and remove it #del st.xred[iimp] st.ntypat -= 1 del st.znucl[1] print "Impurity atom was removed from cell" if xcart1imp: #for compatibility with previous cases; better not to use imp1 = len(xcart_pores) xcart_pores.append(xcart1imp) xcart2imp = xcart1imp - 0.5 * st.rprimd[ 0] #determine coordinates of second impurity assuming that we have mirror symmetry if xcart2imp[0] < 0: xcart2imp = xcart1imp + 0.5 * st.rprimd[0] imp2 = imp1 + 1 xcart_pores.append(xcart2imp) else: #new version; both central pores are found in the pure cell!!! #We have pure cell here; Find central pore in 1st grain and 2nd grain: xcen1 = in_calc.gbpos - 0.25 * st.rprimd[0][ 0] #x center of the first grain xcen2 = in_calc.gbpos - 0.75 * st.rprimd[0][ 0] #z center of the second grain # print "xcen", xcen1, xcen2 d1l = [] d2l = [] rpxx05 = st.rprimd[0][0] * 0.5 for x in xcart_pores: d1 = xcen1 - x[0] d2 = xcen2 - x[0] if d2 < -rpxx05: d2 += st.rprimd[0][ 0] # assuming that periodic boundary conditions needed only here d1l.append(abs(d1)) d2l.append(abs(d2)) # print d1,d2 imp1 = np.argmin(d1l) #needed numbers of pores imp2 = np.argmin(d2l) # print imp1, imp2 xcart1imp = xcart_pores[imp1] xcart2imp = xcart_pores[imp2] # print "xcartimp", xcart1imp, xcart2imp """3. Define central atoms for segregation and co-segregation cases--------------------------------------------------------""" max_dist_from_gb = 100 if segtyp in ('segreg', 'coseg'): # central_atoms = [] max_dist_between_atoms = 4.8 max_dist_from_gb = 3 #main controls for i, x in enumerate(xcart_pores): #generate central atoms d = abs(x[0] - in_calc.gbpos) if d < max_dist_from_gb: central_atoms.append(i) """4. Assume that we always have target_znucl, but only three !!!--------------------------------------------------------""" st.znucl = target_znucl #Please make this part more general st.ntypat = len(set(st.znucl)) print 'Warning! Found only ', st.ntypat, 'of unique atoms in target_znucl' st.xred = xcart2xred(st.xcart, st.rprimd) """5. Find segreg and co-segreg cases--------------------------------------------------------""" in_calc.init = st dlist_coseg = [] if segtyp == 'coseg': print "\nStart searching pairs in gb" # main_path = 'T2/CO/' #! please make more general dlist_coseg = pairs(in_calc, xcart_pores, central_atoms, prec, max_dist_between_atoms, max_dist_from_gb, pairtyp='gb') dlist_coseg_exc = [] for el in copy.deepcopy( dlist_coseg): #Exchange C and O only for unsymmetrical cases if 's' in el[2]: continue # not needed for symmetrical cases el[2] = el[2].replace('C', 'x') el[2] = el[2].replace('O', 'C') el[2] = el[2].replace('x', 'O') el[7], el[8] = el[8], el[7] el[3], el[4] = el[4], el[3] dlist_coseg_exc.append(el) for el in dlist_coseg + dlist_coseg_exc: # Helper stname = base_name + el[2] path = main_path + base_name + '_coseg' print(( "struct_des['{0:s}'] = des('{1:s}', 'co-segregation configurations; made from " + based_on + "' )").format(stname, path)) for el in dlist_coseg + dlist_coseg_exc: # Helper stname = base_name + el[2] path = main_path + base_name + '_coseg' print "add_loop('" + stname + "','" + based_on.split( '.' )[1] + "',range(1,5),calc,conv,varset, 'up1', inherit_option = 'inherit_xred')" write_geometry_files(dlist_coseg + dlist_coseg_exc, in_calc, xcart_pores, segtyp, take_final_rprimd_from, add_typat=add_typat) elif segtyp == 'segreg': """Produce segregation cases only in the case of segreg""" print "\nStart producing segragation cases" dlist_segreg = [] # dlist_segreg1 = copy.deepcopy(input_dlist_coseg) #in this case we use input_dlist with co-segragation cases from pure cell. # dlist_segreg2 = copy.deepcopy(input_dlist_coseg) #There is small error, because positions of pores at grain boundary # #differs in pure cell and cell with impurity in grain volume # for i, el in enumerate(input_dlist_coseg): # sym = '' # if 'is' in el[2]: sym = 'is' # elif 'ms' in el[2]: sym = 'ms' # dlist_segreg1[i][7] = xcart1imp # dlist_segreg1[i][2] = 'CvOi'+str(i+1)+sym # dlist_segreg2[i][8] = xcart1imp # dlist_segreg2[i][2] = 'CiOv'+str(i+1)+sym """new determination based on input_dlist_coseg[0][-1]""" el = copy.deepcopy(input_dlist_coseg[0]) unique = el[-1] #sums and coordinates of unique pores print "unique", unique for i, sx in enumerate(unique): el[2] = 'Ci' + str(i + 1) + 'Ov' el[7] = sx[1] d1, dnext = image_distance(sx[1], xcart1imp, st.rprimd, 2) d2, dnext = image_distance(sx[1], xcart2imp, st.rprimd, 2) if d1 > d2: el[8] = xcart1imp else: el[8] = xcart2imp # the farthest impurity in grain volume is used dlist_segreg.append(copy.deepcopy(el)) #dlist_segreg = dlist_segreg1 + dlist_segreg2 #Segregation of the first impurity and of the second dlist_segreg_exc = [] for el in copy.deepcopy( dlist_segreg): #Exchange C and O only for unsymmetrical cases if 's' in el[2]: continue # not needed for symmetrical cases el[2] = el[2].replace('C', 'x') el[2] = el[2].replace('O', 'C') el[2] = el[2].replace('x', 'O') el[7], el[8] = el[8], el[7] el[3], el[4] = el[4], el[3] dlist_segreg_exc.append(el) #helper for el in dlist_segreg + dlist_segreg_exc: stname = base_name + el[2] path = main_path + base_name + '_segreg' print(( "struct_des['{0:s}'] = des('{1:s}', 'co-segregation configurations; made from " + based_on + "' )").format(stname, path)) for el in dlist_segreg + dlist_segreg_exc: stname = base_name + el[2] path = main_path + base_name + '_segreg' print "add_loop('" + stname + "','" + based_on.split( '.' )[1] + "',range(1,5),calc,conv,varset, 'up1', inherit_option = 'inherit_xred')" write_geometry_files(dlist_segreg + dlist_segreg_exc, in_calc, xcart_pores, segtyp, take_final_rprimd_from, add_typat=add_typat) """6. Find volume cases--------------------------------------------------------""" # this part for construction volume cases if segtyp == "grainvol": #take care that you have only one carbon atom in the grain print "\nStart searching pairs in the volume" central_atoms = [imp1] max_dist_between_atoms = 4. #gvolume_config_num = 0 #please choose manually dlist = pairs(in_calc, xcart_pores, central_atoms, prec, max_dist_between_atoms, max_dist_from_gb, pairtyp='gvol') #dlist = [dlist[0], copy.deepcopy(dlist[gvolume_config_num-1]) ] #dlist[0][4] = imp2 #no matter wht was dlist[0]; used for vv case dlist.append(copy.deepcopy(dlist[0])) dlist[-1][8] = xcart2imp #last element for both atoms in grain volumes dlist[-1][2] = 'CvOvms' #helper for el in dlist: stname = base_name + el[2] path = main_path + base_name + '_gvol' #grain volume print "add_loop('" + stname + "','" + based_on.split( '.' )[1] + "',range(1,5),calc,conv,varset, 'up1', inherit_option = 'inherit_xred')" for el in dlist: stname = base_name + el[2] path = main_path + base_name + '_gvol' #grain volume print(( "struct_des['{0:s}'] = des('{1:s}', 'co-segregation configurations; made from " + based_on + "' )").format(stname, path)) write_geometry_files(dlist, in_calc, xcart_pores, segtyp, take_final_rprimd_from, add_typat=add_typat) """. Triple cases--------------------------------------------------------""" def triples(addatom=('O', 3), dlist=[], tlist=[], in_calc=None, xcart_pores=[], max_dist_to_next_atom=3): """ Add addatom to all configurations in tlist; addatom[1] - type of atom in typat dlist - list of configurations with two impurity atoms; Used if tlist == []; the format of dlist is quiet special tlist - list of configurations with arbirtary number of atoms; RETURN: tlist - list of configurations with add atoms """ st = in_calc.init if dlist and tlist == []: for el in dlist: par = el print 'pair 1', par, x1 = par[7] x2 = par[8] print 'x1 = ', x1 print 'x2 = ', x2 config = Structure() config.xcart = [x1, x2] config.typat = [2, 3] config.name = el[2] tlist.append(config) tlist_new = [] for config in tlist: xcart = config.xcart typat = config.typat name = config.name print '\n\n\nStart to adding atom to ', name i = 1 dlistlist = [] diffprec = 0.001 [dlistlist.append([]) for x in xcart] print len(dlistlist) for xpor in xcart_pores: skip = True for j, x in enumerate( xcart ): # list of 2 or 3 initial atoms to which additional atom will be added if all(np.around(xpor, 5) == np.around(x, 5)): skip = True break d1, d2 = image_distance( x, xpor, st.rprimd, 2) # the minimum distance and the next minimum dist if d1 > max_dist_to_next_atom: skip = True break #if only one pore is larger from atom than limit, the pore is skiped # suml = d11+d21+par[0] # for dl in dlistlist: # print 'j is ', j i_min, smaller = min_diff( d1, dlistlist[j], diffprec ) #old condition - bad - removes unique configurations #if smaller: skip = True; continue # symmetrical pores deleted dlistlist[j].append(d1) skip = False # all conditions are fullfilled - this configuration is unique # else: # print 'List of distances to atoms' if skip: continue # #print "Pore can be used", xpor #sum of distances for triple new = Structure() new.name = name + addatom[0] + str(i) new.xcart = copy.deepcopy(xcart) new.xcart.append(xpor) new.typat = copy.deepcopy(typat) new.typat.append(addatom[1]) # print 'new.typat =', new.typat #calculate sum of lengths new.length = 0 new.lengthCO = 0 new.lengthCC = 0 new.lengthOO = 0 new.xcartC = [] new.xcartO = [] for m, x1 in enumerate(new.xcart): if new.typat[m] == 2: new.xcartC.append(x1) if new.typat[m] == 3: new.xcartO.append(x1) for x2 in new.xcart: d1, d2 = image_distance(x1, x2, st.rprimd, 2) new.length += d1 for xC in new.xcartC: for xO in new.xcartO: d1, d2 = image_distance(xC, xO, st.rprimd, 2) new.lengthCO += d1 for xC1 in new.xcartC: for xC2 in new.xcartC: d1, d2 = image_distance(xC1, xC2, st.rprimd, 2) new.lengthCC += d1 for xO1 in new.xcartO: for xO2 in new.xcartO: d1, d2 = image_distance(xO1, xO2, st.rprimd, 2) new.lengthOO += d1 skip = False n = len(new.xcart) """additional conditions to leave only unique configurations""" for config in tlist_new: if 1: nr = 0 for (v1, t1) in zip(new.xcart, new.typat): for (v2, t2) in zip(config.xcart, config.typat): if all(np.around(v1, 8) == np.around( v2, 8)) and t1 == t2: nr += 1 if nr == n: print "The configurations", new.name, 'and', config.name, 'consist of the same atoms, continue' skip = True break # print all([ all( np.around(v1, 8) == np.around(v2, 8) ) for (v1, v2) in zip(new.xcart, config.xcart) ]) #check identity using sum of distances # i_min, smaller = min_diff(config.length, [new.length], diffprec) # if smaller: # print "Configuration ", new.name, "has the same sum of lengths as", config.name i_min, smaller1 = min_diff(config.lengthCO, [new.lengthCO], diffprec) i_min, smaller2 = min_diff(config.lengthCC, [new.lengthCC], diffprec) i_min, smaller3 = min_diff(config.lengthOO, [new.lengthOO], diffprec) # print 'Compare', new.name, config.name, smaller1, smaller2, smaller3 if smaller1 and smaller2 and smaller3: print "\nConfiguration ", new.name, "has the same sum of C-O, C-C and O-O lengths as", config.name print skip = True break if skip: continue print '\nSum of CO lengths in :', new.name, new.lengthCC, new.lengthOO, new.lengthCO tlist_new.append(new) i += 1 return tlist_new if segtyp == "bulk_triple" or segtyp == "bulk_pairs": # max_dist_between_atoms = 4.8 print "\nSearching pairs ..." dlist = pairs(in_calc, xcart_pores, central_atoms, prec, max_dist_between_atoms, pairtyp='gvol') if segtyp == "bulk_pairs": write_geometry_files(dlist, in_calc, xcart_pores, segtyp, take_final_rprimd_from, configver=True, add_typat=add_typat) if segtyp == "bulk_triple": max_dist_to_next_atom = 5.5 print "\nSearching triples ..." #, tlist tlist = [] tlist = triples(('O', 3), dlist, tlist, in_calc, xcart_pores, max_dist_to_next_atom) tlist = triples(('C', 2), dlist, tlist, in_calc, xcart_pores, max_dist_to_next_atom) write_geometry_files(dlist, in_calc, xcart_pores, segtyp, take_final_rprimd_from, tlist=tlist, configver=True, add_typat=add_typat) return dlist_coseg, xcart_pores
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], #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], # 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