def set_potential(self, znucl, arg=''): # print arg if not arg: arg = header.PATH2POTENTIALS + '/' + invert(znucl) printlog('Attention!, Default potentials is chosen from ', header.PATH2POTENTIALS, 'for', invert(znucl), imp='Y') if type(arg) not in (str, ): # sys.exit("\nset_potential error\n") raise RuntimeError if znucl in self.potdir: if arg == self.potdir[znucl]: print_and_log( "Warning! You already have the same potential for " + str(znucl) + " element\n") # print type(self.potdir) self.potdir[znucl] = arg self.history += "Potential for " + str( znucl) + " was changed to " + arg + "\n" print_and_log("Potential for " + str(znucl) + " was changed to " + arg + "\n") # self.update() return
def form_en(sources, products, norm_el=None): """ Calculate formation energy of reaction. sources, products - list of tuples (x, cl), where x is multiplier and cl is calculation norm_el - which element to use for normalization 'all' - normalize by total number of atoms 'el' - normalize by this element int - divide by this number """ El = [] Nzl = [] for ls in [sources, products]: E = 0 Nz = {} for x, cl in ls: E += x * cl.e0 for i, z in enumerate(cl.end.znucl): if z not in Nz: Nz[z] = 0 Nz[z] += x * cl.end.nznucl[i] El.append(E) Nzl.append(Nz) for z in Nzl[0]: if abs(Nzl[0][z] - Nzl[1][z]) > 1e-5: printlog('Error! Number of', invert(z), 'atoms in source and product are different!') # norm = 1 if 'all' == norm_el: norm = sum(Nzl[0].values()) elif type(norm_el) == str: norm = Nzl[0][invert(norm_el)] elif norm_el != None: norm = norm_el else: norm = 1 print('Normalizing by ', norm_el, norm, 'atoms') dE = (El[1] - El[0]) / norm print('dE = {:4.2f} eV'.format(dE)) return dE
def exchange_with_external(st, zr, thickness, external = None): """ external (dict) - {'Ni':['Li']} - atoms from external reservior which can replace existing elements, in this example Ni can replace Li """ printlog('Starting exchange with external') zr_range = get_zr_range(st, thickness, zr) # get external # print(external.keys()) el_ext = random.choice(list(external.keys())) # get element to change el_int = random.choice(external[el_ext]) nn1 = st.get_specific_elements([invert(el_int)], zr_range = zr_range) nn2 = st.get_specific_elements([invert(el_ext)], zr_range = zr_range) # just to know good TM-O distance j = random.choice(nn2) av2 = st.nn(j, 6, only = [8], from_one = 0, silent = 1)['av(A-O,F)'] # in slab if len(nn1) == 0: printlog('All atoms were replaced, exiting ', imp = 'y') sys.exit() for k in range(10): i = random.choice(nn1) av1 = st.nn(i, 6, only = [8], from_one = 0, silent = 1)['av(A-O,F)'] if av1 < av2+0.4: printlog('The chosen position is compared to the existing in slab for {:s}: {:.2f} {:.2f} A'.format(el_ext, av1, av2), imp = 'y') break else: printlog('Trying ', i) else: printlog('No more good options, trying all', imp = 'y') st_new = st.replace_atoms([i], el_ext) printlog('Atom', el_int, i, 'was replaced by ', el_ext, 'from external reservoir') return st_new
def chgsum(cll, el, site, silent=1): """ calculate sum of Bader charges for particular atoms """ for cl in cll: # print(cl.id, end = ' ') try: cl.chgsum[(el, site)] = 0 except: pass if not hasattr(cl, 'charges') or len(cl.charges) == 0: cl.get_bader_ACF() # determine_symmetry_positions(cl.end, el, silent = 0) # print('') try: pos = determine_symmetry_positions(cll[0].end, el, silent=1) except: printlog('chgsum() Warning!', cll[0].id, 'is broken!') return 0 for p in pos[site]: '' for cl in cll: if not hasattr(cl, 'chgsum'): cl.chgsum = {} cl.chgsum[(el, site)] = 0 cl.chgsum[(el, site)] += cl.charges[p] # print('{:5.3f}'.format(cl.charges[p]), end = ' ') # print('') if not silent: print('Sum of charges for ', el + str(site + 1), ':') el_ind = cl.init.znucl.index( invert(el)) # index of element in znucl and zval and nznucl zval = cl.init.zval[el_ind] # number of electrons in chosen potential for cl in cll: cl.chgsum[(el, site)] /= len(pos[site]) chgsum = zval - cl.chgsum[(el, site)] if cl == cll[0]: chgsum_ref = chgsum if not silent: print('{:5.2f}({:4.2f})'.format(chgsum, chgsum_ref - chgsum), ) if not silent: print('\n') # print(cl.charges) return chgsum
def find_polaron(st, i_alk_ion, out_prec=1): """ #using magmom, find the transition atoms that have different magnetic moments #i_alk_ion - number of ion from 0 to calculate distances to transition metals out_prec (int) - precision of magmom output # maglist = cli.end.get_maglist() # magm = np.array(cli.end.magmom) # n_tm = len(magm[maglist]) # # print(len(maglist)) # numb, dist, chosen_ion = around_alkali(cli.end, n_tm, atom_num) # # print(magm[numb][1:]) # mtm = magm[numb][1:] # the first is alkali # m_av = sum(mtm)/len(mtm) # print(mtm-m_av) """ def zscore(s): # print(np.std(s)) return (s - np.mean(s)) / np.std(s) magmom = np.array(st.magmom) if len(magmom) == 0: printlog('Warning! magmom is empty') _, mag_numbers = st.get_maglist() pol = {} # for z in mag_numbers: # pos = determine_symmetry_positions(st, invert(z)) # sys.exit() magmom_tm = None for key in mag_numbers: printlog('Looking at polarons on transition atoms: ', invert(key)) numbs = np.array(mag_numbers[key]) # print(numbs) # print(magmom) magmom_tm = magmom[numbs] dev = np.absolute(zscore(magmom_tm)) # print(magmom_tm) # print(list(zip(magmom_tm, dev.round(1)))) # p = np.where(dev>2)[0] # 2 standard deviations # print(dev>2) # print (type(numbs)) nstd = 1.5 # nstd = 4 i_pols = numbs[dev > nstd] if len(i_pols) > 0: x1 = st.xcart[i_alk_ion] d_to_pols = [] for j in i_pols: x2 = st.xcart[j] d, _ = st.image_distance(x1, x2, st.rprimd) d_to_pols.append(d) print( 'polarons are detected on atoms', [i + 1 for i in i_pols], 'with magnetic moments:', magmom[i_pols], 'and distances: ' + ', '.join('{:2.2f}'.format(d) for d in d_to_pols), 'A') print('mag moments on trans. atoms:', magmom_tm.round(out_prec)) pol[key] = i_pols else: print('no polarons is detected with nstd', nstd) print('mag moments on trans. atoms:', magmom_tm.round(out_prec)) # print(' deviations :', dev.round(1)) pol[key] = None return pol, magmom_tm
def create_segregation_cases(it, ise, verlist, dist_gb, gbpos=None, ise_new=None, option=None, precip_folder=None, use_init=False, precision=None): """ Written for Ti-Fe project. Allows to create segregation by substituting atoms; dist_gb - distance from gb inside which the atoms are included option = 'precip'- adding additional impurities to the already existing at gb. Please use 'precip_folder' use_init - allows to use initial structure. !Warning PBC are not used in determination of seg positions """ # hstring = ("%s #on %s"% (traceback.extract_stack(None, 2)[0][3], datetime.date.today() ) ) # try: # if hstring != header.history[-1]: header.history.append( hstring ) # except: # header.history.append( hstring ) def write_local(cl, it_new, it_new_path, el_sub, main_path): cl.version = v # it_new_path cl.name = it_new cl.des = 'Obtained from end state of ' + str( (it, ise, v) ) + ' by substitution of one atom near gb with ' + el_sub + ' impurity ' path_new_geo = it_new_path + "/" + it_new + "/" + it_new + '.imp.' + el_sub + '.' + str( cl.version) + '.' + 'geo' cl.init.name = it_new + ".init." + str(cl.version) xyzpath = it_new_path + "/" + it_new cl.path["input_geo"] = path_new_geo print(path_new_geo) cl.write_geometry("init", cl.des, override=1) write_xyz(cl.init, xyzpath) return it_new_path if 0: res_loop(it, ise, verlist, up=0) cl = header.calc[(it, ise, verlist[0])] znucl_sub = 3 #atom to be added """1. Create list of atoms near gb to substitue""" cl.gbpos = gbpos # print cl.gbpos seg_pos_list = [] # numbers of segregation positions if use_init: st = cl.init else: st = cl.end # print(st.xcart) if len(st.xcart) == 0: print( 'Warning!, xcart is empty', cl.id, ) for i, x in enumerate(st.xcart): z_cur = st.znucl[st.typat[i] - 1] print('z_cur', z_cur) if z_cur == znucl_sub: printlog('Skipping znucl_sub atom\n') continue if abs(x[0] - gbpos) < dist_gb: print('adding possible seg position') seg_pos_list.append(i) """2. Substitue""" el_sub = invert(znucl_sub) base_name = it main_path = header.struct_des[it].sfolder based_on = it + '.' + ise des_list = [] add_list = [] cl_list = [] sumr_list = [] i = 0 # print(seg_pos_list) for j, replace_atom in enumerate(seg_pos_list): # v = verlist[0] # the first version from list is used cl = calc[(it, ise, v)] cl.gbpos = gbpos new = copy.deepcopy(cl) if use_init: new.end = new.init else: new.init = new.end #replace init structure by the end structure if 1: #atom substitution !make function; see TODO if znucl_sub not in new.init.znucl: new.init.znucl.append(znucl_sub) new.init.ntypat += 1 new.init.typat[replace_atom] = new.init.ntypat else: ind = new.init.znucl.index(znucl_sub) 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)) printlog("Impurity with Z=" + str(znucl_sub) + " has been substituted in " + new.name + "\n\n") it_new = base_name + el_sub + 'is' + str( i + 1) #interface substitution if option == 'precip': it_new_path = precip_folder else: it_new_path = main_path + '/' + base_name + '_segreg' #Check if configuration is unique add = 1 # for cl in cl_list: st = new.end st_replic = replic(st, (2, 2, 2)) st_replic = replic(st_replic, (2, 2, 2), -1) #replic in negative direction also sumr = local_surrounding( st.xcart[replace_atom], st_replic, n_neighbours=6) # sum of distances to surrounding atoms print("sumr", sumr) for ad_sumr in sumr_list: if abs(ad_sumr - sumr) < precision: add = 0 printlog("The void is non-equivalent; skipping\n") if add: i += 1 sumr_list.append(sumr) # cl_list.append(new) write_local(new, it_new, it_new_path, el_sub, main_path) for v in verlist[1:]: #write files; versions are scaled cl = calc[(it, ise, v)] rprimd_scaled = cl.end.rprimd new_scaled = copy.deepcopy(new) new_scaled.init.rprimd = copy.deepcopy(rprimd_scaled) new_scaled.init.xred2xcart() write_local(new_scaled, it_new, it_new_path, el_sub, main_path) #create names des_list.append( "struct_des['{0:s}'] = des('{1:s}', 'segregation configurations; made from {2:s}' )" .format(it_new, it_new_path, based_on)) add_list.append("add_loop('" + it_new + "','" + ise_new + "'," + "range(1,6)" + ", up = 'up1', it_folder = '" + it_new_path + "')") for d in des_list: print(d) for d in add_list: print(d) return
def add_neb(starting_calc=None, st=None, st_end=None, it_new=None, ise_new=None, i_atom_to_move=None, up='up2', search_type='vacancy_creation', images=None, r_impurity=None, calc_method=['neb'], inherit_option=None, mag_config=None, i_void_start=None, i_void_final=None, atom_to_insert=None, atom_to_move=None, rep_moving_atom=None, end_pos_types_z=None, replicate=None, it_new_folder=None, it_folder=None, inherit_magmom=False, x_start=None, xr_start=None, x_final=None, xr_final=None, upload_vts=False, center_on_moving=True, run=False, add_loop_dic=None, old_behaviour=None, params=None): """ Prepare needed files for NEB Provides several regimes controlled by *search_type* flag: - existing_voids - search for voids around atom and use them as a final position - vacancy_creation - search for neighbors of the same type and make a vacancy as a start position - interstitial_insertion - search for two neighboring voids; use them as start and final positions by inserting atom *atom_to_insert* - None - just use st and st2 as initial and final ###INPUT: - starting_calc (Calculation) - Calculation object with structure - st (Structure) - structure, can be used instead of Calculation - it_new (str) - name for calculation - st_end (Structure) - final structure - i_atom_to_move (int) - number of atom for moving starting from 0; - *mag_config* (int ) - choose magnetic configuration - allows to obtain different localizations of electron - *replicate* (tuple 3*int) - replicate cell along rprimd - i_void_start, i_void_final (int) - position numbers of voids (or atoms) from the suggested lists - atom_to_insert (str) - element name of atom to insert - atom_to_move (str) - element name of atom to move - it_new_folder or it_folder (str) - section folder - inherit_option (str) - passed only to add_loop - inherit_magmom (bool) - if True than magmom from starting_calc is used, else from set - end_pos_types_z (list of int) - list of Z - type of atoms, which could be considered as final positions in vacancy creation mode - calc_method (list) - 'neb' - 'only_neb' - run only footer - x_start, x_final (array) - explicit xcart coordinates of moving atom for starting and final positions, combined with atom_to_insert - xr_start, xr_final (array) - explicit xred - rep_moving_atom (str)- replace moving atom by needed atom - can be useful than completly different atom is needed. - upload_vts (bool) - if True upload Vasp.pm and nebmake.pl to server - run (bool) - run on server - old_behaviour (str) - choose naming behavior before some date in the past for compatibility with your projects '020917' '261018' - after this moment new namig convention applied if end_pos_types_z is used - add_loop_dic - standart parameters of add() - params (dic) - provide additional parameters to add() # should be removed ###RETURN: None ###DEPENDS: ###TODO 1. Take care of manually provided i_atom_to_move in case of replicate flag using init_numbers 2. For search_type == None x_m and x_del should be determined for magnetic searching and for saving their coordinates to struct_des; now their just (0,0,0) """ naming_conventions209 = True # set False to reproduce old behavior before 2.09.2017 if old_behaviour == '020917': naming_conventions209 = False # # print('atom_to_insert', atom_to_insert) # sys.exit() calc = header.calc struct_des = header.struct_des varset = header.varset if not add_loop_dic: add_loop_dic = {} if not end_pos_types_z: end_pos_types_z = [] end_pos_types_z = sorted(end_pos_types_z) if not hasattr(calc_method, '__iter__'): calc_method = [calc_method] if starting_calc and st: printlog( 'Warning! both *starting_calc* and *st* are provided. I use *starting_calc*' ) st = copy.deepcopy(starting_calc.end) elif starting_calc: st = copy.deepcopy(starting_calc.end) printlog('I use *starting_calc*') elif st: '' printlog('I use *st*') else: printlog( 'Error! no input structure. Use either *starting_calc* or *st*') corenum = add_loop_dic.get('corenum') # print(corenum) # sys.exit() if corenum == None: if images == 3: corenum = 15 elif images == 5: corenum = 15 elif images == 7: corenum = 14 else: printlog('add_neb(): Error! number of images', images, 'is unknown to me; please provide corenum!') # print(corenum) # sys.exit() # print(atom_to_insert) # sys.exit() if corenum: # header.corenum = corenum '' else: corenum = header.CORENUM if corenum % images > 0: print_and_log( 'Error! Number of cores should be dividable by number of IMAGES', images, corenum) if not ise_new: ise_new = starting_calc.id[1] printlog('I use', ise_new, 'as ise_new', imp='y') name_suffix = '' st_pores = [] name_suffix += 'n' + str(images) """Replicate cell """ if replicate: print_and_log('You have chosen to replicate the structure by', replicate) st = replic(st, mul=replicate) name_suffix += str(replicate[0]) + str(replicate[1]) + str( replicate[2]) printlog('Search type is ', search_type) if search_type == None: if st_end == None: printlog( 'Error! You have provided search_type == None, st_end should be provided!' ) st1 = st st2 = st_end x_m = (0, 0, 0) x_del = (0, 0, 0) else: """1. Choose atom (or insert) for moving """ if is_list_like(xr_start): x_start = xred2xcart([xr_start], st.rprimd)[0] # print('atom_to_insert', atom_to_insert) # sys.exit() st1, i_m = st.add_atoms([x_start], atom_to_insert, return_ins=1) x_m = x_start # i_m = st1.find_atom_num_by_xcart(x_start) # print(st1.get_elements()[i_m]) # sys.exit() if i_atom_to_move: nn = str(i_atom_to_move + 1) else: nn = str(i_void_start) name_suffix += atom_to_insert + nn write_xyz(st1, file_name=st.name + '_manually_start') printlog('Start position is created manually by adding xr_start', xr_start, x_start) type_atom_to_move = atom_to_insert el_num_suffix = '' else: atoms_to_move = [] atoms_to_move_types = [] # print('d', i_atom_to_move) # sys.exit() if i_atom_to_move: typ = st.get_elements()[i_atom_to_move] printlog('add_neb(): atom', typ, 'will be moved', imp='y') atoms_to_move.append( [i_atom_to_move, typ, st.xcart[i_atom_to_move]]) atoms_to_move_types.append(typ) if naming_conventions209: name_suffix += typ + str(i_atom_to_move + 1) else: #try to find automatically among alkali - special case for batteries for i, typ, x in zip(range(st.natom), st.get_elements(), st.xcart): if typ in ['Li', 'Na', 'K', 'Rb', 'Mg']: atoms_to_move.append([i, typ, x]) if typ not in atoms_to_move_types: atoms_to_move_types.append(typ) if atoms_to_move: # print(atom_to_move) # sys.exit() if not atom_to_move: atom_to_move = atoms_to_move_types[ 0] # taking first found element if len(atoms_to_move_types) > 1: printlog( 'Error! More than one type of atoms available for moving detected', atoms_to_move_types, 'please specify needed atom with *atom_to_move*') type_atom_to_move = atom_to_move #atoms_to_move[0][1] # printlog('atom ', type_atom_to_move, 'will be moved', imp ='y') if i_atom_to_move: printlog('add_neb(): *i_atom_to_move* = ', i_atom_to_move, 'is used', imp='y') numbers = [[i_atom_to_move]] i_void_start = 1 else: printlog('add_neb(): determine_symmetry_positions ...', imp='y') numbers = determine_symmetry_positions(st, atom_to_move) # print(numbers) # sys.exit() if len(numbers) > 0: printlog('Please choose position using *i_void_start* :', [i + 1 for i in range(len(numbers))], imp='y') printlog('*i_void_start* = ', i_void_start) i_m = numbers[i_void_start - 1][0] printlog('Position', i_void_start, 'chosen, atom:', i_m + 1, type_atom_to_move, imp='y') else: i_m = numbers[0][0] x_m = st.xcart[i_m] el_num_suffix = type_atom_to_move + str(i_m + 1) atom_to_insert = atom_to_move st1 = st # elif atom_to_replace: # num = st.get_specific_elements(atom_to_replace) # if len(n)>0: # printlog('Please choose position using *i_void_start* :', [i+1 for i in range(len(num))],imp = 'y' ) # printlog('*i_void_start* = ', i_void_start) # i_m = num[i_void_start-1] # printlog('Position',i_void_start,'chosen, atom to replace:', i_m+1, atom_to_replace, imp = 'y' ) # sys.exit() else: print_and_log( 'No atoms to move found, you probably gave me deintercalated structure', important='y') st_pores, sums, avds = determine_voids(st, r_impurity, step_dec=0.1, fine=2) insert_positions = determine_unique_voids(st_pores, sums, avds) print_and_log( 'Please use *i_void_start* to choose the void for atom insertion from the Table above:', end='\n', imp='Y') if i_void_start == None: sys.exit() if atom_to_insert == None: printlog('Error! atom_to_insert = None') st = st.add_atoms([ insert_positions[i_void_start], ], atom_to_insert) name_suffix += 'i' + str(i_void_start) i_m = st.natom - 1 x_m = st.xcart[i_m] search_type = 'existing_voids' type_atom_to_move = atom_to_insert el_num_suffix = '' st1 = st """2. Choose final position""" if is_list_like(xr_final): x_final = xred2xcart([xr_final], st.rprimd)[0] #old #check if i_atom_to_move should be removed # st2 = st1.del_atom(i_m) # st2 = st2.add_atoms([x_final], atom_to_insert) #new st2 = st1.mov_atoms(i_m, x_final) # st1.printme() # st2.printme() # sys.exit() x_del = x_final search_type = 'manual_insertion' name_suffix += 'v' + str(i_void_final) write_xyz(st2, file_name=st.name + '_manually_final') printlog('Final position is created manually by adding xr_final', xr_final, x_del) elif search_type == 'existing_voids': #Search for voids around choosen atoms if not st_pores: st_pores, sums, avds = determine_voids(st, r_impurity) sur = determine_unique_final(st_pores, sums, avds, x_m) print_and_log('Please choose *i_void_final* from the Table above:', end='\n', imp='Y') if i_void_final == None: sys.exit() x_final = sur[0][i_void_final] # printlog('You chose:', np.array(x_final).round(2), end='\n', imp='Y') x_del = x_final #please compare with vacancy creation mode write_xyz(st.add_atoms([x_final], 'H'), replications=(2, 2, 2), file_name=st.name + '_possible_positions2_replicated') print_and_log('Choosing the closest position as end', important='n') st1 = st st2 = st.mov_atoms(i_m, x_final) name_suffix += el_num_suffix + 'e' + str( i_void_final) + atom_to_insert st1 = return_atoms_to_cell(st1) st2 = return_atoms_to_cell(st2) write_xyz(st1, file_name=st1.name + name_suffix + '_start') write_xyz(st2, file_name=st2.name + name_suffix + '_final') elif search_type == 'vacancy_creation': #Create vacancy by removing some neibouring atom of the same type print_and_log( 'You have chosen vacancy_creation mode of add_neb tool', imp='Y') print_and_log('Type of atom to move = ', type_atom_to_move, imp='y') # print 'List of left atoms = ', np.array(st.leave_only(type_atom_to_move).xcart) final_pos_z = end_pos_types_z or [ invert(type_atom_to_move) ] # by default only moving atom is considered end_pos_types_el = [invert(z) for z in end_pos_types_z] sur = local_surrounding(x_m, st, n_neighbours=14, control='atoms', only_elements=final_pos_z, periodic=True) #exclude the atom itself # print(x_m) # print(sur) # st.nn() end_pos_n = sur[2][1:] print_and_log( 'I can suggest you ' + str(len(end_pos_n)) + ' end positions. The distances to them are : ', np.round(sur[3][1:], 2), ' A\n ', 'They are ', [invert(z) for z in final_pos_z], 'atoms, use *i_void_final* to choose required: 1, 2, 3 ..', imp='y') i_sym_final_l = [] for j in end_pos_n: for i, l in enumerate(numbers): if j in l: i_sym_final_l.append(i + 1) printlog('Their symmetry positions are ', i_sym_final_l, imp='y') # sys.exit() if not i_void_final: printlog('Changing i_void_final: None -> 1', imp='y') i_void_final = 1 #since zero is itself chosen_dist = sur[3][i_void_final] print_and_log('Choosing position ', i_void_final, 'with distance', round(chosen_dist, 2), 'A', imp='y') # print(end_pos_n) i_sym_final = 0 n_final = sur[2][i_void_final] for i, l in enumerate(numbers): if n_final in l: i_sym_final = i + 1 printlog('It is symmetrically non-equiv position #', i_sym_final, imp='y') # sys.exit() header.temp_chosen_dist = chosen_dist if old_behaviour == '261018': name_suffix += el_num_suffix + 'v' + str(i_void_final) else: name_suffix += el_num_suffix + 'v' + str( i_void_final) + list2string(end_pos_types_el, joiner='') # print(name_suffix) # sys.exit() x_del = sur[0][i_void_final] printlog('xcart of atom to delete', x_del) i_del = st.find_atom_num_by_xcart(x_del) # print(x_del) # print(st.xcart) # for x in st.xcart: # if x[0] > 10: # print(x) print_and_log('number of atom to delete = ', i_del, imp='y') if i_del == None: printlog('add_neb(): Error! I could find atom to delete!') # print st.magmom # print st1.magmom # try: if is_list_like(xr_start): st2 = st1.mov_atoms( i_m, x_del) # i_m and sur[0][neb_config] should coincide # i_del = st1.find_atom_num_by_xcart(x_del) st1 = st1.del_atom(i_del) else: print_and_log( 'Making vacancy at end position for starting configuration', imp='y') st1 = st.del_atom(i_del) print_and_log( 'Making vacancy at start position for final configuration', important='n') st2 = st.mov_atoms( i_m, x_del) # i_m and sur[0][neb_config] should coincide # except: # st2 = st st2 = st2.del_atom(i_del) # these two steps provide the same order """Checking correctness of path""" #if start and final positions are used, collisions with existing atoms are possible if is_list_like(xr_start) and is_list_like(xr_final): printlog('Checking correctness') st1, _, _ = st1.remove_close_lying() stt = st1.add_atoms([ x_final, ], 'Pu') stt, x, _ = stt.remove_close_lying( rm_both=True ) # now the final position is empty for sure; however the order can be spoiled # print(st._removed) if stt._removed: st1 = stt # only if overlapping was found we assign new structure st2, _, _ = st2.remove_close_lying(rm_first=stt._removed) stt = st2.add_atoms([ x_start, ], 'Pu') stt, x, _ = stt.remove_close_lying( rm_both=True) # now the start position is empty for sure if stt._removed: st2 = stt print(st2.get_elements()) # sys.exit() elif is_list_like(xr_final) and not is_list_like(xr_start) or is_list_like( xr_start) and not is_list_like(xr_final): printlog( 'Attention! only start or final position is provided, please check that everything is ok with start and final states!!!' ) """ Determining magnetic moments """ vp = varset[ise_new].vasp_params if 'ISPIN' in vp and vp['ISPIN'] == 2: print_and_log( 'Magnetic calculation detected. Preparing spin modifications ...', imp='y') cl_test = CalculationVasp(varset[ise_new]) cl_test.init = st1 # print 'asdfsdfasdfsadfsadf', st1.magmom if inherit_magmom and hasattr(st, 'magmom') and st.magmom and any( st.magmom): print_and_log( 'inherit_magmom=True: You have chosen MAGMOM from provided structure', imp='y') name_suffix += 'mp' #Magmom from Previous else: cl_test.init.magmom = None print_and_log( 'inherit_magmom=False or no magmom in input structure : MAGMOM will be determined from set', imp='y') name_suffix += 'ms' #Magmom from Set cl_test.actualize_set() #find magmom for current structure st1.magmom = copy.deepcopy(cl_test.init.magmom) st2.magmom = copy.deepcopy(cl_test.init.magmom) # sys.exit() # print_and_log('The magnetic moments from set:') # print cl_test.init.magmom if search_type != None: # for None not implemented; x_m should be determined first for this #checking for closest atoms now only for Fe, Mn, Ni, Co sur = local_surrounding(x_m, st1, n_neighbours=3, control='atoms', periodic=True, only_elements=header.TRANSITION_ELEMENTS) dist = np.array(sur[3]).round(2) numb = np.array(sur[2]) a = zip(numb, dist) # a= np.array(a) # print a[1] # a = np.apply_along_axis(np.unique, 1, a) # print a def unique_by_key(elements, key=None): if key is None: # no key: the whole element must be unique key = lambda e: e return list({key(el): el for el in elements}.values()) # print a mag_atoms_dists = unique_by_key(a, key=itemgetter(1)) # print (mag_atoms_dists) # a = unique_by_key(a, key=itemgetter(1)) print_and_log( 'I change spin for the following atoms:\ni atom dist\n', np.round(mag_atoms_dists, 2), imp='y') # print 'I have found closest Fe atoms' muls = [(1.2, 0.6), (0.6, 1.2)] mag_moments_variants = [] for mm in muls: mags = copy.deepcopy(cl_test.init.magmom) # print mags for a, m in zip(mag_atoms_dists, mm): # print t[1] mags[a[0]] = mags[a[0]] * m mag_moments_variants.append(mags) print_and_log('The list of possible mag_moments:', imp='y') for i, mag in enumerate(mag_moments_variants): print_and_log(i, mag) print_and_log( 'Please use *mag_config* arg to choose desired config', imp='y') if mag_config != None: st1.magmom = copy.deepcopy(mag_moments_variants[mag_config]) st2.magmom = copy.deepcopy(mag_moments_variants[mag_config]) name_suffix += 'm' + str(mag_config) print_and_log('You have chosen mag configuration #', mag_config, imp='y') else: print_and_log('Non-magnetic calculation continue ...') """3. Add to struct_des, create geo files, check set, add_loop """ if starting_calc: it = starting_calc.id[0] it_new = it + 'v' + str(starting_calc.id[2]) + '.' + name_suffix if not it_new_folder: it_new_folder = struct_des[it].sfolder + '/neb/' obtained_from = str(starting_calc.id) if not ise_new: print_and_log('I will run add_loop() using the same set', important='Y') ise_new = cl.id[1] elif st: if not it_new: printlog( 'Error! please provide *it_new* - name for your calculation', important='Y') it = None it_new += '.' + name_suffix obtained_from = st.name if not ise_new: printlog('Error! please provide *ise_new*', important='Y') if not it_new_folder and not it_folder: printlog( 'Error! please provide *it_new_folder* - folder for your new calculation', important='Y') if it_folder: it_new_folder = it_folder if rep_moving_atom: it_new += 'r' + rep_moving_atom if it_new not in struct_des: add_des(struct_des, it_new, it_new_folder, 'Automatically created and added from ' + obtained_from) print_and_log( 'Creating geo files for starting and final configurations (versions 1 and 2) ', important='y') # if starting_calc: # cl = copy.deepcopy(starting_calc) # else: cl = CalculationVasp() #write start position if search_type is not None: struct_des[it_new].x_m_ion_start = x_m struct_des[it_new].xr_m_ion_start = xcart2xred([x_m], st1.rprimd)[0] # st1, _, _ = st1.remove_close_lying() # st2, _, _ = st2.remove_close_lying() print('Trying to find x_m', x_m) i1 = st1.find_atom_num_by_xcart( x_m, prec=0.45, ) # sys.exit() print('Trying to find x_del', x_del) i2 = st2.find_atom_num_by_xcart( x_del, prec=0.45, ) if rep_moving_atom: #replace the moving atom by required st1 = st1.replace_atoms([i1], rep_moving_atom) st2 = st2.replace_atoms([i2], rep_moving_atom) else: #allows to make correct order for nebmake.pl st1 = st1.replace_atoms([i1], type_atom_to_move) st2 = st2.replace_atoms([i2], type_atom_to_move) i1 = st1.find_atom_num_by_xcart( x_m, prec=0.45) # the positions were changed # check if this is correct i2 = st2.find_atom_num_by_xcart(x_del, prec=0.45) cl.end = st1 ver_new = 1 cl.version = ver_new cl.path["input_geo"] = header.geo_folder + struct_des[it_new].sfolder + '/' + \ it_new+"/"+it_new+'.auto_created_starting_position_for_neb_'+str(search_type)+'.'+str(ver_new)+'.'+'geo' cl.write_siman_geo(geotype='end', description='Starting conf. for neb from ' + obtained_from, override=True) #write final position struct_des[it_new].x_m_ion_final = x_del struct_des[it_new].xr_m_ion_final = xcart2xred([x_del], st2.rprimd)[0] cl.end = st2 ver_new = 2 cl.version = ver_new cl.path["input_geo"] = header.geo_folder + struct_des[it_new].sfolder + '/' + \ it_new+"/"+it_new+'.auto_created_final_position_for_neb_'+str(search_type)+'.'+str(ver_new)+'.'+'geo' cl.write_siman_geo(geotype='end', description='Final conf. for neb from ' + obtained_from, override=True) if not rep_moving_atom and search_type is not None: st1s = st1.replace_atoms([i1], 'Pu') st2s = st2.replace_atoms([i2], 'Pu') else: st1s = copy.deepcopy(st1) st2s = copy.deepcopy(st2) if center_on_moving and search_type is not None: vec = st1.center_on(i1) st1s = st1s.shift_atoms(vec) st2s = st2s.shift_atoms(vec) write_xyz(st1s, file_name=it_new + '_start') write_xyz(st2s, file_name=it_new + '_end') st1s.write_poscar('xyz/POSCAR1') st2s.write_poscar('xyz/POSCAR2') # print(a) # runBash('cd xyz; mkdir '+it_new+'_all;'+"""for i in {00..04}; do cp $i/POSCAR """+ it_new+'_all/POSCAR$i; done; rm -r 00 01 02 03 04') with cd('xyz'): a = runBash(header.PATH2NEBMAKE + ' POSCAR1 POSCAR2 3') print(a) dst = it_new + '_all' makedir(dst + '/any') for f in ['00', '01', '02', '03', '04']: shutil.move(f + '/POSCAR', dst + '/POSCAR' + f) shutil.rmtree(f) #prepare calculations # sys.exit() #Check if nebmake is avail # if int(runBash('ssh '+cluster_address+' test -e '+project_path_cluster+'/tools/vts/nebmake.pl; echo $?') ): # '' # print_and_log('Please upload vtsttools to ',cluster_address, project_path_cluster+'/tools/vts/') # raise RuntimeError # copy_to_server(path_to_wrapper+'/vtstscripts/nebmake.pl', to = project_path_cluster+'/tools/', addr = cluster_address) # if int(runBash('ssh '+cluster_address+' test -e '+project_path_cluster+'/tools/Vasp.pm; echo $?') ): # copy_to_server(path_to_wrapper+'/vtstscripts/Vasp.pm', to = project_path_cluster+'/tools/', addr = cluster_address) inherit_ngkpt(it_new, it, varset[ise_new]) if run: add_loop_dic['run'] = run add_loop_dic['corenum'] = corenum # print(add_loop_dic) add_loop( it_new, ise_new, verlist=[1, 2], up=up, calc_method=calc_method, savefile='oc', inherit_option=inherit_option, n_neb_images=images, # params=params, **add_loop_dic) if upload_vts: siman_dir = os.path.dirname(__file__) # print(upload_vts) push_to_server([ siman_dir + '/cluster_tools/nebmake.pl', siman_dir + '/cluster_tools/Vasp.pm' ], to=header.cluster_home + '/tools/vts', addr=header.cluster_address) else: print_and_log('Please be sure that vtsttools are at', header.cluster_address, header.cluster_home + '/tools/vts/', imp='Y') printlog('add_neb finished') return it_new
def find_polaron(st, i_alk_ion, out_prec=1, nstd=1.5): """ Find TM atoms with outlying magnetic moments, which is a good indication of being a small polaron Can be problems with charged-ordered materials INPUT: i_alk_ion - number of ion from 0 to calculate distances to detected polarons out_prec (int) - precision of magmom output nstd - number of standart deviations to detect polaron RETURN: pol (dict of int) - numbers of atoms, where polarons are detected for each TM element magmom_tm (list of float) - just magmom for TM TODO: 1. Add analysis of bond lengths to distinguish small polarons Janh-Teller 2. Add treatment of charged-ordered """ def zscore(s): # print(np.std(s)) return (s - np.mean(s)) / np.std(s) magmom = np.array(st.magmom) if len(magmom) == 0: printlog('Warning! magmom is empty') _, mag_numbers = st.get_maglist() pol = {} # for z in mag_numbers: # pos = determine_symmetry_positions(st, invert(z)) # sys.exit() magmom_tm = None for z in mag_numbers: printlog('Looking at polarons on transition atoms: ', invert(z)) numbs = np.array(mag_numbers[z]) # print(numbs) # print(magmom) magmom_tm = magmom[numbs] dev = np.absolute(zscore(magmom_tm)) # print(magmom_tm) # print(list(zip(magmom_tm, dev.round(1)))) # p = np.where(dev>2)[0] # 2 standard deviations # print(dev>2) # print (type(numbs)) # nstd = 1.5 # nstd = 4 i_pols = numbs[dev > nstd] if len(i_pols) > 0: x1 = st.xcart[i_alk_ion] d_to_pols = [] for j in i_pols: x2 = st.xcart[j] d, _ = st.image_distance(x1, x2, st.rprimd) d_to_pols.append(d) print( 'polarons are detected on atoms', [i for i in i_pols], 'with magnetic moments:', magmom[i_pols], 'and distances: ' + ', '.join('{:2.2f}'.format(d) for d in d_to_pols), 'A') print('mag moments on trans. atoms:', magmom_tm.round(out_prec)) pol[z] = i_pols else: print('no polarons is detected with nstd', nstd) print('mag moments on trans. atoms:', magmom_tm.round(out_prec)) # print(' deviations :', dev.round(1)) pol[z] = None return pol, magmom_tm
def suf_en(cl1, cl2, silent=0, chem_pot=None, return_diff_energy=False, ev_a=0, normal=2, normalize_by=None): """Calculate surface energy cl1 - supercell with surface cl2 - comensurate bulk supercell the area is determined from r[0] and r[1];- i.e they lie in surface chem_pot (dic) - dictionary of chemical potentials for nonstoichiometric slabs normal - normal to the surface 0 - along a, 1 - along b, 2 - along c normalize_by - name of element to normalize number of atoms in bulk and slab, if None, transition elements are used return_diff_energy (bool) - in addtion to gamma return difference of energies """ if chem_pot is None: chem_pot = {} st1 = cl1.end st2 = cl2.end # pm = st1.convert2pymatgen(oxidation = {'Y':'Y3+', 'Ba':'Ba2+', 'Co':'Co2.25+', 'O':'O2-'}) natom1 = st1.get_natom() natom2 = st2.get_natom() if natom1 % natom2: printlog('Warning! Non-stoichiometric slab, atom1/natom2 is', natom1 / natom2) if normal == 0: A = np.linalg.norm(np.cross(st1.rprimd[1], st1.rprimd[2])) if normal == 1: A = np.linalg.norm(np.cross(st1.rprimd[0], st1.rprimd[2])) if normal == 2: A = np.linalg.norm(np.cross(st1.rprimd[0], st1.rprimd[1])) if not silent: print('Surface area is {:.2f} A^2, please check'.format(A)) # get_reduced_formula # print(natom1, natom2) if normalize_by: '' z = invert(normalize_by) tra1 = st1.get_specific_elements([z]) tra2 = st2.get_specific_elements([z]) else: tra1 = st1.get_transition_elements() tra2 = st2.get_transition_elements() ntra1 = len(tra1) # if ntra1 == 0: if ntra1 == 0: ntra1 = natom1 ntra2 = len(tra2) if ntra2 == 0: ntra2 = natom2 rat1 = natom1 / ntra1 rat2 = natom2 / ntra2 mul = ntra1 / ntra2 # print(rat1, rat2, natom1, ntra1, natom2, ntra2,) if not silent: print('Number of bulk cells in slab is {:n}'.format(mul)) if rat1 != rat2: printlog('Non-stoichiometric slab, ratios are ', rat1, rat2, 'provide chemical potentials', imp='y') #get number of TM atoms in slab if len(set(tra1)) > 1: printlog('More than one type of TM is not supported yet') return els1 = st1.get_elements() els2 = st2.get_elements() uniqe_elements = list(set(els1)) el_dif = { } # difference of elements between slab and normalized by transition metals bulk phase for el in uniqe_elements: dif = els1.count(el) - mul * els2.count(el) if not float(dif).is_integer(): printlog( 'Error! difference of atom numbers is not integer for element ', el, 'something is wrong') if abs(dif) > 0: el_dif[el] = int(dif) print('The following elements are off-stoicheometry in the slab', el_dif, 'please provide corresponding chemical potentials') E_nonst = 0 for key in el_dif: if key not in chem_pot: printlog('Warning! no chemical potential for ', key, 'in chem_pot, return') return E_nonst += el_dif[key] * chem_pot[key] else: E_nonst = 0 diff = cl1.e0 - (cl2.e0 * mul + E_nonst) gamma = diff / 2 / A * header.eV_A_to_J_m gamma_ev = diff / 2 / A # print(A) if not silent: print('Surface energy = {:3.2f} J/m2 | {:} | {:} '.format( gamma, cl1.id, cl2.id)) if ev_a: print('Surface energy = {:3.2f} eV/A2 | {:} | {:} '.format( gamma_ev, cl1.id, cl2.id)) if return_diff_energy: return gamma, diff else: return gamma
def add_to_archive_database(cl, subgroup): """ cl is Calculation which should be added to database subgroup (str) - subgroup folder """ from pymatgen.core.composition import Composition from pymatgen.io.cif import CifWriter from pymatgen.symmetry.analyzer import SpacegroupAnalyzer join = os.path.join basename = os.path.basename dirname = os.path.dirname save_format = 'azh' dbpath = header.PATH2DATABASE it = cl.id[0] # print(cl.path) sub_folder = cl.path['output'].split('/')[ 0] # usually basic chemical formula # sub_folder = header.struct_des[it].sfolder.split('/')[0] # usually basic chemical formula print('Processing ', cl.id) cl.read_results() if '4' not in cl.state: return st = cl.end # print(cl.end.typat) # sys.exit() if 1: #determine x #universal method, supports several alkali elements #requires cl.base_formula in 'Na2FePO4F' format #requires pymatgen, would be nice to remove dependency cmb = Composition(cl.base_formula) cm = st.get_pm_composition() rc = cl.end.get_reduced_composition().as_dict( ) #reduced composition dict rcb = cmb.reduced_composition.as_dict() # print(rc, rcb) alk = list(set(st.get_specific_elements( header.ALKALI_ION_ELEMENTS))) # list of unique alkali elements tra = list(set(st.get_specific_elements(header.TRANSITION_ELEMENTS))) # print(alk, tra) el_for_norm = tra[0] #first element used for normalization nnb = rcb[el_for_norm] #number of norm elements in base nn = rc[el_for_norm] #number of norm elements in interesting structure # print(nb, n) mul = nn / nnb # multiplier that garanties normalization # print(rcb) nab = sum([ rcb[invert(z)] for z in header.ALKALI_ION_ELEMENTS if invert(z) in rcb ]) na = sum([rc[el] for el in alk]) x = na / mul / nab # determine formula # cm = st.get_pm_composition() #get pymatgen composition class # print( (cm/4).formula) # print('Material detected:', formula, 'sub_folder:', sub_folder) #obtain base without alk formula = (cm.reduced_composition / mul).formula # formula = formula.replace('1 ', '').replace(' ', '') # print(formula) cl.formula = formula # print(Composition('Na0.75')) print('Material detected:', formula, 'sub_folder:', sub_folder) # sys.exit() if 0: #Old method, not robust at all! #determine x for alkali ion from structure name parsed = re.findall(r'([A-Z][a-z]*)(\d*)', formula) parsed = [(el, x if x else '1') for (el, x) in parsed] print(parsed) print('detected element is ', parsed[0][0]) if parsed[0][0] in [invert(z) for z in header.ALKALI_ION_ELEMENTS]: x = parsed[0][0] if hasattr(cl, 'max_alk_ion_content'): x = float(x) / cl.max_alk_ion_content else: x = '1' else: x = '0' sfolder = os.path.join(dbpath, sub_folder) name = [] if 'azh' in save_format: #1. Single point calculation of total energy # print(sfolder) makedir(join(sfolder, 'dummy')) if x < 1: x = int(round(100 * x, 0)) else: x = int(round(x, 0)) print('Concentration x:', x) name.append('x' + str(x)) # sys.exit() # if formula in ['LiCoO2', 'LiTiO2', 'LiFePO4', 'NaFePO4', 'LiMnPO4', # 'LiNiO2', 'LiTiS2', 'LiMn2O4', 'LiVP2O7', 'LiVPO4F', # 'NaMnAsO4', 'Na2FePO4F', 'Na2FeVF7', 'KFeSO4F', 'NaLiCoPO4F', 'KVPO4F' ]: sfolder = join(sfolder, subgroup) makedir(join(sfolder, 'dummy')) cl.set.update() # print(cl.potcar_lines) potcar1_m = cl.potcar_lines[0][0] if '_' in potcar1_m: (pot, _) = potcar1_m.split('_') else: pot = potcar1_m xc = cl.xc_inc if '-' in xc: xc = cl.xc_pot if xc == 'PE': func = 'PBE' elif xc == 'CA': func = 'LDA' elif xc == 'PS': func = 'PBEsol' else: print('uknown xc type:', xc) sys.exit() if cl.set.spin_polarized: func = 'U' + func #unrestricted u_ramping_flag = False if hasattr(cl.set, 'u_ramping_nstep') and cl.set.u_ramping_nstep: func += '-UR' u_ramping_flag = True elif cl.set.dftu: func += '-U' else: func += '-' func += pot.lower() ecut = str(round(cl.set.ecut)) func += ecut # print(func) name.append(func) name.extend([it.replace('.', '_')] + [cl.id[1]] + [str(cl.id[2])]) name_str = '_'.join(name) # print('_'.join(name) ) # sys.exit() outcar_name = name_str + '.out' shutil.copyfile(cl.path["output"], join(sfolder, outcar_name)) if u_ramping_flag: print(cl.associated_outcars) for i, u_outcar in enumerate( cl.associated_outcars[:-1] ): # except the last one, which was copied above u = u_outcar.split('.')[1] # print(u) path_to_outcar = join(dirname(cl.path["output"]), u_outcar) cl.read_results(load='o', choose_outcar=i + 1, only_load=1) shutil.copyfile(path_to_outcar, join(sfolder, name_str + '_' + u + '.out')) # sys.exit() cl.end.write_xyz(path=sfolder, filename=name_str) pickle_file = cl.serialize(os.path.join(sfolder, 'bin', name_str)) # cl #write input, problem with fitted version 100, which does not have input geometry, since they are created on cluster # makedir(sfolder+'input/dummy') # shutil.copyfile(cl.path["input_geo"], sfolder+'input/'+name_str+'.geo') st_mp = cl.end.convert2pymatgen() sg_before = st_mp.get_space_group_info() # from pymatgen.symmetry.finder import SymmetryFinder # sf = SymmetryFinder(st_mp_prim) symprec = 0.1 sf = SpacegroupAnalyzer(st_mp, symprec=symprec) st_mp_prim = sf.find_primitive() # st_mp_prim = sf.get_primitive_standard_structure() # st_mp_prim = sf.get_conventional_standard_structure() # st_mp_conv = sf.get_conventional_standard_structure() # print(st_mp_conv) # print(st_mp_conv.lattice.matrix) # print(st_mp_prim) # print(st_mp_prim.lattice) sg_after = st_mp_prim.get_space_group_info() if sg_before[0] != sg_after[0]: printlog( 'Attention! the space group was changed after primitive cell searching', sg_before, sg_after) printlog('I will save supercell in cif and reduce symprec to 0.01') st_mp_prim = st_mp symprec = 0.01 if st_mp_prim: cif = CifWriter(st_mp_prim, symprec=symprec) cif_name = name_str + '.cif' cif.write_file(join(sfolder, cif_name)) printlog('Writing cif', cif_name) if 0: #get multiplication matrix which allows to obtain the supercell from primitive cell. #however this matrix is not integer which is not convinient. print(st_mp.lattice.matrix.round(2)) print(st_mp_prim.lattice.matrix.round(2)) mul_matrix = np.dot(st_mp.lattice.matrix, np.linalg.inv(st_mp_prim.lattice.matrix)) print(mul_matrix.round(1)) rprimd = np.dot(mul_matrix, st_mp_prim.lattice.matrix) print(rprimd.round(2)) #write chg if 1: path_to_chg = cl.get_chg_file('CHGCAR') if path_to_chg: makedir(join(sfolder, 'bin', 'dummy')) printlog('path to chgcar', path_to_chg) gz = '.gz' if gz not in path_to_chg: gz = '' shutil.copyfile(path_to_chg, join(sfolder, 'bin', name_str + '.chg' + gz)) #write dos if subgroup in ['dos', 'DOS']: DOSCAR = cl.get_file('DOSCAR', nametype='asoutcar') if DOSCAR: printlog('path to DOSCAR', DOSCAR) gz = '.gz' if gz not in path_to_chg: gz = '' shutil.copyfile(DOSCAR, join(sfolder, 'bin', name_str + '.dos' + gz)) if subgroup in ['BAD']: #bader cl.get_bader_ACF() acf = cl.get_file(basename(cl.path['acf'])) # print(acf) # sys.exit() if acf: shutil.copyfile(acf, join(sfolder, 'bin', name_str + '.acf')) if subgroup in ['ph', 'PH']: #bader # cl.get_bader_ACF() xml = cl.get_file('vasprun.xml', nametype='asoutcar') # print(acf) # sys.exit() if xml: shutil.copyfile(xml, join(sfolder, 'bin', name_str + '.xml')) #make dat #incars makedir(join(sfolder, 'dat', 'dummy')) incars = glob.glob(join(cl.dir, '*INCAR*')) # print(incars) for inc in incars: dest = join(sfolder, 'dat') # inc_name = if not os.path.exists(join(dest, basename(inc))): shutil.copy(inc, dest) #kpoints if it in header.struct_des: with open(join(sfolder, 'dat', 'kpoints_for_kspacings.json'), 'w', newline='') as fp: json.dump( header.struct_des[it].ngkpt_dict_for_kspacings, fp, ) else: printlog('Warning!, it not in struct_des:', it) # print(cl.set.toJSON()) #prepare for neb # makedir(sfolder+'neb_'+name_str+'/dummy') return