def add_neb(starting_calc = None, st = None, it_new = None, ise_new = None, i_atom_to_move = None, up = 'up1', search_type = 'vacancy_creation', images = 3, r_impurity = None, corenum = 15, calc_method = ['neb'], inherit_option = None, mag_config = None, i_void_start = None, i_void_final = None, atom_to_insert = None, replicate = None, it_new_folder = None, inherit_magmom = False, x_start = None, xr_start = None, x_final = None, xr_final = None, upload_vts = False, run = False ): """ Prepare needed files for NEB Provides several regimes controlled by *search_type* flag: - existing_voids - search for voids around atom and use them as a final position - vacancy_creation - search for neighbors of the same type and make a vacancy as a start position - interstitial_insertion - search for two neighboring voids; use them as start and final positions by inserting atom *atom_to_insert* ###INPUT: - starting_calc (Calculation) - Calculation object with structure - st (Structure) - structure, can be used instead of Calculation - it_new (str) - name for calculation - i_atom_to_move (int) - number of atom for moving; - *mag_config* (int ) - choose magnetic configuration - allows to obtain different localizations of electron - *replicate* (tuple 3*int) - replicate cell along rprimd - i_void_start, i_void_final (int) - number of voids from the suggested lists - atom_to_insert (str) - element name of atom to insert - it_new_folder (str) - section folder - inherit_option (str) - passed only to add_loop - inherit_magmom (bool) - if True than magmom from starting_calc is used, else from set - calc_method (list) - 'neb' - 'only_neb' - run only footer - x_start, x_final (array) - explicit coordinates of moving atom for starting and final positions, combined with atom_to_insert - upload_vts (bool) - if True upload Vasp.pm and nebmake.pl to server - run (bool) - run on server ###RETURN: None ###DEPENDS: ###TODO please take care of manually provided i_atom_to_move in case of replicate flag using init_numbers """ calc = header.calc struct_des = header.struct_des varset = header.varset if not hasattr(calc_method, '__iter__'): calc_method = [calc_method] if starting_calc and st: printlog('Warning! both *starting_calc* and *st* are provided. I use *starting_calc*') st = copy.deepcopy(starting_calc.end) elif starting_calc: st = copy.deepcopy(starting_calc.end) printlog('I use *starting_calc*') elif st: '' printlog('I use *st*') else: printlog('Error! no input structure. Use either *starting_calc* or *st*') if corenum: # header.corenum = corenum '' else: corenum = header.CORENUM if corenum % images > 0: print_and_log('Error! Number of cores should be dividable by number of IMAGES') name_suffix = '' st_pores = [] name_suffix+='n'+str(images) """Replicate cell """ if replicate: print_and_log('You have chosen to replicate the structure by', replicate) st = replic(st, mul = replicate) name_suffix += str(replicate[0])+str(replicate[1])+str(replicate[2]) """1. Choose atom (or insert) for moving """ atoms_to_move = [] for i, typ, x in zip(range(st.natom), st.typat, st.xcart): #try to find automatically if st.znucl[typ-1] == 3: #Li atoms_to_move.append([i, 'Li', x]) if st.znucl[typ-1] == 11: # atoms_to_move.append([i, 'Na', x]) if st.znucl[typ-1] == 19: # atoms_to_move.append([i, 'K', x]) if is_list_like(xr_start): x_start = xred2xcart([xr_start], st.rprimd)[0] st1 = st.add_atoms([x_start], atom_to_insert) x_m = x_start name_suffix+='s' write_xyz(st1, file_name = st.name+'_manually_start') printlog('Start position is created manually by adding xr_start', xr_start, x_start) elif not atoms_to_move: print_and_log('No atoms to move found, you probably gave me intercalated structure', important = 'y') print_and_log('Searching for voids', important = 'y') st_pores = find_pores(st, r_matrix = 0.5, r_impurity = r_impurity, fine = 1, calctype = 'all_pores') print_and_log('List of found voids:\n', np.array(st_pores.xcart) ) write_xyz(st.add_atoms(st_pores.xcart, 'H'), file_name = st.name+'_possible_positions') write_xyz(st.add_atoms(st_pores.xcart, 'H'), replications = (2,2,2), file_name = st.name+'_possible_positions_replicated') sums = [] avds = [] for x in st_pores.xcart: summ = local_surrounding(x, st, n_neighbours = 6, control = 'sum', periodic = True) avd = local_surrounding(x, st, n_neighbours = 6, control = 'av_dev', periodic = True) # print sur, sums.append(summ) avds.append(avd[0]) # print sums = np.array(sums) avds = np.array(avds).round(0) print_and_log('Sum of distances to 6 neighboring atoms for each void (A):\n', sums, imp ='y') print_and_log('Distortion of voids (0 - is symmetrical):\n', avds, imp ='y') crude_prec = 1 sums_crude = np.unique(sums.round(crude_prec)) print_and_log('The unique voids based on the sums:', '\nwith 0.01 A prec:',np.unique(sums.round(2)), '\nwith 0.1 A prec:',sums_crude, imp ='y') print_and_log('Based on crude criteria only', len(sums_crude),'types of void are relevant') print_and_log('Please use *i_void_start* to choose the void for atom insertion from this Table:', end = '\n', imp = 'Y') insert_positions = [] start_table = [] for i, s in enumerate(sums_crude): index_of_first = np.where(sums.round(crude_prec)==s)[0][0] start_table.append([i, st_pores.xcart[index_of_first].round(2), index_of_first, avds[index_of_first], sums[index_of_first] ]) insert_positions.append( st_pores.xcart[index_of_first] ) print_and_log( tabulate(start_table, headers = ['Start void #', 'Cart.', 'Index', 'Dev.', 'Sum'], tablefmt='psql'), imp = 'Y' ) if i_void_start == None: sys.exit() st = st.add_atoms([insert_positions[i_void_start],], atom_to_insert) name_suffix+='i'+str(i_void_start) i_m = st.natom-1 x_m = st.xcart[i_m] search_type = 'existing_voids' type_atom_to_move = atom_to_insert el_num_suffix = '' else: print_and_log('I have found', len(atoms_to_move), ' anion atoms', important = 'n') print_and_log( 'Sums of bond lengths around these atoms:',) sums = [] for a in atoms_to_move: summ = local_surrounding(a[2], st, n_neighbours = 6, control = 'sum', periodic = True) sums.append(summ) # print( summ, end = '') print_and_log('\nAmong them only',len(set(sums)), 'unique' , important = 'n') # if print_and_log('Choosing the first' , important = 'n') type_atom_to_move = atoms_to_move[0][1] i_atom_to_move = atoms_to_move[0][0]+1 el_num_suffix = type_atom_to_move +str(i_atom_to_move) i_m = i_atom_to_move-1 x_m = st.xcart[i_m] #highlight the moving atom for user for double-check # st_new = st.change_atom_z(i_m, new_z = 100) # search_type = 'vacancy_creation' """2. Choose final position""" if is_list_like(xr_final): x_final = xred2xcart([xr_final], st.rprimd)[0] st2 = st.add_atoms([x_final], atom_to_insert) x_del = x_final search_type = 'manual_insertion' name_suffix+='f'+atom_to_insert write_xyz(st2, file_name = st.name+'_manually_final') printlog('Final position is created manually by adding xr_final', xr_final, x_del) elif search_type == 'existing_voids': #Search for voids around choosen atoms if not st_pores: st_pores = find_pores(st, r_matrix = 0.5, r_impurity = r_impurity, fine = 2, calctype = 'all_pores') sur = local_surrounding(x_m, st_pores, n_neighbours = len(st_pores.xcart), control = 'atoms', periodic = True) # print sur print_and_log( 'I can suggest you '+str (len(sur[0])-1 )+' end positions.' ) # The distances to them are : '+str(np.round(sur[3], 2) )+' A\n ', # 'Openning Jmol end positions are highlighted by inserting H ', important = 'y') # print x_m # print sur[0] print_and_log('Please choose *i_void_final* from the following Table:', end = '\n', imp = 'Y') final_table = [] for i, (x, d, ind) in enumerate( zip(sur[0], sur[3], sur[2])[1:] ): final_table.append([i, np.array(x).round(2), round(d, 2), avds[ind], sums[ind] ] ) print_and_log( tabulate(final_table, headers = ['Final void #', 'Cart.', 'Dist', 'Dev.', 'Sum'], tablefmt='psql'), imp = 'Y' ) if i_void_final == None: sys.exit() x_final = sur[0][i_void_final+1] # +1 because first element is x_m atom itself write_xyz(st.add_atoms([ x_final], 'H'), replications = (2,2,2), file_name = st.name+'_possible_positions2_replicated') # sys.exit() # write_xyz(st.add_atoms(sur[0][2:3], 'H'), analysis = 'imp_surrounding', show_around = 230,nnumber = 10, replications = (2,2,2), file_name = 'local230') # # write_xyz(st.add_atoms(sur[0][0:1], 'H'), analysis = 'imp_surrounding', show_around = 226,nnumber = 10, replications = (2,2,2), file_name = 'local') # run_jmol print_and_log('Choosing the closest position as end', important = 'n') # i_void_final = 0 st1 = st # print st1.natom # sys.exit() st2 = st.mov_atoms(i_m, x_final) name_suffix += el_num_suffix+'e'+str(i_void_final)+atom_to_insert st1 = return_atoms_to_cell(st1) st2 = return_atoms_to_cell(st2) write_xyz(st1, file_name = st1.name+name_suffix +'_start') write_xyz(st2, file_name = st2.name+name_suffix +'_final') elif search_type == 'vacancy_creation': #Create vacancy by removing some neibouring atom of the same type print_and_log('You have chosen vacancy_creation mode of add_neb tool', important = 'Y') print_and_log( 'Type of atom to move = ', type_atom_to_move, imp = 'y') # print 'List of left atoms = ', np.array(st.leave_only(type_atom_to_move).xcart) sur = local_surrounding(x_m, st.leave_only(type_atom_to_move) , n_neighbours = 4, control = 'atoms', periodic = False) # print 'xcart of moving atom', x_m # print 'Local surround = ', sur # print 'len', len(sur[0]) if len(sur[0]) < 3: # print 'rprimd = \n',np.array(st.rprimd) # print 'r lengths = \n',( [np.linalg.norm(r) for r in st.rprimd] ) # print 'xred = \n', np.array(st.xred) # print 'xcart = \n', np.array(st.xcart) print_and_log('The supercell is too small, I increase it 8 times!') st = replic(st, mul = (2,2,2) ) sur = local_surrounding(x_m, st.leave_only(type_atom_to_move) , n_neighbours = 4, control = 'atoms', periodic = False) # print 'xcart of moving atom', x_m write_xyz(st, file_name = st.name+'_replicated')#replications = (2,2,2)) # print 'Local surround = ', sur # sys.exit() print_and_log( 'I can suggest you '+str (len(sur[0]) )+' end positions. The distances to them are : '+str(np.round(sur[3], 2) )+' A\n ', 'They are all', type_atom_to_move, 'atoms', important = 'y') print_and_log('Choosing the closest position as end', important = 'n') neb_config = 1 #cause the first item in sur is moving atom itself x_del = sur[0][neb_config] i_del = st.find_atom_num_by_xcart(x_del) print_and_log('Making vacancy at end position for starting configuration', important = 'n') print_and_log( 'number of atom to delete = ', i_del) # print st.magmom st1 = st.del_atom(i_del) # print st1.magmom print_and_log('Making vacancy at start position for final configuration', important = 'n') st2 = st.mov_atoms(i_m, x_del) # i_m and sur[0][neb_config] should coincide st2 = st2.del_atom(i_del) # these two steps provide the same order name_suffix += el_num_suffix+'v'+str(neb_config) write_xyz(st1, file_name = st1.name+'_start')# replications = (2,2,2)) write_xyz(st2, file_name = st2.name+'_end')# replications = (2,2,2)) # sys.exit() # sys.exit() """ Determining magnetic moments """ if varset[ise_new].vasp_params['ISPIN'] == 2: print_and_log('Magnetic calculation detected. Preparing spin modifications ...', imp = 'y') cl_test = CalculationVasp(varset[ise_new]) cl_test.init = st1 # print 'asdfsdfasdfsadfsadf', st1.magmom if inherit_magmom and hasattr(st, 'magmom') and st.magmom and any(st.magmom): print_and_log('inherit_magmom=True: You have chosen MAGMOM from provided structure', imp = 'y') name_suffix+='mp' #Magmom from Previous else: cl_test.init.magmom = None print_and_log('inherit_magmom=False or no magmom in input structure : MAGMOM will be determined from set', imp = 'y') name_suffix+='ms' #Magmom from Set cl_test.actualize_set() #find magmom for current structure st1.magmom = copy.deepcopy(cl_test.init.magmom) st2.magmom = copy.deepcopy(cl_test.init.magmom) # sys.exit() # print_and_log('The magnetic moments from set:') # print cl_test.init.magmom #checking for closest atoms now only for Fe, Mn, Ni, Co sur = local_surrounding(x_m, st1, n_neighbours = 3, control = 'atoms', periodic = True, only_elements = header.TRANSITION_ELEMENTS) dist = np.array(sur[3]).round(2) numb = np.array(sur[2]) a = zip(numb, dist ) # a= np.array(a) # print a[1] # a = np.apply_along_axis(np.unique, 1, a) # print a def unique_by_key(elements, key=None): if key is None: # no key: the whole element must be unique key = lambda e: e return list ( {key(el): el for el in elements}.values() ) # print a mag_atoms_dists = unique_by_key(a, key=itemgetter(1)) # print (mag_atoms_dists) # a = unique_by_key(a, key=itemgetter(1)) print_and_log( 'I change spin for the following atoms:\ni atom dist\n', np.round(mag_atoms_dists, 2) , imp = 'y' ) # print 'I have found closest Fe atoms' muls = [(1.2, 0.6), (0.6, 1.2)] mag_moments_variants = [] for mm in muls: mags = copy.deepcopy(cl_test.init.magmom) # print mags for a, m in zip(mag_atoms_dists, mm): # print t[1] mags[a[0]] = mags[a[0]]*m mag_moments_variants.append(mags) print_and_log( 'The list of possible mag_moments:', imp = 'y' ) for i, mag in enumerate(mag_moments_variants): print_and_log( i, mag) print_and_log( 'Please use *mag_config* arg to choose desired config' , imp = 'y' ) if mag_config != None: st1.magmom = copy.deepcopy(mag_moments_variants[mag_config]) st2.magmom = copy.deepcopy(mag_moments_variants[mag_config]) name_suffix+='m'+str(mag_config) print_and_log('You have chosen mag configuration #',mag_config,imp = 'y') else: print_and_log('Non-magnetic calculation continue ...') """3. Add to struct_des, create geo files, check set, add_loop """ if starting_calc: it = starting_calc.id[0] it_new = it+'v'+str(starting_calc.id[2])+'.'+name_suffix if not it_new_folder: it_new_folder = struct_des[it].sfolder+'/neb/' obtained_from = str(starting_calc.id) if not ise_new: print_and_log('I will run add_loop() using the same set', important = 'Y') ise_new = cl.id[1] elif st: if not it_new: printlog('Error! please provide *it_new* - name for your calculation', important = 'Y') it = None it_new+='.'+name_suffix obtained_from = st.name if not ise_new: printlog('Error! please provide *ise_new*', important = 'Y') if not it_new_folder: printlog('Error! please provide *it_new_folder* - folder for your new calculation', important = 'Y') if it_new not in struct_des: add_des(struct_des, it_new, it_new_folder, 'Automatically created and added from '+obtained_from ) print_and_log('Creating geo files for starting and final configurations (versions 1 and 2) ', important = 'y') # if starting_calc: # cl = copy.deepcopy(starting_calc) # else: cl = CalculationVasp() #write start position struct_des[it_new].x_m_ion_start = x_m struct_des[it_new].xr_m_ion_start = xcart2xred([x_m], st1.rprimd)[0] cl.end = st1 ver_new = 1 cl.version = ver_new cl.path["input_geo"] = header.geo_folder + struct_des[it_new].sfolder + '/' + \ it_new+"/"+it_new+'.auto_created_starting_position_for_neb_'+search_type+'.'+str(ver_new)+'.'+'geo' cl.write_siman_geo(geotype = 'end', description = 'Starting conf. for neb from '+obtained_from, override = True) #write final position struct_des[it_new].x_m_ion_final = x_del struct_des[it_new].xr_m_ion_final = xcart2xred([x_del], st2.rprimd)[0] cl.end = st2 ver_new = 2 cl.version = ver_new cl.path["input_geo"] = header.geo_folder + struct_des[it_new].sfolder + '/' + \ it_new+"/"+it_new+'.auto_created_final_position_for_neb_'+search_type+'.'+str(ver_new)+'.'+'geo' cl.write_siman_geo(geotype = 'end', description = 'Final conf. for neb from '+obtained_from, override = True) #prepare calculations #Check if nebmake is avail # if int(runBash('ssh '+cluster_address+' test -e '+project_path_cluster+'/tools/vts/nebmake.pl; echo $?') ): # '' # print_and_log('Please upload vtsttools to ',cluster_address, project_path_cluster+'/tools/vts/') # raise RuntimeError # copy_to_server(path_to_wrapper+'/vtstscripts/nebmake.pl', to = project_path_cluster+'/tools/', addr = cluster_address) # if int(runBash('ssh '+cluster_address+' test -e '+project_path_cluster+'/tools/Vasp.pm; echo $?') ): # copy_to_server(path_to_wrapper+'/vtstscripts/Vasp.pm', to = project_path_cluster+'/tools/', addr = cluster_address) inherit_ngkpt(it_new, it, varset[ise_new]) add_loop(it_new, ise_new, verlist = [1,2], up = up, calc_method = calc_method, savefile = 'ov', inherit_option = inherit_option, n_neb_images = images, corenum = corenum, run =run ) if upload_vts: siman_dir = os.path.dirname(__file__) # print(upload_vts) push_to_server([siman_dir+'/cluster_tools/nebmake.pl', siman_dir+'/cluster_tools/Vasp.pm'], to = header.cluster_home+'/tools/vts', addr = header.cluster_address) else: print_and_log('Please be sure that vtsttools are at',header.cluster_address, header.cluster_home+'/tools/vts/', imp = 'Y') return it_new
def add_neb( starting_calc=None, st=None, st_end=None, it_new=None, ise_new=None, i_atom_to_move=None, up='up2', search_type='vacancy_creation', images=None, r_impurity=None, corenum=None, calc_method=['neb'], inherit_option=None, mag_config=None, i_void_start=None, i_void_final=None, atom_to_insert=None, atom_to_move=None, rep_moving_atom=None, end_pos_types_z=None, replicate=None, it_new_folder=None, inherit_magmom=False, x_start=None, xr_start=None, x_final=None, xr_final=None, upload_vts=False, run=False, add_loop_dic=None, old_behaviour=None, ): """ Prepare needed files for NEB Provides several regimes controlled by *search_type* flag: - existing_voids - search for voids around atom and use them as a final position - vacancy_creation - search for neighbors of the same type and make a vacancy as a start position - interstitial_insertion - search for two neighboring voids; use them as start and final positions by inserting atom *atom_to_insert* - None - just use st and st2 as initial and final ###INPUT: - starting_calc (Calculation) - Calculation object with structure - st (Structure) - structure, can be used instead of Calculation - it_new (str) - name for calculation - st_end (Structure) - final structure - i_atom_to_move (int) - number of atom for moving starting from 0; - *mag_config* (int ) - choose magnetic configuration - allows to obtain different localizations of electron - *replicate* (tuple 3*int) - replicate cell along rprimd - i_void_start, i_void_final (int) - position numbers of voids (or atoms) from the suggested lists - atom_to_insert (str) - element name of atom to insert - atom_to_move (str) - element name of atom to move - it_new_folder (str) - section folder - inherit_option (str) - passed only to add_loop - inherit_magmom (bool) - if True than magmom from starting_calc is used, else from set - end_pos_types_z (list of int) - list of Z - type of atoms, which could be considered as final positions in vacancy creation mode - calc_method (list) - 'neb' - 'only_neb' - run only footer - x_start, x_final (array) - explicit xcart coordinates of moving atom for starting and final positions, combined with atom_to_insert - xr_start, xr_final (array) - explicit xred - rep_moving_atom (str)- replace moving atom by needed atom - can be useful than completly different atom is needed. - upload_vts (bool) - if True upload Vasp.pm and nebmake.pl to server - run (bool) - run on server ###RETURN: None ###DEPENDS: ###TODO 1. Take care of manually provided i_atom_to_move in case of replicate flag using init_numbers 2. For search_type == None x_m and x_del should be determined for magnetic searching and for saving their coordinates to struct_des; now their just (0,0,0) """ if old_behaviour: naming_conventions209 = False # else: naming_conventions209 = True # set False to reproduce old behavior before 2.09.2017 # print(atom_to_insert) # sys.exit() calc = header.calc struct_des = header.struct_des varset = header.varset if not add_loop_dic: add_loop_dic = {} if not end_pos_types_z: end_pos_types_z = [] if not hasattr(calc_method, '__iter__'): calc_method = [calc_method] if starting_calc and st: printlog( 'Warning! both *starting_calc* and *st* are provided. I use *starting_calc*' ) st = copy.deepcopy(starting_calc.end) elif starting_calc: st = copy.deepcopy(starting_calc.end) printlog('I use *starting_calc*') elif st: '' printlog('I use *st*') else: printlog( 'Error! no input structure. Use either *starting_calc* or *st*') if corenum == None: if images == 3: corenum = 15 elif images == 5: corenum = 15 elif images == 7: corenum = 14 else: printlog('add_neb(): Error! number of images', images, 'is unknown to me; please provide corenum!') # print(atom_to_insert) # sys.exit() if corenum: # header.corenum = corenum '' else: corenum = header.CORENUM if corenum % images > 0: print_and_log( 'Error! Number of cores should be dividable by number of IMAGES', images, corenum) if not ise_new: ise_new = starting_calc.id[1] printlog('I use', ise_new, 'as ise_new', imp='y') name_suffix = '' st_pores = [] name_suffix += 'n' + str(images) """Replicate cell """ if replicate: print_and_log('You have chosen to replicate the structure by', replicate) st = replic(st, mul=replicate) name_suffix += str(replicate[0]) + str(replicate[1]) + str( replicate[2]) printlog('Search type is ', search_type) if search_type == None: if st_end == None: printlog( 'Error! You have provided search_type == None, st_end should be provided!' ) st1 = st st2 = st_end x_m = (0, 0, 0) x_del = (0, 0, 0) else: """1. Choose atom (or insert) for moving """ if is_list_like(xr_start): x_start = xred2xcart([xr_start], st.rprimd)[0] st1, i_m = st.add_atoms([x_start], atom_to_insert, return_ins=1) x_m = x_start # i_m = st1.find_atom_num_by_xcart(x_start) # print(st1.get_elements()[i_m]) # sys.exit() if i_atom_to_move: nn = str(i_atom_to_move + 1) else: nn = str(i_void_start) name_suffix += atom_to_insert + nn write_xyz(st1, file_name=st.name + '_manually_start') printlog('Start position is created manually by adding xr_start', xr_start, x_start) type_atom_to_move = atom_to_insert el_num_suffix = '' else: atoms_to_move = [] atoms_to_move_types = [] # print('d', i_atom_to_move) # sys.exit() if i_atom_to_move: typ = st.get_elements()[i_atom_to_move] printlog('add_neb(): atom', typ, 'will be moved', imp='y') atoms_to_move.append( [i_atom_to_move, typ, st.xcart[i_atom_to_move]]) atoms_to_move_types.append(typ) if naming_conventions209: name_suffix += typ + str(i_atom_to_move + 1) else: #try to find automatically among alkali - special case for batteries for i, typ, x in zip(range(st.natom), st.get_elements(), st.xcart): if typ in ['Li', 'Na', 'K', 'Rb', 'Mg']: atoms_to_move.append([i, typ, x]) if typ not in atoms_to_move_types: atoms_to_move_types.append(typ) if atoms_to_move: # print(atom_to_move) # sys.exit() if not atom_to_move: atom_to_move = atoms_to_move_types[ 0] # taking first found element if len(atoms_to_move_types) > 1: printlog( 'Error! More than one type of atoms available for moving detected', atoms_to_move_types, 'please specify needed atom with *atom_to_move*') type_atom_to_move = atom_to_move #atoms_to_move[0][1] # printlog('atom ', type_atom_to_move, 'will be moved', imp ='y') if i_atom_to_move: printlog('add_neb(): *i_atom_to_move* = ', i_atom_to_move, 'is used', imp='y') numbers = [[i_atom_to_move]] i_void_start = 1 else: printlog('add_neb(): determine_symmetry_positions ...', imp='y') numbers = determine_symmetry_positions(st, atom_to_move) # print(numbers) # sys.exit() if len(numbers) > 0: printlog('Please choose position using *i_void_start* :', [i + 1 for i in range(len(numbers))], imp='y') printlog('*i_void_start* = ', i_void_start) i_m = numbers[i_void_start - 1][0] printlog('Position', i_void_start, 'chosen, atom:', i_m + 1, type_atom_to_move, imp='y') else: i_m = numbers[0][0] x_m = st.xcart[i_m] el_num_suffix = type_atom_to_move + str(i_m + 1) atom_to_insert = atom_to_move st1 = st # elif atom_to_replace: # num = st.get_specific_elements(atom_to_replace) # if len(n)>0: # printlog('Please choose position using *i_void_start* :', [i+1 for i in range(len(num))],imp = 'y' ) # printlog('*i_void_start* = ', i_void_start) # i_m = num[i_void_start-1] # printlog('Position',i_void_start,'chosen, atom to replace:', i_m+1, atom_to_replace, imp = 'y' ) # sys.exit() else: print_and_log( 'No atoms to move found, you probably gave me deintercalated structure', important='y') st_pores, sums, avds = determine_voids(st, r_impurity, step_dec=0.1, fine=2) insert_positions = determine_unique_voids(st_pores, sums, avds) print_and_log( 'Please use *i_void_start* to choose the void for atom insertion from the Table above:', end='\n', imp='Y') if i_void_start == None: sys.exit() if atom_to_insert == None: printlog('Error! atom_to_insert = None') st = st.add_atoms([ insert_positions[i_void_start], ], atom_to_insert) name_suffix += 'i' + str(i_void_start) i_m = st.natom - 1 x_m = st.xcart[i_m] search_type = 'existing_voids' type_atom_to_move = atom_to_insert el_num_suffix = '' st1 = st """2. Choose final position""" if is_list_like(xr_final): x_final = xred2xcart([xr_final], st.rprimd)[0] #old #check if i_atom_to_move should be removed # st2 = st1.del_atom(i_m) # st2 = st2.add_atoms([x_final], atom_to_insert) #new st2 = st1.mov_atoms(i_m, x_final) # st1.printme() # st2.printme() # sys.exit() x_del = x_final search_type = 'manual_insertion' name_suffix += 'v' + str(i_void_final) write_xyz(st2, file_name=st.name + '_manually_final') printlog('Final position is created manually by adding xr_final', xr_final, x_del) elif search_type == 'existing_voids': #Search for voids around choosen atoms if not st_pores: st_pores, sums, avds = determine_voids(st, r_impurity) sur = determine_unique_final(st_pores, sums, avds, x_m) print_and_log('Please choose *i_void_final* from the Table above:', end='\n', imp='Y') if i_void_final == None: sys.exit() x_final = sur[0][i_void_final] # printlog('You chose:', np.array(x_final).round(2), end='\n', imp='Y') x_del = x_final #please compare with vacancy creation mode write_xyz(st.add_atoms([x_final], 'H'), replications=(2, 2, 2), file_name=st.name + '_possible_positions2_replicated') print_and_log('Choosing the closest position as end', important='n') st1 = st st2 = st.mov_atoms(i_m, x_final) name_suffix += el_num_suffix + 'e' + str( i_void_final) + atom_to_insert st1 = return_atoms_to_cell(st1) st2 = return_atoms_to_cell(st2) write_xyz(st1, file_name=st1.name + name_suffix + '_start') write_xyz(st2, file_name=st2.name + name_suffix + '_final') elif search_type == 'vacancy_creation': #Create vacancy by removing some neibouring atom of the same type print_and_log( 'You have chosen vacancy_creation mode of add_neb tool', imp='Y') print_and_log('Type of atom to move = ', type_atom_to_move, imp='y') # print 'List of left atoms = ', np.array(st.leave_only(type_atom_to_move).xcart) sur = local_surrounding(x_m, st, n_neighbours=12, control='atoms', only_elements=[invert(type_atom_to_move)] + end_pos_types_z, periodic=True) #exclude the atom itself # print(x_m) # print(sur) # st.nn() print_and_log( 'I can suggest you ' + str(len(sur[0][1:])) + ' end positions. The distances to them are : ', np.round(sur[3][1:], 2), ' A\n ', 'They are ', type_atom_to_move, [invert(z) for z in end_pos_types_z], 'atoms, use *i_void_final* to choose required: 1, 2, 3 ..', imp='y') if not i_void_final: i_void_final = 1 #since zero is itself print_and_log('Choosing position ', i_void_final, 'with distance', round(sur[3][i_void_final], 2), 'A', imp='y') name_suffix += el_num_suffix + 'v' + str(i_void_final) x_del = sur[0][i_void_final] printlog('xcart of atom to delete', x_del) i_del = st.find_atom_num_by_xcart(x_del) # print(x_del) # print(st.xcart) # for x in st.xcart: # if x[0] > 10: # print(x) print_and_log('number of atom to delete = ', i_del, imp='y') if i_del == None: printlog('add_neb(): Error! I could find atom to delete!') # print st.magmom # print st1.magmom # try: if is_list_like(xr_start): st2 = st1.mov_atoms( i_m, x_del) # i_m and sur[0][neb_config] should coincide # i_del = st1.find_atom_num_by_xcart(x_del) st1 = st1.del_atom(i_del) else: print_and_log( 'Making vacancy at end position for starting configuration', imp='y') st1 = st.del_atom(i_del) print_and_log( 'Making vacancy at start position for final configuration', important='n') st2 = st.mov_atoms( i_m, x_del) # i_m and sur[0][neb_config] should coincide # except: # st2 = st st2 = st2.del_atom(i_del) # these two steps provide the same order """Checking correctness of path""" #if start and final positions are used, collisions with existing atoms are possible if is_list_like(xr_start) and is_list_like(xr_final): printlog('Checking correctness') st1, _, _ = st1.remove_close_lying() stt = st1.add_atoms([ x_final, ], 'Pu') stt, x, _ = stt.remove_close_lying( rm_both=True ) # now the final position is empty for sure; however the order can be spoiled # print(st._removed) if stt._removed: st1 = stt # only if overlapping was found we assign new structure st2, _, _ = st2.remove_close_lying(rm_first=stt._removed) stt = st2.add_atoms([ x_start, ], 'Pu') stt, x, _ = stt.remove_close_lying( rm_both=True) # now the start position is empty for sure if stt._removed: st2 = stt print(st2.get_elements()) # sys.exit() elif is_list_like(xr_final) and not is_list_like(xr_start) or is_list_like( xr_start) and not is_list_like(xr_final): printlog( 'Attention! only start of final position is provided, please check that everything is ok with start and final states!!!' ) """ Determining magnetic moments """ vp = varset[ise_new].vasp_params if search_type != None: #for None not implemented; x_m should be determined first for this if 'ISPIN' in vp and vp['ISPIN'] == 2: print_and_log( 'Magnetic calculation detected. Preparing spin modifications ...', imp='y') cl_test = CalculationVasp(varset[ise_new]) cl_test.init = st1 # print 'asdfsdfasdfsadfsadf', st1.magmom if inherit_magmom and hasattr(st, 'magmom') and st.magmom and any( st.magmom): print_and_log( 'inherit_magmom=True: You have chosen MAGMOM from provided structure', imp='y') name_suffix += 'mp' #Magmom from Previous else: cl_test.init.magmom = None print_and_log( 'inherit_magmom=False or no magmom in input structure : MAGMOM will be determined from set', imp='y') name_suffix += 'ms' #Magmom from Set cl_test.actualize_set() #find magmom for current structure st1.magmom = copy.deepcopy(cl_test.init.magmom) st2.magmom = copy.deepcopy(cl_test.init.magmom) # sys.exit() # print_and_log('The magnetic moments from set:') # print cl_test.init.magmom #checking for closest atoms now only for Fe, Mn, Ni, Co sur = local_surrounding(x_m, st1, n_neighbours=3, control='atoms', periodic=True, only_elements=header.TRANSITION_ELEMENTS) dist = np.array(sur[3]).round(2) numb = np.array(sur[2]) a = zip(numb, dist) # a= np.array(a) # print a[1] # a = np.apply_along_axis(np.unique, 1, a) # print a def unique_by_key(elements, key=None): if key is None: # no key: the whole element must be unique key = lambda e: e return list({key(el): el for el in elements}.values()) # print a mag_atoms_dists = unique_by_key(a, key=itemgetter(1)) # print (mag_atoms_dists) # a = unique_by_key(a, key=itemgetter(1)) print_and_log( 'I change spin for the following atoms:\ni atom dist\n', np.round(mag_atoms_dists, 2), imp='y') # print 'I have found closest Fe atoms' muls = [(1.2, 0.6), (0.6, 1.2)] mag_moments_variants = [] for mm in muls: mags = copy.deepcopy(cl_test.init.magmom) # print mags for a, m in zip(mag_atoms_dists, mm): # print t[1] mags[a[0]] = mags[a[0]] * m mag_moments_variants.append(mags) print_and_log('The list of possible mag_moments:', imp='y') for i, mag in enumerate(mag_moments_variants): print_and_log(i, mag) print_and_log( 'Please use *mag_config* arg to choose desired config', imp='y') if mag_config != None: st1.magmom = copy.deepcopy(mag_moments_variants[mag_config]) st2.magmom = copy.deepcopy(mag_moments_variants[mag_config]) name_suffix += 'm' + str(mag_config) print_and_log('You have chosen mag configuration #', mag_config, imp='y') else: print_and_log('Non-magnetic calculation continue ...') """3. Add to struct_des, create geo files, check set, add_loop """ if starting_calc: it = starting_calc.id[0] it_new = it + 'v' + str(starting_calc.id[2]) + '.' + name_suffix if not it_new_folder: it_new_folder = struct_des[it].sfolder + '/neb/' obtained_from = str(starting_calc.id) if not ise_new: print_and_log('I will run add_loop() using the same set', important='Y') ise_new = cl.id[1] elif st: if not it_new: printlog( 'Error! please provide *it_new* - name for your calculation', important='Y') it = None it_new += '.' + name_suffix obtained_from = st.name if not ise_new: printlog('Error! please provide *ise_new*', important='Y') if not it_new_folder: printlog( 'Error! please provide *it_new_folder* - folder for your new calculation', important='Y') if rep_moving_atom: it_new += 'r' + rep_moving_atom if it_new not in struct_des: add_des(struct_des, it_new, it_new_folder, 'Automatically created and added from ' + obtained_from) print_and_log( 'Creating geo files for starting and final configurations (versions 1 and 2) ', important='y') # if starting_calc: # cl = copy.deepcopy(starting_calc) # else: cl = CalculationVasp() #write start position struct_des[it_new].x_m_ion_start = x_m struct_des[it_new].xr_m_ion_start = xcart2xred([x_m], st1.rprimd)[0] # st1, _, _ = st1.remove_close_lying() # st2, _, _ = st2.remove_close_lying() i1 = st1.find_atom_num_by_xcart(x_m, prec=0.3) i2 = st2.find_atom_num_by_xcart(x_del, prec=0.3) if rep_moving_atom: #replace the moving atom by required st1 = st1.replace_atoms([i1], rep_moving_atom) st2 = st2.replace_atoms([i2], rep_moving_atom) else: #allows to make correct order for nebmake.pl st1 = st1.replace_atoms([i1], type_atom_to_move) st2 = st2.replace_atoms([i2], type_atom_to_move) i1 = st1.find_atom_num_by_xcart(x_m, prec=0.3) # the positions were changed i2 = st2.find_atom_num_by_xcart(x_del, prec=0.3) cl.end = st1 ver_new = 1 cl.version = ver_new cl.path["input_geo"] = header.geo_folder + struct_des[it_new].sfolder + '/' + \ it_new+"/"+it_new+'.auto_created_starting_position_for_neb_'+str(search_type)+'.'+str(ver_new)+'.'+'geo' cl.write_siman_geo(geotype='end', description='Starting conf. for neb from ' + obtained_from, override=True) #write final position struct_des[it_new].x_m_ion_final = x_del struct_des[it_new].xr_m_ion_final = xcart2xred([x_del], st2.rprimd)[0] cl.end = st2 ver_new = 2 cl.version = ver_new cl.path["input_geo"] = header.geo_folder + struct_des[it_new].sfolder + '/' + \ it_new+"/"+it_new+'.auto_created_final_position_for_neb_'+str(search_type)+'.'+str(ver_new)+'.'+'geo' cl.write_siman_geo(geotype='end', description='Final conf. for neb from ' + obtained_from, override=True) if not rep_moving_atom: st1s = st1.replace_atoms([i1], 'Pu') st2s = st2.replace_atoms([i2], 'Pu') else: st1s = copy.deepcopy(st1) st2s = copy.deepcopy(st2) vec = st1.center_on(i1) st1s = st1s.shift_atoms(vec) st2s = st2s.shift_atoms(vec) write_xyz(st1s, file_name=it_new + '_start') write_xyz(st2s, file_name=it_new + '_end') st1s.write_poscar('xyz/POSCAR1') st2s.write_poscar('xyz/POSCAR2') # print(a) # runBash('cd xyz; mkdir '+it_new+'_all;'+"""for i in {00..04}; do cp $i/POSCAR """+ it_new+'_all/POSCAR$i; done; rm -r 00 01 02 03 04') with cd('xyz'): a = runBash(header.PATH2NEBMAKE + ' POSCAR1 POSCAR2 3') dst = it_new + '_all' makedir(dst + '/any') for f in ['00', '01', '02', '03', '04']: shutil.move(f + '/POSCAR', dst + '/POSCAR' + f) shutil.rmtree(f) #prepare calculations # sys.exit() #Check if nebmake is avail # if int(runBash('ssh '+cluster_address+' test -e '+project_path_cluster+'/tools/vts/nebmake.pl; echo $?') ): # '' # print_and_log('Please upload vtsttools to ',cluster_address, project_path_cluster+'/tools/vts/') # raise RuntimeError # copy_to_server(path_to_wrapper+'/vtstscripts/nebmake.pl', to = project_path_cluster+'/tools/', addr = cluster_address) # if int(runBash('ssh '+cluster_address+' test -e '+project_path_cluster+'/tools/Vasp.pm; echo $?') ): # copy_to_server(path_to_wrapper+'/vtstscripts/Vasp.pm', to = project_path_cluster+'/tools/', addr = cluster_address) inherit_ngkpt(it_new, it, varset[ise_new]) add_loop(it_new, ise_new, verlist=[1, 2], up=up, calc_method=calc_method, savefile='oc', inherit_option=inherit_option, n_neb_images=images, corenum=corenum, run=run, **add_loop_dic) if upload_vts: siman_dir = os.path.dirname(__file__) # print(upload_vts) push_to_server([ siman_dir + '/cluster_tools/nebmake.pl', siman_dir + '/cluster_tools/Vasp.pm' ], to=header.cluster_home + '/tools/vts', addr=header.cluster_address) else: print_and_log('Please be sure that vtsttools are at', header.cluster_address, header.cluster_home + '/tools/vts/', imp='Y') printlog('add_neb finished') return it_new
def insert(it_ins, ise_ins, mat_path, it_new, calc, type_of_insertion = "xcart" ): """For insertion of atoms to cells with changed lateral sizes Input: 'type_of_insertion = xred' used to add xred coordinates mat_path - path to geo files which are supposed to be changed it_ins - already existed calculation; xred will be used from this calculation. it_new - new folder in geo folder for obtained structure This function finds version of calculation in folder mat_path and tries to use the same version of it_ins """ if not os.path.exists(mat_path): print_and_log("Error! Path "+mat_path+" does not exist\n\n") raise RuntimeError if it_ins not in mat_path and it_ins not in it_new: print_and_log('Cells are', it_ins, mat_path, it_new) print_and_log("Error! you are trying to insert coordinates from cell with different name\n\n") #raise RuntimeError hstring = ("%s #on %s"% (traceback.extract_stack(None, 2)[0][3], datetime.date.today() ) ) if hstring != header.history[-1]: header.history.append( hstring ) geofilelist = runBash('find '+mat_path+'/target -name "*.geo*" ').splitlines() if geofilelist == []: print_and_log("Warning! Target folder is empty. Trying to find in root folder ...") geofilelist = runBash('find '+mat_path+'/ -name "*.geo*" ').splitlines() ins = None for mat_geofile in geofilelist: mat = CalculationVasp() mat.name = mat_geofile mat.read_geometry(mat_geofile) #step = 0.27 #r_pore = 0.56 #r_mat = mat.hex_a / 2 - step #pores = find_pores(mat.init, r_mat, r_pore, step, 0.3, 'central') #octahedral #mat.xcart.append ( pores.xcart[0] ) #mat.typat.append(1) try: ins_working = ins ins = calc[(it_ins, ise_ins, mat.version)] except KeyError: print_and_log( "No key", (it_ins, ise_ins, mat.version), "I use previous working version !!!", imp = 'y' ) ins = ins_working #return #ins.end.znucl = ins.znucl #ins.end.nznucl = ins.nznucl #ins.end.ntypat = ins.ntypat #ins.end.typat = ins.typat #print ins.xcart[-1] mat_geopath = geo_folder+struct_des[it_new].sfolder + '/' if type_of_insertion == "xcart": #Please update here! mat_filename = '/'+it_new+"."+"inserted."+str(mat.version)+'.'+'geo' v = np.zeros(3) result = insert_cluster(ins.end, v, mat.init, v ) mat.end = result mat.init = result # mat.znucl = mat.end.znucl # mat.nznucl = mat.end.nznucl # mat.ntypat = mat.end.ntypat # mat.typat = mat.end.typat # mat.natom = len(mat.end.xred) #mat.version = ins.version des = ins.name+" was inserted to "+mat_geofile elif type_of_insertion == "xred": mat_filename = '/from/'+it_new+".xred."+str(mat.version)+'.'+'geo' #mat.end.rprimd = mat.rprimd #mat.init.xred = copy.deepcopy(ins.end.xred) #mat.init.typat = copy.deepcopy(ins.end.) #print ins.end.xcart rprimd = copy.deepcopy(mat.init.rprimd) #build = mat.build mat.init = copy.deepcopy(ins.end) #mat.build = build mat.init.rprimd = rprimd #return initial rprimd mat.init.xcart = xred2xcart(mat.init.xred, mat.init.rprimd) #calculate xcart with new rprimd des = "atoms with reduced coord. from "+ins.name+" was fully copied to "+mat_geofile mat.init.name = 'test_insert_xred'+str(mat.version) write_xyz(mat.init) mat.path["input_geo"] = mat_geopath + it_new + mat_filename if not mat.write_geometry("init",des): continue print_and_log("Xred from "+it_ins+" was inserted in "+mat_geofile+" and saved as "+mat_filename+" \n\n") return
def 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.xcart = xred2xcart(st.xred, st.rprimd) new.init = st #print "Add impurity: len(xred ", len(new.init.xred) #print "natom", new.init.natom #For automatisation of fit try: #new.build if new.build.nadded == None: new.build.nadded=npores else: new.build.nadded+=npores if new.build.listadded == [None]: new.build.listadded = range(new.natom - npores, new.natom) #list of atoms which were added else: new.build.listadded.extend( range(new.natom - npores, new.natom) ) #print "Warning!!! Information about added impurities rewritten" except AttributeError: pass #new.init.znucl = new.znucl #new.init.typat = new.typat #write_xyz(replic(new.init, (2,1,2)) , xyzpath) #test_adding_of_impurities(new, new_before, v) print_and_log("Impurity with Z="+str(znucl)+" has been added to the found pore in "+new.name+"\n\n") if write_geo: write_xyz(new.init , xyzpath) new.write_geometry("init",new.des, override = override) print_and_log( "\n") return new
def find_pores(st_in, r_matrix=1.4, r_impurity = 0.6, step_dec = 0.05, fine = 0.3, prec = 0.1, calctype = 'central', gbpos = 0, find_close_to = (), check_pore_vol = 0): """ st_in - input Structure() object r_impurity (A)- all pores smaller than this radius will be found r_matrix (A) - radius of matrix atoms disregarding to their type step_dec - scanning step of the cell in Angstroms fine - allows to change density of local points; local_step = step_dec/fine prec - precicion of pore center determination check_pore_vol - allows to estimate volume of pores; has problems for big cells 'find_close_to' - works in the cases of gb and grain_vol; allows to ignore all and find pore close to provided three reduced coordinates return - instance of Structure() class with coordinates of pores. Number and type of included pores depend on the argument of 'calctype'. """ xred = st_in.xred natom = len(xred) rprimd = st_in.rprimd name = st_in.name #print xred """Additional values""" # check_pore_vol = 1 #if calctype in ("pore_vol","gb","grain_vol","all_local" ): check_pore_vol = 1 #something wrong with this function, especially for big cells """----Conversions of types for C++""" r1 = create_c_array(rprimd[0], float) r2 = create_c_array(rprimd[1], float) r3 = create_c_array(rprimd[2], float) xred1 = (c_float * len(xred))(*[x[0] for x in xred]) xred2 = (c_float * len(xred))(*[x[1] for x in xred]) xred3 = (c_float * len(xred))(*[x[2] for x in xred]) max_npores = 10000; ntot = ctypes.c_int32(); npores = ctypes.c_int32() l_pxred1 = (c_float * max_npores)(0) #make static arrays fol local points l_pxred2 = (c_float * max_npores)(0) l_pxred3 = (c_float * max_npores)(0) l_npores = (ctypes.c_int32 * max_npores)(0) pxred1 = (c_float * max_npores)(0) #make static arrays natoms + npore pxred2 = (c_float * max_npores)(0) pxred3 = (c_float * max_npores)(0) """----Run C++ function""" print_and_log("Starting C++ function lib.findpores()...\n") lib.findpores ( check_pore_vol, \ max_npores, \ byref(ntot), l_pxred1, l_pxred2, l_pxred3, l_npores, \ byref(npores), pxred1, pxred2, pxred3, \ natom, xred1, xred2, xred3, \ c_float(r_matrix), c_float(r_impurity), c_float(step_dec), c_float(fine), c_float(prec), \ r1, r2, r3 ) print_and_log( "ntot is ", ntot.value) print_and_log( "l_npores[0] is ",l_npores[0]) v = np.zeros((3)) l_pxred = [] shift1 = 0; shift2 = 0 for i_por in range(npores.value): l_pxred.append( [] ) shift2+=l_npores[i_por] for i in range(shift1, shift2): v[0] = l_pxred1[i]; v[1] = l_pxred2[i]; v[2] = l_pxred3[i] l_pxred[i_por].append( v.copy() ) shift1 = shift2 if shift2 != ntot.value: print_and_log( "Error! final shift2 not equal to ntot") #print l_pxred[0] pxred = [] # only coordinates of pores #print pxred1[natom] for i in range(npores.value): v[0] = pxred1[i+natom]; v[1]= pxred2[i+natom]; v[2] = pxred3[i+natom] #with shift, because first natom elements are coordinates of atoms pxred.append( v.copy() ) #print pxred """----End of C++; result is two lists: lpxred - local geometry of all pores, pxred - coordinates of all pores""" """ Analyse of pores """ st_result = Structure() st_result.rprimd = rprimd targetp = np.array((0.,0.,0.)) if find_close_to: targetp = np.asarray(find_close_to) #targer point print_and_log( "Target point is ",targetp) a = step_dec/fine #the side of little cube formed by the mesh which is used to find spheres inside the pore. aaa = a*a*a #find most central pore if calctype == 'central': #return coordinates of the most central pore st_result.name = "central_pore_from "+name center = np.array((0.5,0.5,0.5))#center of cell d_min = 100 for x in pxred: d = np.linalg.norm(x - center) #print x, x-center, d if d < d_min and x[0] <= 0.5 and x[1] <= 0.5 and x[2] <= 0.5: d_min = d x_min = x print_and_log( "The closest pore to the center has coordinates",x_min) st_result.xred.append( x_min ) elif calctype == 'gb': #add impurity at gb st_result.name = "gb_pore_from "+name d_min = 100; #d2_min = 100 dt_min =100 i_min = 0; x_min = np.zeros((3)) for i, x in enumerate(pxred): #print "l_npores ",l_npores[i] d = abs(x[0] - gbpos/rprimd[0][0]) # #print x[0], d if find_close_to: closer = (np.linalg.norm(targetp - x) < dt_min) else: closer = ( d < d_min ) # and x[1]>0.3 and x[2]>0.3: if closer: x_pre = x_min i_pre = i_min d_min = d dt_min = np.linalg.norm(targetp - x) x_min = x i_min = i #find and add impurity in bulk #d2 = abs( x[0] - (gbpos/rprimd[0][0] - 0.25) ) #if d2 < d2_min: # d2_min = d2 # x2_min = x # i2_min = i #print "rprimd[0][0]", rprimd[0][0] print_and_log( "Position of boundary is ",gbpos/rprimd[0][0]) #x_min[0] = gbpos/rprimd[0][0] if find_close_to: print_and_log( "The closest pore to the target point is [ %.2f %.2f %.2f ]"%(x_min[0], x_min[1], x_min[2])) else: print_and_log( "The closest pore to the gb has coordinates",x_min) st_result.xred.append( x_min ) #st_result.xred.append( x_pre ) #Calculate volume of the pore using local balls: print_and_log( "The number of pore is ",i_min," ; It has ",l_npores[i_min], "local balls") print_and_log( "Volume of pore is ", l_npores[i_min] * a*a*a, " A^3") #st_result.xred.extend( l_pxred[i_min] ) #st_result.xred.extend( l_pxred[i_pre] ) #print "The closest pore to the center of bulk has coordinates",x2_min #st_result.xred.append( x2_min ) #Calculate volume of the pore using local balls: #print "The number of bulk pore is ",i2_min," ; It has ",l_npores[i2_min], "local balls" #print "Volume of pore is ", l_npores[i2_min] * a*a*a, " A^3"; #st_result.xred.extend( l_pxred[i2_min] ) elif calctype == 'grain_vol': #add impurity to volume of grain st_result.name = "grain_volume_pore_from "+name d2_min = 100 dt_min = 100 i_min = 0; x_min = np.zeros((3)) for i, x in enumerate(pxred): #find and add impurity to the bulk d2 = abs( x[0] - (gbpos/rprimd[0][0] - 0.25) ) if find_close_to: closer = (np.linalg.norm(targetp - x) < dt_min) else: closer = ( d2 < d2_min ) # and x[1]>0.3 and x[2]>0.3: if closer: dt_min = np.linalg.norm(targetp - x) d2_min = d2 x2_min = x i2_min = i if find_close_to: print_and_log( "The closest pore to the target point is [ %.2f %.2f %.2f ]"%(x2_min[0], x2_min[1], x2_min[2])) else: print_and_log( "The closest pore to the center of bulk has coordinates",x2_min) st_result.xred.append( x2_min ) #Calculate volume of the pore using local balls: print_and_log( "The number of bulk pore is ",i2_min," ; It has ",l_npores[i2_min], "local balls") print_and_log( "Volume of pore is ", l_npores[i2_min] * a*a*a, " A^3") st_result.xred.extend( l_pxred[i2_min] ) elif calctype == 'all_local': st_result.name = "all_local_points_from "+name v_max = 0 i_max = 0 for i in range(npores.value): v_pore = l_npores[i] * aaa print_and_log( "Volume of pore is ", l_npores[i] * aaa, " A^3") if v_pore > v_max: v_max = v_pore; i_max = i print_and_log( "Pore number ", i_max,"has the largest volume ", v_max," A^3") # st_result.xred = l_pxred[i_max] # here coordinates of all local points to show geometry of pore with largerst volume st_result.xred = [x for group in l_pxred for x in group ] # all pores elif calctype == 'all_pores': st_result.name = "all_local_pores_from "+name st_result.xred = pxred st_result.xcart = xred2xcart(st_result.xred, rprimd) st_result.typat = [1 for x in st_result.xred] st_result.natom = len(st_result.typat) st_result.znucl = [200] st_ntypat = 1 return st_result
def write_lammps(st, filename = '', charges = None): """Writes structure in lammps format charges (list of float) - list of charges for each atom type """ rprimd = st.rprimd xcart = st.xcart xred = st.xred typat = st.typat ntypat = st.ntypat znucl = st.znucl name = st.name natom = st.natom if natom != len(xred) != len(xcart) != len(typat) or len(znucl) != max(typat): print_and_log( "Error! write_xyz: check your structure" ) if name == '': name = 'noname' if xcart == [] or len(xcart) != len(xred): print_and_log( "Warining! write_xyz: len(xcart) != len(xred) making xcart from xred.\n", imp = 'y') xcart = xred2xcart(xred, rprimd) #print xcart[1] if not filename: filename = 'lammps/'+name filename+='.inp' makedir(filename) """Write lammps structure file; """ if 1: """ My version; valid only for octahedral cells""" printlog( "Warining! write_lammps(): this func supports only orthogonal cells", imp = 'Y') with open(filename+'','w') as f: f.write("Lammps format "+name+'\n') f.write(str(natom)+" atoms\n") f.write(str(ntypat)+" atom types\n") f.write("{:10.8f} {:10.8f} xlo xhi\n".format(0, rprimd[0][0])) f.write("{:10.8f} {:10.8f} ylo yhi\n".format(0, rprimd[1][1])) f.write("{:10.8f} {:10.8f} zlo zhi\n".format(0, rprimd[2][2])) f.write("0.00000000 0.00000000 0.00000000 xy xz yz\n") f.write("\nAtoms\n\n") for i, x in enumerate(xcart): f.write("{0:8d} {1:2d}".format(i+1, typat[i])) if charges: f.write(" {:6.3f}".format(charges[typat[i]-1] ) ) f.write(" {:12.6f} {:12.6f} {:12.6f}\n".format(x[0], x[1], x[2] )) f.write("\n") printlog('File', filename, 'was written', imp = 'y') else: """Write poscar and convert from poscar to lammps using external script; Valid for arbitary cells""" cl.write_structure('POSCAR', 'dir', path = 'voronoi_analysis/', state = state) runBash("voronoi_analysis/VASP-poscar2lammps.awk voronoi_analysis/POSCAR > "+filepath) if 0: """Write lammps.in file """ with open('voronoi_analysis/voronoi.in','w') as f: f.write("""units metal atom_style atomic boundary p p p\n""") f.write("read_data /home/aksenov/programs/Simulation_wrapper/siman1/voronoi_analysis/structure.lammps\n") # f.write('lattice custom 1 ') # for i, a in enumerate(rprimd): # f.write(' a'+str(i+1)) # for x in a: # f.write(' '+str(x)) # f.write(' &\n') # for x in xred: # f.write(' basis {0:f} {1:f} {2:f}&\n '.format(x[0], x[1], x[2]) ) # f.write("""\n # region 1 prism 0 1 0 1 0 1 1 0 0 # create_box 1 prism # create_atoms 1 prism""") for i in range(ntypat): f.write('\nmass '+str(i+1)+' '+str(int(znucl[i]))+'\n') f.write('pair_style lj/cut 2.0\n') for i in range(ntypat): for j in range(i, ntypat): f.write('pair_coeff '+str(i+1)+' '+str(j+1)+' 0.0 1.0\n') f.write("""compute v1 all voronoi/atom dump d1 all custom 1 /home/aksenov/programs/Simulation_wrapper/siman1/voronoi_analysis/dump.voro id type x y z c_v1[1] c_v1[2] run 0 uncompute v1\n""") return
def write_xyz(st, path = None, repeat = 1, shift = 1.0, gbpos2 = None, gbwidth = 1 , imp_positions = [], specialcommand = None, analysis = None, show_around = None, replications = None, nnumber = 6, topview = True, filename = None, file_name = None, full_cell = False, orientation = None, boundbox = 2, withgb = False, include_boundary = 2, rotate = None, imp_sub_positions = None, jmol = None, show_around_x = None, ): """Writes st structure in xyz format in the folder xyz/path if repeat == 2: produces jmol script shift - in rprimd[1][1] - shift of the second view gbpos2 - position of grain boundary in A gbwidth - atoms aroung gbpos2 will be colored differently imp_positions - type and xcart coordinates additionally to be added to structure; to visulaze all impurity positions: for jmol imp_sub_positions - list of atom numbers; the typat of these atoms is changed: not used now specialcommand - any command at the end of script analysis - additional processing, allows to show only specifice atoms, 'imp_surrounding' - shows Ti atoms only around impurity nnumber - number of neighbours to show show_around - choose atom number around which to show show_around_x - show atoms around point, has higher priority replications - list of replications, (2,2,2) full_cell - returns atoms to cell and replicate boundary atoms jmol - 1,0 - allow to use jmol """ if replications: st = replic(st, mul = replications, inv = 1 ) def update_var(): return st.rprimd, st.xcart, st.xred, st.typat, st.znucl, len(st.xred) rprimd, xcart, xred, typat, znucl, natom = update_var() if file_name: name = file_name elif filename: name = filename else: name = st.name if natom != len(xred) != len(xcart) != len(typat) or len(znucl) != max(typat): print_and_log( "Error! write_xyz: check your arrays.\n\n" ) # print st.natom, len(st.xred), len(st.xcart), len(st.typat), len(st.znucl), max(st.typat) print_and_log("write_xyz(): Name is", name, important = 'n') if name == '': name = 'noname' if xcart == [] or len(xcart) != len(xred): print_and_log( "Warining! write_xyz: len(xcart) != len(xred) making xcart from xred.\n") xcart = xred2xcart(xred, rprimd) #print xcart[1] if path: basepath = path else: basepath = 'xyz/' xyzfile = os.path.join(basepath, name+".xyz") makedir(xyzfile) """Processing section""" if analysis == 'imp_surrounding': lxcart = [] ltypat = [] i=0 for t, x in zip(typat, xcart): condition = False # print show_around, 'show' if show_around: # print i, condition condition = (i + 1 == show_around) # print i, condition else: condition = (t > 1) # compat with prev behav # print 'se', condition if condition: # lxcart.append(x) # ltypat.append(t) # print x, ' x' x_t = local_surrounding(x, st, nnumber, control = 'atoms', periodic = True) # print x_t[1] lxcart+=x_t[0] ltypat+=x_t[1] i+=1 if show_around_x: x = show_around_x x_t = local_surrounding(x, st, nnumber, control = 'atoms', periodic = True) # print x_t[1] lxcart+=x_t[0] ltypat+=x_t[1] xcart = lxcart typat = ltypat natom = len(typat) # print natom, 'nat' """Include atoms on the edge of cell""" if full_cell: # print xred # print natom # st = return_atoms_to_cell(st) # print xred st = replic(st, mul = (1,1,2), inv = 0, cut_one_cell = 1, include_boundary = include_boundary) # print natom, st.natom # print st.xred rprimd, xcart, xred, typat, znucl, natom = update_var() # asdegf """Writing section""" # print_and_log("Writing xyz: "+xyzfile, imp = 'y') #analyze imp_positions if imp_sub_positions == None: imp_sub_positions = [] nsub = 0 for pos in imp_positions: if 's' not in pos[4]: continue # skip interstitial positions xs = np.asarray([pos[0],pos[1],pos[2]]) nsub+=1 # print xs for i, x in enumerate(xcart): # print np.linalg.norm( x-xs) if np.linalg.norm( x-xs) < 1: imp_sub_positions.append(i) if imp_sub_positions : print_and_log( imp_sub_positions, ': numbers of found atoms to be changed ' ) # for i in sorted(indices, reverse=True): # del somelist[i] with open(xyzfile,'w') as f: for i in range(repeat): f.write(str(natom + len(imp_positions)-nsub + 3)+"\n") #+3 vectors f.write(name+"\n") if imp_positions: for i, el in enumerate(imp_positions): # if len(el) != 4: continue f.write( "%s %.5f %.5f %.5f \n"%( el[3], el[0], el[1], el[2] ) ) # print 'composite -pointsize 60 label:{0:d} -geometry +{1:d}+{2:d} 1.png 2.png'.format(i, el[0], el[1]) for i in range(natom): typ = typat[i] - 1 z = int ( znucl[ typ ] ) if i in imp_sub_positions: # f.write( "Be " ) continue else: el = element_name_inv(z) f.write( el+" " ) f.write( "%.5f %.5f %.5f \n"%( xcart[i][0], xcart[i][1], xcart[i][2] ) ) for r in st.rprimd: f.write('Tv {:.10f} {:.10f} {:.10f}\n'.format(*r) ) # os._exit(1) printlog('File', xyzfile, 'was written', imp = 'y') if jmol: """ script mode for jmol. Create script file as well for elobarate visualization """ """Choose gb atoms to change their color""" print_and_log( 'position of boundary 2', gbpos2) atomselection = '' #create consistent xcart_new list like it will be in Jmol xcart_new = [] for i, x in enumerate(xcart): if i in imp_sub_positions: continue xcart_new.append(x) if gbpos2: gbpos1 = gbpos2 - rprimd[0][0]/2. gbatoms = [] for i, x in enumerate(xcart_new): # print i # if x[0] > gbpos1 - gbwidth/2. and x[0] < gbpos1 + gbwidth/2.: if abs(x[0] - gbpos1) < gbwidth/2.: gbatoms.append(i) # print i, x[0], abs(x[0] - gbpos1) if abs(x[0] - gbpos2) < gbwidth/2.: # if x[0] > gbpos2 - gbwidth/2. and x[0] < gbpos2 + gbwidth/2.: # print i, x[0], abs(x[0] - gbpos2) gbatoms.append(i) print_and_log( 'Atoms at GB:', gbatoms) atomselection = '' for i in gbatoms: atomselection +='Ti'+str(i+1+len(imp_positions))+',' atomselection = atomselection[:-1] # elif withgb: # color half of cell # else: # color half of cell # # pass # atomselection = 'atomno>'+str(0+len(imp_positions) )+' and atomno<'+str(( natom + len(imp_positions) )/2-1) xyzfile = os.getcwd()+'/'+xyzfile scriptfile = basepath+name+".jmol" pngfile = os.getcwd()+'/'+basepath+name+".png" print_and_log( 'imp_positions = ',imp_positions) write_jmol(xyzfile, pngfile, scriptfile, atomselection, topview = topview, rprimd =rprimd, shift = shift, label = [(pos[3], pos[4]) for pos in imp_positions], specialcommand = specialcommand, orientation = orientation, boundbox =boundbox, rotate = rotate) return