Пример #1
0
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 
Пример #2
0
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
Пример #3
0
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 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 "No key", (it_ins, ise_ins, mat.version), "I use previous working version !!!"
            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
    
Пример #4
0
"""
import cgitb, cgi
cgitb.enable()
print('Content-type: text/html\n\n')

import sys
sys.path.extend(['/home/aksenov/www/siman'])
from classes import CalculationVasp
from analysis import calc_redox

db_path = '/home/aksenov/www/CES/'

form = cgi.FieldStorage()

# Get data from fields
string = form.getvalue('param')
string = string.replace('"', '')
files = string.split()

cl1 = CalculationVasp().deserialize(db_path + files[0])
cl2 = CalculationVasp().deserialize(db_path + files[1])

# output = cl1.energy_sigma0
output = calc_redox(cl1, cl2)['redox_pot']

# print(output, 'V')

# sys.stdout.write(str(output) )
# sys.stdout.flush()
sys.exit(0)
Пример #5
0
def insert(it_ins, ise_ins, mat_path, it_new, calc, type_of_insertion="xcart"):
    """For insertion of atoms to cells with changed lateral sizes
    Input:
    'type_of_insertion = xred' used to add xred coordinates  
    mat_path - path to geo files which are supposed to be changed
    it_ins - already existed calculation; xred will be used from this calculation.
    it_new - new folder in geo folder for obtained structure
    
    This function finds version of calculation in folder mat_path and tries to use the same version of it_ins

    """
    if not os.path.exists(mat_path):
        print_and_log("Error! Path " + mat_path + " does not exist\n\n")
        raise RuntimeError

    if it_ins not in mat_path and it_ins not in it_new:
        print_and_log('Cells are', it_ins, mat_path, it_new)
        print_and_log(
            "Error! you are trying to insert coordinates from cell with different name\n\n"
        )
        #raise RuntimeError

    hstring = ("%s    #on %s" %
               (traceback.extract_stack(None, 2)[0][3], datetime.date.today()))
    if hstring != header.history[-1]: header.history.append(hstring)

    geofilelist = runBash('find ' + mat_path +
                          '/target -name "*.geo*" ').splitlines()

    if geofilelist == []:
        print_and_log(
            "Warning! Target folder is empty. Trying to find in root folder ..."
        )
        geofilelist = runBash('find ' + mat_path +
                              '/ -name "*.geo*" ').splitlines()

    ins = None
    for mat_geofile in geofilelist:
        mat = CalculationVasp()
        mat.name = mat_geofile
        mat.read_geometry(mat_geofile)
        #step = 0.27
        #r_pore = 0.56
        #r_mat = mat.hex_a / 2 - step
        #pores = find_pores(mat.init, r_mat, r_pore, step, 0.3, 'central') #octahedral
        #mat.xcart.append ( pores.xcart[0] )
        #mat.typat.append(1)
        try:
            ins_working = ins
            ins = calc[(it_ins, ise_ins, mat.version)]
        except KeyError:
            print_and_log("No key", (it_ins, ise_ins, mat.version),
                          "I use previous working version !!!",
                          imp='y')
            ins = ins_working
            #return
        #ins.end.znucl = ins.znucl
        #ins.end.nznucl = ins.nznucl
        #ins.end.ntypat = ins.ntypat
        #ins.end.typat = ins.typat
        #print ins.xcart[-1]
        mat_geopath = geo_folder + struct_des[it_new].sfolder + '/'

        if type_of_insertion == "xcart":
            #Please update here!
            mat_filename = '/' + it_new + "." + "inserted." + str(
                mat.version) + '.' + 'geo'

            v = np.zeros(3)
            result = insert_cluster(ins.end, v, mat.init, v)
            mat.end = result
            mat.init = result
            # mat.znucl  =   mat.end.znucl
            # mat.nznucl =   mat.end.nznucl
            # mat.ntypat =   mat.end.ntypat
            # mat.typat  =   mat.end.typat
            # mat.natom = len(mat.end.xred)
            #mat.version = ins.version
            des = ins.name + " was inserted to " + mat_geofile

        elif type_of_insertion == "xred":

            mat_filename = '/from/' + it_new + ".xred." + str(
                mat.version) + '.' + 'geo'

            #mat.end.rprimd = mat.rprimd
            #mat.init.xred  = copy.deepcopy(ins.end.xred)
            #mat.init.typat = copy.deepcopy(ins.end.)
            #print ins.end.xcart
            rprimd = copy.deepcopy(mat.init.rprimd)
            #build    = mat.build
            mat.init = copy.deepcopy(ins.end)
            #mat.build = build
            mat.init.rprimd = rprimd  #return initial rprimd
            mat.init.xred2xcart()  #calculate xcart with new rprimd

            des = "atoms with reduced coord. from " + ins.name + " was fully copied to " + mat_geofile
            mat.init.name = 'test_insert_xred' + str(mat.version)
            write_xyz(mat.init)

        mat.path["input_geo"] = mat_geopath + it_new + mat_filename
        if not mat.write_geometry("init", des): continue
        print_and_log("Xred from " + it_ins + " was inserted in " +
                      mat_geofile + " and saved as " + mat_filename + " \n\n")

    return
Пример #6
0
def add_impurity(it_new, impurity_type = None, addtype = 'central', calc = [], r_pore = 0.5,
    it_to = '', ise_to = '', verlist_to = [], copy_geo_from = "", find_close_to = (),add_to_version = 0,
    write_geo = True, only_version = None, fine = 4, put_exactly_to = None, check_pore_vol = 0):

    """
    Add impurities in pores.

    Input:
    it_new - name of new structure with impurity
    
    impurity_type - name of impurity from Mendeley table, for example 'C'
    
    addtype - type of adding: ['central',]; 'central' means that impurity 
    will be placed as close to the geometrical center of cell as possible.
    
    it_to , ise_to , verlist_to - completed calculations in which impurity 
    will be added
    
    if 'verlist_to' is empty, function will try to find geometry files in 'geo_folder + struct_des[it_to].sfolder' folder;
    even if 'it_to' is empty it will try to find files in 'geo_folder + struct_des[it_new].sfolder+'/from' ' folder.
    'ise_to' also can be empty

    if 'copy_geo_from' is not empty, then programm copy all files from folder 'copy_geo_from' to 
    folder 'geo_folder + struct_des[it_to].sfolder+"/"+it_to' or  'geo_folder + struct_des[it_new].sfolder+"/from" '  

    'find_close_to' is tuple of three reduced coordinates of point close to which you want to find impurity. If empty - ignored; 

    'add_to_version' is integer number added to each 'verlist_to' number to produce ver_new.
    
    'only_version' - if == [v,], then instertion will be provided only for v. If None insertion will be made in all found versions

    If you want to add impurity to relaxed structure ...

    'fine' - integer number; allows to reduce number of small steps for defining center


    Possible addtype's:
    'central' - add one atom to the pore which is most close to  the center of the cell but with reduced coordinates less than 0.5 0.5 0.5
    'all_pore'  - add atoms in every found pore
    'all_local' - add atoms to every local point which allows to visualise topology of pores.
    'gb' - uses self.gbpos and places atom close to this value assuming that it will be at gb
    'grain_vol' - uses self.gbpos and assuming that cell contains two gb and two equal grains, places atom close to the centre of grain; y and z can be arbiratry


    put_exactly_to - will add impurity to this point 
    find_close_to - will try to find closest void and insert pore here.

    check_pore_vol - allows to estimate volume of pores; has problems for big cells


    Side effects: creates new geometry folder with input structures; 

    """
    def test_adding_of_impurities(added, init, v):
        """
        Can be used only inside add_impurity()
        Replicates the structure and find again pores
        """
        global natoms_v1
        if added == None: return
        if v == 1: #TEST
            
            natoms_v1 = len(added.init.xcart) # for test 
            st_rep_after  = replic( added.init,      (1,2,1) )

            rep = copy.deepcopy(init)

            rep.init = replic( rep.init, (1,2,1) );   
            #print rep
            rep = add(znucl, "", rep, write_geo = False)
            #print rep
            #print "xcart of replic after adding ", st_rep_after.xcart
            #print "xcart of adding to    replic ", rep.init.xcart
            if len(st_rep_after.xcart) != len(rep.init.xcart): raise RuntimeError
            p = 0
            #for x2 in st_rep_after.xcart:
            #    print x2
            for x in rep.init.xcart:
                a = any(  ( np.around(x2, p) == np.around(x, p) ).all() for x2 in st_rep_after.xcart   )
                #b = any(  ( np.ceil(x2, p)   == np.ceil(x, p)  ).all()  for x2 in st_rep_after.xcart   )
                #c = any(  ( np.floor(x2, p)  == np.floor(x, p) ).all()  for x2 in st_rep_after.xcart   )
                #print a, b, c
                #np.concatenate(a, b, c):
                if not a:
                    print "Can't find ", np.around(x,3), "in replic  "
                    raise RuntimeError

            #assert all([ all( np.around(v1, 8) == np.around(v2, 8) ) for (v1, v2) in zip(st_rep_after.xcart, rep.init.xcart) ])
            print "add_impurity: test succesfully done"

        if natoms_v1 != len(added.init.xcart): print_and_log("You have different number of pores in different versions\n");  raise RuntimeError
        return
    


    def 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"]):
            print_and_log("add: File '"+new.path["input_geo"]+"' already exists; continue\n");
            return new

        #new.init = return_atoms_to_cell(new.init)

        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 'Inmpurity just put in ', pores_xred
        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 "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)

        print "\n"


        return new

    """0.Begin----------------------------------------------------------------------------"""

    znucl = element_name_inv(impurity_type)


    if impurity_type != 'octa' and impurity_type not in it_new:
        print_and_log("add_impurity: Your name 'it_new' is incorrect!\n\n")
        raise RuntimeError
    #del header.history[-2]
    #
    
    #hstring = ("add_impurity('%s', '%s', '%s', calc, %.3f, '%s', '%s', %s, '%s')  #at %s" %
    #    (it_new, impurity_type, addtype, r_pore,
    #        it_to, ise_to, verlist_to, copy_geo_from,
    #     datetime.date.today() ) )
    
    hstring = ("%s    #on %s"% (traceback.extract_stack(None, 2)[0][3],   datetime.date.today() ) )
    if hstring != header.history[-1]: header.history.append( hstring  )


    #geo_exists = 
    





    """1. The case of insertion to existing calculations--------------------------------------------------"""

    if verlist_to:         

        for v in verlist_to:
            if only_version and v not in only_version: continue # only_version = None works for all versions 
            id = (it_to, ise_to, v)
            new = copy.deepcopy(calc[id])

            new.init = new.end #replace init structure by the end structure
            #new.xred = new.init.xred
            #new.xcart = new.init.xcart
            #new.rprimd = new.init.rprimd
            #del new.init.xred[-1]
            #del new.init.xcart[-1]
            #del new.init.typat[-1]
            #new.init.natom -=1
            #print new.init.xred

            #print new.end.xred
            #print new.xred
            #rint new.init.xred
            new.version = v+add_to_version
            new.name = it_new#+'.'+id[1]+'.'+str(id[2])
            new.des = 'Obtained from '+str(id)+' by adding '+impurity_type+' impurity '
            path_new_geo = struct_des[it_new].sfolder+"/"+it_new+"/"+it_new+'.imp.'+addtype+'.'+str(new.version)+'.'+'geo'
            new.init.name = it_new+".init."+str(new.version)
            xyzpath = struct_des[it_new].sfolder+"/"+it_new
            
            new.path["input_geo"] = geo_folder+path_new_geo
            
            print_and_log("File '"+new.path["input_geo"] +"' with impurity will be created\n");
            #new.init.name = 'test_before_add_impurity'

            new = add(znucl, xyzpath, new, write_geo, put_exactly_to = put_exactly_to)

            



        """2. The case of insertion to geo files------------------------------------------------------------"""
    else:     

        

        print_and_log("You does not set 'id' of relaxed calculation. I try to find geometry files in "+it_new+" folder\n")

        if it_to:       geo_path = geo_folder + struct_des[it_to].sfolder  + "/" + it_to
        else:           geo_path = geo_folder + struct_des[it_new].sfolder + "/" + it_new+'/from'
        if copy_geo_from:
            print_and_log("You asked to copy geo files from "+copy_geo_from+" to " +geo_path+ " folder\n") 
            #if not os.path.exists(os.path.dirname(geo_path)): 
            runBash( "mkdir -p "+geo_path ) 
            runBash( "cp "+copy_geo_from+"/* "+geo_path  )




        if os.path.exists(geo_path):
            print_and_log("Folder '"+geo_path +"' was found. Trying to add impurity\n");
        else:
            print_and_log("Error! Folder "+geo_path+" does not exist\n"); raise RuntimeError

        #geofilelist = glob.glob(geo_path+'/*.geo*') #Find input_geofile
        #geofilelist = runBash('find '+geo_path+' -name "*grainA*.geo*" ').splitlines()
        #geofilelist = runBash('find '+geo_path+' -name "*.geo*" ').splitlines()
        geofilelist = glob.glob(geo_path+'/*.geo*')
        print "There are several files here already: ", geofilelist
        #print 'find '+geo_path+' -name "*.geo*" ',geofilelist
        #return


        for input_geofile in geofilelist:

            v = int( runBash("grep version "+str(input_geofile) ).split()[1] )
            
            if only_version and v not in only_version: continue # only_version = None works for all versions 
            
            new = CalculationVasp()
            new.version = v
            new.name = input_geofile
            
            

            new.read_geometry(input_geofile)
            init = copy.deepcopy(new)
            
            igl = input_geofile.split("/")
            #new.name = igl[-3]+'/'+igl[-3] #+input_geofile
            new.name = struct_des[it_new].sfolder+"/"+it_new+"/"+it_new
            print "New path and part of name of file is ", new.name
            #return
            new.des = 'Obtained from '+input_geofile+' by adding '+impurity_type+' impurity '
            #new.init.xred   = new.xred
            #new.init.rprimd = new.rprimd

            #print new.rprimd
            new.init.name = new.name+'.imp.'+addtype+'.'+str(new.version)
            #new.path["input_geo"] = geo_folder+it_new+"/"+new.end.name+'.'+'geo'
            new.path["input_geo"] = geo_folder+"/"+new.init.name+'.'+'geo'
            #new.init.name = 'test_before_add_impurity'
            
            new = add(znucl, "", new, write_geo, put_exactly_to = put_exactly_to)



    return new.path["input_geo"] #return for last version
Пример #7
0
    def write_geometry_files(
        dlist,
        in_calc,
        xcart_pores,
        segtyp,
        take_final_rprimd_from=None,
        add_name_before="",
        tlist=[],
        configver=False,
        add_typat=None,
    ):
        """Creating files
        dlist - list of pairs with distances and numbers
        in_calc - base calculation without pores

        tlist - list of additional atoms in the case of triples; list of structures
        configver - if True each configuration saved as a new version
        add_typat - manually determined; please automatize!
        """

        print "Warning! add_typat", add_typat
        if tlist == []:  # convert dlist to tlist - to do earlier
            for el in dlist:
                config = Structure()
                config.name = el[2]
                config.length = el[0]
                config.typat = add_typat
                config.xcart = [el[7], el[8]]
                tlist.append(config)

        for i, el in enumerate(tlist):  # by all found structures
            print "el name is ", el.name
            stn = copy.deepcopy(in_calc.init)
            calc = copy.deepcopy(in_calc)

            stn.typat.extend(el.typat)
            stn.xcart.extend(el.xcart)

            stn.xred = xcart2xred(stn.xcart, stn.rprimd)

            xcart_check = xred2xcart(stn.xred, stn.rprimd)
            assert len(xcart_check) == len(stn.xcart)  # test

            assert all(
                [all(np.around(v1, 8) == np.around(v2, 8)) for (v1, v2) in zip(stn.xcart, xcart_check)]
            )  # check if xcart2xred(stn.xcart,r) and xred2xcart(stn.xred,r) are working correctly up to the eight digits after

            stn.natom = len(stn.xcart)

            """Adapt new rprimd"""
            print "take final rprimd is ", take_final_rprimd_from
            if take_final_rprimd_from:  # read final rprimd and version
                print "Start to read rprimd and version from " + take_final_rprimd_from
                in_calc_rprimd = CalculationVasp()
                in_calc_rprimd.name = "temp"
                in_calc_rprimd.read_geometry(take_final_rprimd_from)

                stn.rprimd = in_calc_rprimd.init.rprimd
                stn.xcart = xred2xcart(stn.xred, stn.rprimd)

                calc.version = in_calc_rprimd.version
            elif configver:
                calc.version = i + 1

            calc.init = stn

            des = (
                " was obtained by the insertion of C-O pair into "
                + in_calc_name
                + "; final vectors taken from corresponding ver"
            )

            calc.build.ipairlen = el.length  # Initial length of pair
            if not hasattr(calc.build, "nadded") or calc.build.nadded == None:
                calc.build.nadded = 2
            else:
                calc.build.nadded += 2
            if not hasattr(calc.build, "listadded") or calc.build.listadded == [None]:
                calc.build.listadded = range(stn.natom - 2, stn.natom)  # list of atoms which were added
            else:
                calc.build.listadded.extend(range(stn.natom - 2, stn.natom))

            structure_name = calc.name + el.name.split(".")[0]
            # calc.name = add_name_before+calc.name+ '.' +el[2]+'.'+str(calc.version)
            print "Structure_name", structure_name
            if structure_name in struct_des:

                if configver:
                    fname = structure_name  # calc.name+'C2O2'
                    calc.path["input_geo"] = (
                        geo_folder
                        + struct_des[fname].sfolder
                        + "/"
                        + fname
                        + "/"
                        + structure_name
                        + "."
                        + segtyp
                        + "."
                        + str(calc.version)
                        + ".geo"
                    )
                else:
                    calc.path["input_geo"] = (
                        geo_folder
                        + struct_des[structure_name].sfolder
                        + "/"
                        + structure_name
                        + "/"
                        + structure_name
                        + "."
                        + segtyp
                        + "."
                        + str(calc.version)
                        + ".geo"
                    )
                print "write geo to ", calc.path["input_geo"]
                calc.write_geometry("init", des)

            print "write_geometry_files(): name ", el.name
            stn.name = add_name_before + calc.name + "" + str(el.name) + "." + str(calc.version)
            # stn = replic(stn, (1,2,2))
            write_xyz(stn)
            print "__________________________\n\n\n"
        return
Пример #8
0
def add_impurity(it_new,
                 impurity_type=None,
                 addtype='central',
                 calc=[],
                 r_pore=0.5,
                 it_to='',
                 ise_to='',
                 verlist_to=[],
                 copy_geo_from="",
                 find_close_to=(),
                 add_to_version=0,
                 write_geo=True,
                 only_version=None,
                 fine=4,
                 put_exactly_to=None,
                 check_pore_vol=0,
                 replace_atom=None,
                 override=False):
    """
    Add impurities in pores.

    Input:
    it_new - name of new structure with impurity
    
    impurity_type - name of impurity from Mendeley table, for example 'C'
    
    addtype - type of adding: ['central',]; 'central' means that impurity 
    will be placed as close to the geometrical center of cell as possible.
    
    it_to , ise_to , verlist_to - completed calculations in which impurity 
    will be added
    
    if 'verlist_to' is empty, function will try to find geometry files in 'geo_folder + struct_des[it_to].sfolder' folder;
    even if 'it_to' is empty it will try to find files in 'geo_folder + struct_des[it_new].sfolder+'/from' ' folder.
    'ise_to' also can be empty

    if 'copy_geo_from' is not empty, then programm copy all files from folder 'copy_geo_from' to 
    folder 'geo_folder + struct_des[it_to].sfolder+"/"+it_to' or  'geo_folder + struct_des[it_new].sfolder+"/from" '  

    'find_close_to' is tuple of three reduced coordinates of point close to which you want to find impurity. If empty - ignored; 

    'add_to_version' is integer number added to each 'verlist_to' number to produce ver_new.
    
    'only_version' - if == [v,], then instertion will be provided only for v. If None insertion will be made in all found versions

    If you want to add impurity to relaxed structure ...

    'fine' - integer number; allows to reduce number of small steps for defining center


    Possible addtype's:
    'central' - add one atom to the pore which is most close to  the center of the cell but with reduced coordinates less than 0.5 0.5 0.5
    'all_pore'  - add atoms in every found pore
    'all_local' - add atoms to every local point which allows to visualise topology of pores.
    'gb' - uses self.gbpos and places atom close to this value assuming that it will be at gb
    'grain_vol' - uses self.gbpos and assuming that cell contains two gb and two equal grains, places atom close to the centre of grain; y and z can be arbiratry


    put_exactly_to - will add impurity to this point 
    find_close_to - will try to find closest void and insert pore here.

    check_pore_vol - allows to estimate volume of pores; has problems for big cells

    replace_atom - if not None, than the specified atom is substituted


    Side effects: creates new geometry folder with input structures; 

    """

    struct_des = header.struct_des

    def test_adding_of_impurities(added, init, v):
        """
        Can be used only inside add_impurity()
        Replicates the structure and find again pores
        """
        global natoms_v1
        if added == None: return
        if v == 1:  #TEST

            natoms_v1 = len(added.init.xcart)  # for test
            st_rep_after = added.init.replic((1, 2, 1))

            rep = copy.deepcopy(init)

            rep.init = rep.init.replic((1, 2, 1))
            #print rep
            rep = add(znucl, "", rep, write_geo=False)
            #print rep
            #print "xcart of replic after adding ", st_rep_after.xcart
            #print "xcart of adding to    replic ", rep.init.xcart
            if len(st_rep_after.xcart) != len(rep.init.xcart):
                raise RuntimeError
            p = 0
            #for x2 in st_rep_after.xcart:
            #    print x2
            for x in rep.init.xcart:
                a = any((np.around(x2, p) == np.around(x, p)).all()
                        for x2 in st_rep_after.xcart)
                #b = any(  ( np.ceil(x2, p)   == np.ceil(x, p)  ).all()  for x2 in st_rep_after.xcart   )
                #c = any(  ( np.floor(x2, p)  == np.floor(x, p) ).all()  for x2 in st_rep_after.xcart   )
                #print a, b, c
                #np.concatenate(a, b, c):
                if not a:
                    print_and_log("Error! Can't find ", np.around(x, 3),
                                  "in replic  ")
                    raise RuntimeError

            #assert all([ all( np.around(v1, 8) == np.around(v2, 8) ) for (v1, v2) in zip(st_rep_after.xcart, rep.init.xcart) ])
            print_and_log("add_impurity: test succesfully done")

        if natoms_v1 != len(added.init.xcart):
            print_and_log(
                "You have different number of pores in different versions\n")
            raise RuntimeError
        return

    def add(znucl, xyzpath="", new=None, write_geo=True, put_exactly_to=None):
        "if put_exactly_to is True, then atom just added and nothing are searched"

        if write_geo and os.path.exists(
                new.path["input_geo"]) and not override:
            print_and_log("add: File '" + new.path["input_geo"] +
                          "' already exists; continue\n",
                          imp='Y')
            return new

        #new.init = return_atoms_to_cell(new.init)
        if replace_atom:
            #atom substitution
            if znucl not in new.init.znucl:
                new.init.znucl.append(znucl)
                new.init.ntypat += 1
                new.init.typat[replace_atom] = new.init.ntypat
            else:
                ind = new.init.znucl.index(znucl)
                new.init.typat[replace_atom] = ind + 1
            new.init.nznucl = []
            for typ in range(1, new.init.ntypat + 1):
                new.init.nznucl.append(new.init.typat.count(typ))

        else:
            new_before = copy.deepcopy(new)

            # new.init.xcart[-2][0]-=0.9 #was made once manually for c1gCOi10.1
            # new.init.xcart[-2][2]+=0.2
            # new.init.xred = xcart2xred(new.init.xcart, new.init.rprimd)
            write_xyz(new.init)
            #step = 0.042
            step = 0.06
            #r_pore = 0.56
            #fine = 0.3 # for visualisation of pores
            #fine = 4   #controls small steps; the steps are smaller for larger numbers
            #r_pore = 0.54
            prec = 0.004  # precision of center Angs
            if new.hex_a == None:
                r_mat = 1.48 - step
            else:
                r_mat = new.hex_a / 2 - step

            if put_exactly_to:
                pores_xred = [
                    np.array(put_exactly_to),
                ]
                print_and_log('Inmpurity just put in ', pores_xred, imp='Y')
            else:
                pores = find_pores(new.init, r_mat, r_pore, step, fine, prec,
                                   addtype, new.gbpos, find_close_to,
                                   check_pore_vol)  #octahedral
                pores_xred = pores.xred

            npores = len(pores_xred)

            st = new.init

            #delete last oxygen; was made once manually for c1gCOi10.1
            # st.natom-=1
            # del st.xred[-1]
            # del st.typat[-1]

            st.natom += npores
            st.xred.extend(pores_xred)

            if znucl in st.znucl:
                print_and_log("znucl of added impurity is already in cell")
                ind = st.znucl.index(znucl)
                typat = ind + 1
                st.nznucl[ind] += npores
            else:
                st.ntypat += 1
                typat = st.ntypat
                st.znucl.append(znucl)
                st.nznucl.append(npores)

            for i in range(npores):
                st.typat.append(typat)

            st.xred2xcart()

            new.init = st

            #print "Add impurity: len(xred ", len(new.init.xred)
            #print "natom", new.init.natom

            #For automatisation of fit
            try:
                #new.build
                if new.build.nadded == None: new.build.nadded = npores
                else: new.build.nadded += npores
                if new.build.listadded == [None]:
                    new.build.listadded = range(
                        new.natom - npores,
                        new.natom)  #list of atoms which were added
                else:
                    new.build.listadded.extend(
                        range(new.natom - npores, new.natom))
                #print "Warning!!! Information about added impurities rewritten"
            except AttributeError:
                pass

            #new.init.znucl = new.znucl
            #new.init.typat = new.typat

            #write_xyz(replic(new.init, (2,1,2))  , xyzpath)

            #test_adding_of_impurities(new, new_before, v)

            print_and_log("Impurity with Z=" + str(znucl) +
                          " has been added to the found pore in " + new.name +
                          "\n\n")

        if write_geo:
            write_xyz(new.init, xyzpath)
            new.write_geometry("init", new.des, override=override)

        print_and_log("\n")

        return new

    """0.Begin----------------------------------------------------------------------------"""

    znucl = element_name_inv(impurity_type)

    if impurity_type != 'octa' and impurity_type not in it_new:
        print_and_log("add_impurity: Your name 'it_new' is incorrect!\n\n")
        raise RuntimeError
    #del header.history[-2]
    #

    #hstring = ("add_impurity('%s', '%s', '%s', calc, %.3f, '%s', '%s', %s, '%s')  #at %s" %
    #    (it_new, impurity_type, addtype, r_pore,
    #        it_to, ise_to, verlist_to, copy_geo_from,
    #     datetime.date.today() ) )

    hstring = ("%s    #on %s" %
               (traceback.extract_stack(None, 2)[0][3], datetime.date.today()))
    if hstring != header.history[-1]: header.history.append(hstring)

    #geo_exists =
    """1. The case of insertion to existing calculations--------------------------------------------------"""

    if verlist_to:

        for v in verlist_to:
            if only_version and v not in only_version:
                continue  # only_version = None works for all versions
            id = (it_to, ise_to, v)
            new = copy.deepcopy(calc[id])

            new.init = new.end  #replace init structure by the end structure

            new.version = v + add_to_version
            new.name = it_new  #+'.'+id[1]+'.'+str(id[2])
            new.des = 'Obtained from ' + str(
                id) + ' by adding ' + impurity_type + ' impurity '
            path_new_geo = struct_des[
                it_new].sfolder + "/" + it_new + "/" + it_new + '.imp.' + addtype + '.' + str(
                    new.version) + '.' + 'geo'
            new.init.name = it_new + ".init." + str(new.version)
            xyzpath = struct_des[it_new].sfolder + "/" + it_new

            new.path["input_geo"] = geo_folder + path_new_geo

            print_and_log("File '" + new.path["input_geo"] +
                          "' with impurity will be created\n")
            #new.init.name = 'test_before_add_impurity'

            new = add(znucl,
                      xyzpath,
                      new,
                      write_geo,
                      put_exactly_to=put_exactly_to)
        """2. The case of insertion to geo files------------------------------------------------------------"""
    else:
        """ Please rewrite using new functions """

        print_and_log(
            "You does not set 'id' of relaxed calculation. I try to find geometry files in "
            + it_new + " folder\n")

        if it_to:
            geo_path = geo_folder + struct_des[it_to].sfolder + "/" + it_to
        else:
            geo_path = geo_folder + struct_des[
                it_new].sfolder + "/" + it_new + '/from'
        if copy_geo_from:
            print_and_log("You asked to copy geo files from " + copy_geo_from +
                          " to " + geo_path + " folder\n")
            #if not os.path.exists(os.path.dirname(geo_path)):
            runBash("mkdir -p " + geo_path)
            runBash("cp " + copy_geo_from + "/* " + geo_path)

        if os.path.exists(geo_path):
            print_and_log("Folder '" + geo_path +
                          "' was found. Trying to add impurity\n")
        else:
            print_and_log("Error! Folder " + geo_path + " does not exist\n")
            raise RuntimeError

        #geofilelist = glob.glob(geo_path+'/*.geo*') #Find input_geofile
        #geofilelist = runBash('find '+geo_path+' -name "*grainA*.geo*" ').splitlines()
        #geofilelist = runBash('find '+geo_path+' -name "*.geo*" ').splitlines()
        geofilelist = glob.glob(geo_path + '/*.geo*')
        print_and_log("There are several files here already: ",
                      geofilelist,
                      imp='y')
        #print 'find '+geo_path+' -name "*.geo*" ',geofilelist
        #return

        for input_geofile in geofilelist:

            v = int(runBash("grep version " + str(input_geofile)).split()[1])

            if only_version and v not in only_version:
                continue  # only_version = None works for all versions

            new = CalculationVasp()
            new.version = v
            new.name = input_geofile

            new.read_geometry(input_geofile)
            init = copy.deepcopy(new)

            igl = input_geofile.split("/")
            #new.name = igl[-3]+'/'+igl[-3] #+input_geofile
            new.name = struct_des[it_new].sfolder + "/" + it_new + "/" + it_new
            print_and_log("New path and part of name of file is ",
                          new.name,
                          imp='Y')
            #return
            new.des = 'Obtained from ' + input_geofile + ' by adding ' + impurity_type + ' impurity '
            #new.init.xred   = new.xred
            #new.init.rprimd = new.rprimd

            #print new.rprimd
            new.init.name = new.name + '.imp.' + addtype + '.' + str(
                new.version)
            #new.path["input_geo"] = geo_folder+it_new+"/"+new.end.name+'.'+'geo'
            new.path[
                "input_geo"] = geo_folder + "/" + new.init.name + '.' + 'geo'
            #new.init.name = 'test_before_add_impurity'

            new = add(znucl, "", new, write_geo, put_exactly_to=put_exactly_to)

    return new.path["input_geo"]  #return for last version
Пример #9
0
def find_pairs(
    base_name,
    segtyp,
    in_calc,
    central_atoms=[],
    xcart1imp=None,
    input_dlist_coseg=None,
    prec=2,
    gvolume_config_num=None,
    gbpos=None,
    take_final_rprimd_from=None,
    main_path=None,
    based_on=None,
    target_znucl=[22, 6, 8],
    max_dist_between_atoms=4.8,
    add_typat=[2, 3],
):
    """
    Find uniq pairs of atoms and analyse them
    Input:
    
    segtyp - 
    three regimes for cells with grain boundaries:
    'segreg' assumes that in_calc contains carbon atom in grain volume, and creates all cases; 
    'coseg' assumes pure cell and creates only coseg cases.
    cosegregation cases of course should be the same for two regimes, however co-segregation configuations after 'coseg' is more easy to relax.
    'grainvol' - searching for pairs in grain volume

    two regimes for bulk cells:
    'bulk_triple' - used for bulk cells without grain boundaries; first step is searching for pairs, second step for triples.
    'bulk_pairs' - used for bulk cells without grain boundaries; searching for pairs.



    new_name - name of created structures; at first should be added to struct_des[]
    in_calc - Calculation() type or path to geo file
    region - list of numbers which determine region
    central_atoms - list of atoms for which pairs are constructed (Warinig! numbers in new array xcart_pores!);
    - parameter to change mode;

    xcart1imp - coordinates of first interstitial in the  grain interior 

    input_dlist_coseg - list of configurations with cosegregation cases. Needed to construct corresponding segregation cases. the format is quiet tricky

    prec - precision of lengths used to determine unique positions.

    gvolume_config_num - number of configuration with two atoms in grain volume choosen by user (usually should be the most favourable) 

    gbpos - position of grain boundary

    take_final_rprimd_from - path to geo file from which rprimd will be used


    target_znucl - numbers of target atoms

    max_dist_between_atoms - now at least used for 'bulk_pairs' and 'bulk_triple'; maximum length of found pairs.

    add_typat - mannualy set please update

    """

    def write_geometry_files(
        dlist,
        in_calc,
        xcart_pores,
        segtyp,
        take_final_rprimd_from=None,
        add_name_before="",
        tlist=[],
        configver=False,
        add_typat=None,
    ):
        """Creating files
        dlist - list of pairs with distances and numbers
        in_calc - base calculation without pores

        tlist - list of additional atoms in the case of triples; list of structures
        configver - if True each configuration saved as a new version
        add_typat - manually determined; please automatize!
        """

        print "Warning! add_typat", add_typat
        if tlist == []:  # convert dlist to tlist - to do earlier
            for el in dlist:
                config = Structure()
                config.name = el[2]
                config.length = el[0]
                config.typat = add_typat
                config.xcart = [el[7], el[8]]
                tlist.append(config)

        for i, el in enumerate(tlist):  # by all found structures
            print "el name is ", el.name
            stn = copy.deepcopy(in_calc.init)
            calc = copy.deepcopy(in_calc)

            stn.typat.extend(el.typat)
            stn.xcart.extend(el.xcart)

            stn.xred = xcart2xred(stn.xcart, stn.rprimd)

            xcart_check = xred2xcart(stn.xred, stn.rprimd)
            assert len(xcart_check) == len(stn.xcart)  # test

            assert all(
                [all(np.around(v1, 8) == np.around(v2, 8)) for (v1, v2) in zip(stn.xcart, xcart_check)]
            )  # check if xcart2xred(stn.xcart,r) and xred2xcart(stn.xred,r) are working correctly up to the eight digits after

            stn.natom = len(stn.xcart)

            """Adapt new rprimd"""
            print "take final rprimd is ", take_final_rprimd_from
            if take_final_rprimd_from:  # read final rprimd and version
                print "Start to read rprimd and version from " + take_final_rprimd_from
                in_calc_rprimd = CalculationVasp()
                in_calc_rprimd.name = "temp"
                in_calc_rprimd.read_geometry(take_final_rprimd_from)

                stn.rprimd = in_calc_rprimd.init.rprimd
                stn.xcart = xred2xcart(stn.xred, stn.rprimd)

                calc.version = in_calc_rprimd.version
            elif configver:
                calc.version = i + 1

            calc.init = stn

            des = (
                " was obtained by the insertion of C-O pair into "
                + in_calc_name
                + "; final vectors taken from corresponding ver"
            )

            calc.build.ipairlen = el.length  # Initial length of pair
            if not hasattr(calc.build, "nadded") or calc.build.nadded == None:
                calc.build.nadded = 2
            else:
                calc.build.nadded += 2
            if not hasattr(calc.build, "listadded") or calc.build.listadded == [None]:
                calc.build.listadded = range(stn.natom - 2, stn.natom)  # list of atoms which were added
            else:
                calc.build.listadded.extend(range(stn.natom - 2, stn.natom))

            structure_name = calc.name + el.name.split(".")[0]
            # calc.name = add_name_before+calc.name+ '.' +el[2]+'.'+str(calc.version)
            print "Structure_name", structure_name
            if structure_name in struct_des:

                if configver:
                    fname = structure_name  # calc.name+'C2O2'
                    calc.path["input_geo"] = (
                        geo_folder
                        + struct_des[fname].sfolder
                        + "/"
                        + fname
                        + "/"
                        + structure_name
                        + "."
                        + segtyp
                        + "."
                        + str(calc.version)
                        + ".geo"
                    )
                else:
                    calc.path["input_geo"] = (
                        geo_folder
                        + struct_des[structure_name].sfolder
                        + "/"
                        + structure_name
                        + "/"
                        + structure_name
                        + "."
                        + segtyp
                        + "."
                        + str(calc.version)
                        + ".geo"
                    )
                print "write geo to ", calc.path["input_geo"]
                calc.write_geometry("init", des)

            print "write_geometry_files(): name ", el.name
            stn.name = add_name_before + calc.name + "" + str(el.name) + "." + str(calc.version)
            # stn = replic(stn, (1,2,2))
            write_xyz(stn)
            print "__________________________\n\n\n"
        return

    def min_diff(f, list, diffprec):
        """
        calculates difference between one number and list of other numbers. return the index of number with smallest difference.
        if difference is smaller than diffprec returns true as the second argument.  
        """
        # print list
        if list == []:
            return 0, False
        mind = min([abs(f - l) for l in list])
        with_i = np.asarray([abs(f - l) for l in list]).argmin()
        return with_i, (mind < diffprec)

    def pairs(in_calc, xcart_pores, central_atoms, prec=2, max_dist=20, max_dist_from_gb=4, pairtyp="gvol"):
        """
        Searhing for pairs and make list of distances and numbers of atoms
        prec - precision, allows to control which distances can be related to the same configurations
        max_dist - maximum distance between atoms in pair
        max_dist_from_gb - 
        pairtyp - 'gvol' assumes that central_atoms are in the grain volume, 'gb' assumes that central_atoms are in the grain boundary region

        """
        st = in_calc.init
        st_replic = replic(st, (2, 2, 2))
        st_replic = replic(st_replic, (2, 2, 2), -1)  # replic in negative direction also
        r1x = in_calc.rprimd[0][0]
        r3z = in_calc.rprimd[2][2]
        print "Half length of r1x is", r1x / 2

        if segtyp in ["segreg", "coseg", "grainvol"]:
            gbpos2 = in_calc.gbpos
            gbpos1 = gbpos2 - r1x / 2.0
            print "\n\nPositions of boundaries gb1 and gb2", gbpos1, gbpos2
            print "Maximum possible distance between boundary and impurity", r1x / 4
        else:
            gbpos2 = 0
            gbpos1 = 0

        dlist = []
        d1list = []
        d2list = []
        dgb2list = []

        n_neighbours = 8  # number of atoms to calculate sums

        sumrulist = []  # list of sums (sumr1 or sumr2) of unique pores
        unique_pores = []  # the same list but also with coordinates of pores

        sumrlist = []  # list of sumr1+sumr2

        k = 1
        d2diff = 0
        d1diff = 0
        # z1 = 6 #charge of added impurity
        # z2 = 8

        diffprec = 0.02

        # print xcart_pores

        for i, x1 in enumerate(xcart_pores):
            if i not in central_atoms:
                continue
            # iz = z1
            for j, x2 in enumerate(xcart_pores):
                if all(x1 == x2):
                    continue

                d = abs(x2[0] - in_calc.gbpos)
                if pairtyp == "gb" and d > max_dist_from_gb:
                    continue  # second atom is too far from grain boundary

                d1, d2 = image_distance(x1, x2, st.rprimd, 2)  # the minimum distance and the next minimum dist
                if d1 > max_dist:
                    continue
                if (d1, d2) != image_distance(x1, x2, st.rprimd, 3):
                    raise RuntimeError  # test, searching in father images

                # d1 = round(d1,prec)
                # d2 = round(d2,prec)
                dgb1 = round(x2[0] - gbpos1, prec)
                dgb2 = round(gbpos2 - x2[0], prec)

                sumr1 = local_surrounding(x1, st_replic, n_neighbours)  # sum of distances to surrounding atoms
                sumr2 = local_surrounding(x2, st_replic, n_neighbours)
                sumr = sumr2 + sumr1

                if sumr1 not in sumrulist:
                    sumrulist.append(sumr1)
                    unique_pores.append((sumr1, x1))  # determine unique pores

                if sumr2 not in sumrulist:
                    sumrulist.append(sumr2)
                    unique_pores.append((sumr2, x2))  # determine unique pores

                # if d1 in d1list: continue
                if sumr in sumrlist:  # new condition based on sumr
                    ind = sumrlist.index(sumr)
                    i_min, smaller = min_diff(d1, d1list, diffprec)
                    if smaller:
                        continue

                # if 0:#d1list:
                #     i_min, smaller = min_diff(d1, d1list, diffprec)# d1 has the smallest difference with di
                #     #print "exist"
                #     d2diff = abs(d2list[i_min]-d2)
                #     #print abs(d2list[i_min]-d2)
                #     #print central_atoms
                #     if smaller and abs(d2list[i_min]-d2) < diffprec*2  : continue #and abs(dgb2list[i_min]-dgb2) < diffprec

                #     i_min, smaller = min_diff(d2, d2list, diffprec)# d1 has the smallest difference with di
                #     d1diff = abs(d1list[i_min]-d1)
                #     if smaller and abs(d1list[i_min]-d1) < diffprec*2  : continue

                # print "skiped"
                # di, smaller = min_diff(d2, d2list, diffprec)
                # if di != None and smaller: continue
                # if min_diff(d2, d2list, diffprec): continue # be carefull here. this condition can pass some unique configrations; should make additional check like below
                # if d2 in d2list and dgb2list[d2list.index(d2)] == dgb2: continue
                # jz = z2

                sumrlist.append(sumr)
                d1list.append(d1)
                # d2list.append(d2)
                # dgb2list.append(dgb2)

                sym = ""
                if 0:  # mannualy switched off
                    if abs(x1[1] - x2[1]) < diffprec:  # Find symmetry
                        if abs(x1[2] - x2[2]) < diffprec:
                            sym = "ms"  # if y and z are the same, than mirror symmetry
                        elif abs(x1[2] - x2[2]) - r3z < diffprec:
                            sym = "is"  # inverse symmtry
                        elif (
                            abs(x1[2] + x2[2]) - 0.5 * r3z < diffprec
                        ):  # only for t111g; should be extended for general case of existing periods along y or z
                            sym = "is"

                dlist.append(
                    [round(d1, prec), round(d2, prec), sym, sumr1, sumr2, dgb1, dgb2, x1, x2, sumr1, sumr2]
                )  # the first sumr1, sumr2 below replaced by their types

                k += 1

        dlist.sort(key=itemgetter(0))

        unique_pores.sort(key=itemgetter(0))
        sumrulist.sort()
        print "Number of unique pores     is", len(unique_pores)
        print "Pores have the following sums: ", unique_pores

        print "Searching for similar pairs but with different distances ..."
        print "number, d1, d2, name,  sumr1, sumr2, dgb1, dgb2; parallel pair with larger distances"

        bname = element_name_inv(target_znucl[1]) + element_name_inv(target_znucl[2])
        for i, el1 in enumerate(dlist):

            typ1 = sumrulist.index(el1[3]) + 1  # typ of pore of the first atom
            typ2 = sumrulist.index(el1[4]) + 1
            el1[3] = typ1
            el1[4] = typ2

            if pairtyp == "gb":
                dlist[i][2] = bname + "i" + str(i + 1) + "." + str(el1[3]) + "-" + str(el1[4]) + dlist[i][2]

            elif pairtyp == "gvol":
                dlist[i][2] = bname + ".v" + str(i + 1) + dlist[i][2]

            print i + 1, el1[:3], el1[-2:], el1[-6], el1[-5],  # number, d1, d2, name,  sumr1, sumr2, dgb1, dgb2

            for (
                el2
            ) in (
                dlist
            ):  # this loop looks for pairs which are parallel to the same direction as el1 but have larger interdistances

                if el1 == el2:
                    continue

                mod = el2[0] / el1[0] % 1

                if (mod < 0.005 or mod > 0.995) and abs(el1[0] - el2[0]) > dlist[0][
                    0
                ]:  # only multiple distances and if difference is larger than smallest distance
                    # if round(el1[2],prec-1) != round(el2[2],prec-1): continue #In either case the sum the distances should be the same for the same direction
                    if el1[0] == el2[1]:
                        continue
                    print el2[0] / el1[0],  # el2, this pair of atoms is analogus to el1 but have larger interdistance
            print
        print "Total number of structures is", len(dlist)

        if 0:
            print "\n\nSearching for pairs with equal distances by periodic boundary conditions:"
            for el1 in dlist:
                if el1[0] == el1[1]:
                    print el1

            print "\nSearching for pairs with not equal distances by periodic boundary conditions:"
            for el1 in dlist:
                if el1[0] != el1[1]:
                    print el1

            print "\nSearching for pairs with d2/d1>2:"
            for el1 in dlist:
                if el1[1] / el1[0] > 2:
                    print el1

        dlist[0].append(unique_pores)  # last element of dlist[0] is sum and coordinates of unique pores

        return dlist

    """0. BEGIN-------------------------------------------------------------------------------"""

    hstring = "%s    #on %s" % (traceback.extract_stack(None, 2)[0][3], datetime.date.today())
    if hstring != header.history[-1]:
        header.history.append(hstring)

    print_and_log("\n\n------Starting find_pairs()-----------...\n")

    if type(central_atoms) == int:  # not in [tuple, list]:

        central_atoms = [central_atoms]
        # transform to list

    if type(in_calc) == str:
        in_calc_name = in_calc
        in_calc = CalculationVasp()
        # in_calc.name = str(in_calc_name)

        in_calc.name = base_name
        print "in_calc name is ", in_calc.name

        in_calc.read_geometry(in_calc_name)
        if gbpos:
            in_calc.gbpos = gbpos  # rewrite gbpos

        st = in_calc.init
    else:
        """End relaxed structure is used!!!"""
        st = copy.deepcopy(in_calc.end)
        in_calc_name = str(in_calc.id)

    """1. Create separate list of pores and remove them from xcart--------------------------------------------------------"""

    if "hcp_octa_xred":
        in_calc.init.name = segtyp + "_all_pores"
        rep = replic(in_calc.init, (2, 2, 2), -1)
        write_xyz(rep)  # just to check

        """Coordinates of octapores provided in xcart; znucl = 200;"""
        xcart = st.xcart
        typat = st.typat
        st.typat = []
        st.xcart = []
        xcart_pores = []

        # clean structure from pores with z == 200 and construct xcart_pores
        for i, x in enumerate(xcart):
            z = st.znucl[typat[i] - 1]
            if z == 200:
                xcart_pores.append(x)
                # print "Found pore"
            else:
                st.xcart.append(x)
                st.typat.append(typat[i])
        st.natom = len(st.xcart)
        print "Number of found pores with znucl = 200 is ", len(xcart_pores)
        for n in central_atoms:
            if n >= len(xcart_pores):
                raise RuntimeError

    """2. Preprocess segreg and grainvol cases--------------------------------------------------------"""
    # in_calc can be of two types: pure and with C in grain volume; using pure we construct co-segregation cases; using carbon in volume we can construct segregation cases

    if segtyp in ("segreg", "grainvol"):

        if 2 in st.typat:  # impurity in grain volume; (now assume that Carbon)

            iimp = st.typat.index(2)

            xcart1imp = st.xcart[iimp]  # save coordinates of carbon atom

            del st.xcart[iimp]
            del st.typat[iimp]
            st.natom -= 1  # and remove it
            # del st.xred[iimp]
            st.ntypat -= 1
            del st.znucl[1]

            print "Impurity atom was removed from cell"

        if xcart1imp:  # for compatibility with previous cases; better not to use

            imp1 = len(xcart_pores)
            xcart_pores.append(xcart1imp)

            xcart2imp = (
                xcart1imp - 0.5 * st.rprimd[0]
            )  # determine coordinates of second impurity assuming that we have mirror symmetry
            if xcart2imp[0] < 0:
                xcart2imp = xcart1imp + 0.5 * st.rprimd[0]

            imp2 = imp1 + 1
            xcart_pores.append(xcart2imp)

        else:  # new version; both central pores are found in the pure cell!!!

            # We have pure cell here; Find central pore in 1st grain and 2nd grain:
            xcen1 = in_calc.gbpos - 0.25 * st.rprimd[0][0]  # x center of the first grain
            xcen2 = in_calc.gbpos - 0.75 * st.rprimd[0][0]  # z center of the second grain
            # print "xcen", xcen1, xcen2

            d1l = []
            d2l = []
            rpxx05 = st.rprimd[0][0] * 0.5
            for x in xcart_pores:
                d1 = xcen1 - x[0]
                d2 = xcen2 - x[0]
                if d2 < -rpxx05:
                    d2 += st.rprimd[0][0]  # assuming that periodic boundary conditions needed only here

                d1l.append(abs(d1))
                d2l.append(abs(d2))
                # print d1,d2
            imp1 = np.argmin(d1l)  # needed numbers of pores
            imp2 = np.argmin(d2l)
            # print imp1, imp2
            xcart1imp = xcart_pores[imp1]
            xcart2imp = xcart_pores[imp2]
            # print "xcartimp", xcart1imp, xcart2imp

    """3. Define central atoms for segregation and co-segregation cases--------------------------------------------------------"""
    max_dist_from_gb = 100
    if segtyp in ("segreg", "coseg"):

        # central_atoms = []

        max_dist_between_atoms = 4.8
        max_dist_from_gb = 3  # main controls

        for i, x in enumerate(xcart_pores):  # generate central atoms
            d = abs(x[0] - in_calc.gbpos)
            if d < max_dist_from_gb:
                central_atoms.append(i)

    """4. Assume that we always have target_znucl, but only three !!!--------------------------------------------------------"""

    st.znucl = target_znucl  # Please make this part more general
    st.ntypat = len(set(st.znucl))
    print "Warning! Found only ", st.ntypat, "of unique atoms in target_znucl"

    st.xred = xcart2xred(st.xcart, st.rprimd)

    """5. Find segreg and co-segreg cases--------------------------------------------------------"""
    in_calc.init = st

    dlist_coseg = []
    if segtyp == "coseg":
        print "\nStart searching pairs in  gb"
        # main_path = 'T2/CO/' #! please make more general

        dlist_coseg = pairs(
            in_calc, xcart_pores, central_atoms, prec, max_dist_between_atoms, max_dist_from_gb, pairtyp="gb"
        )

        dlist_coseg_exc = []
        for el in copy.deepcopy(dlist_coseg):  # Exchange C and O only for unsymmetrical cases
            if "s" in el[2]:
                continue  # not needed for symmetrical cases
            el[2] = el[2].replace("C", "x")
            el[2] = el[2].replace("O", "C")
            el[2] = el[2].replace("x", "O")
            el[7], el[8] = el[8], el[7]
            el[3], el[4] = el[4], el[3]
            dlist_coseg_exc.append(el)

        for el in dlist_coseg + dlist_coseg_exc:  # Helper
            stname = base_name + el[2]
            path = main_path + base_name + "_coseg"
            print (
                (
                    "struct_des['{0:s}'] = des('{1:s}', 'co-segregation configurations; made from " + based_on + "'   )"
                ).format(stname, path)
            )

        for el in dlist_coseg + dlist_coseg_exc:  # Helper
            stname = base_name + el[2]
            path = main_path + base_name + "_coseg"
            print "add_loop('" + stname + "','" + based_on.split(".")[
                1
            ] + "',range(1,5),calc,conv,varset, 'up1', inherit_option = 'inherit_xred')"

        write_geometry_files(
            dlist_coseg + dlist_coseg_exc, in_calc, xcart_pores, segtyp, take_final_rprimd_from, add_typat=add_typat
        )

    elif segtyp == "segreg":

        """Produce segregation cases only in the case of segreg"""
        print "\nStart producing segragation cases"

        dlist_segreg = []
        # dlist_segreg1 = copy.deepcopy(input_dlist_coseg) #in this case we use input_dlist with co-segragation cases from pure cell.
        # dlist_segreg2 = copy.deepcopy(input_dlist_coseg) #There is small error, because positions of pores at grain boundary
        #                                            #differs in pure cell and cell with impurity in grain volume
        # for i, el in enumerate(input_dlist_coseg):
        #     sym = ''
        #     if   'is' in el[2]: sym = 'is'
        #     elif 'ms' in el[2]: sym = 'ms'
        #     dlist_segreg1[i][7] =  xcart1imp
        #     dlist_segreg1[i][2] = 'CvOi'+str(i+1)+sym

        #     dlist_segreg2[i][8] =  xcart1imp

        #     dlist_segreg2[i][2] = 'CiOv'+str(i+1)+sym

        """new determination based on input_dlist_coseg[0][-1]"""
        el = copy.deepcopy(input_dlist_coseg[0])
        unique = el[-1]  # sums and coordinates of unique pores
        print "unique", unique
        for i, sx in enumerate(unique):
            el[2] = "Ci" + str(i + 1) + "Ov"
            el[7] = sx[1]
            d1, dnext = image_distance(sx[1], xcart1imp, st.rprimd, 2)
            d2, dnext = image_distance(sx[1], xcart2imp, st.rprimd, 2)
            if d1 > d2:
                el[8] = xcart1imp
            else:
                el[8] = xcart2imp  # the farthest impurity in grain volume is used

            dlist_segreg.append(copy.deepcopy(el))

        # dlist_segreg = dlist_segreg1 + dlist_segreg2 #Segregation of the first impurity and of the second

        dlist_segreg_exc = []
        for el in copy.deepcopy(dlist_segreg):  # Exchange C and O only for unsymmetrical cases
            if "s" in el[2]:
                continue  # not needed for symmetrical cases
            el[2] = el[2].replace("C", "x")
            el[2] = el[2].replace("O", "C")
            el[2] = el[2].replace("x", "O")
            el[7], el[8] = el[8], el[7]
            el[3], el[4] = el[4], el[3]
            dlist_segreg_exc.append(el)

        # helper
        for el in dlist_segreg + dlist_segreg_exc:
            stname = base_name + el[2]
            path = main_path + base_name + "_segreg"
            print (
                (
                    "struct_des['{0:s}'] = des('{1:s}', 'co-segregation configurations; made from " + based_on + "'   )"
                ).format(stname, path)
            )

        for el in dlist_segreg + dlist_segreg_exc:
            stname = base_name + el[2]
            path = main_path + base_name + "_segreg"

            print "add_loop('" + stname + "','" + based_on.split(".")[
                1
            ] + "',range(1,5),calc,conv,varset, 'up1', inherit_option = 'inherit_xred')"

        write_geometry_files(
            dlist_segreg + dlist_segreg_exc, in_calc, xcart_pores, segtyp, take_final_rprimd_from, add_typat=add_typat
        )

    """6. Find volume cases--------------------------------------------------------"""
    # this part for construction volume cases
    if segtyp == "grainvol":  # take care that you have only one carbon atom in the grain
        print "\nStart searching pairs in the volume"
        central_atoms = [imp1]
        max_dist_between_atoms = 4.0
        # gvolume_config_num = 0 #please choose manually

        dlist = pairs(
            in_calc, xcart_pores, central_atoms, prec, max_dist_between_atoms, max_dist_from_gb, pairtyp="gvol"
        )

        # dlist = [dlist[0], copy.deepcopy(dlist[gvolume_config_num-1])  ]

        # dlist[0][4] = imp2 #no matter wht was dlist[0]; used for vv case
        dlist.append(copy.deepcopy(dlist[0]))
        dlist[-1][8] = xcart2imp  # last element for both atoms in grain volumes
        dlist[-1][2] = "CvOvms"

        # helper
        for el in dlist:
            stname = base_name + el[2]
            path = main_path + base_name + "_gvol"  # grain volume
            print "add_loop('" + stname + "','" + based_on.split(".")[
                1
            ] + "',range(1,5),calc,conv,varset, 'up1', inherit_option = 'inherit_xred')"

        for el in dlist:
            stname = base_name + el[2]
            path = main_path + base_name + "_gvol"  # grain volume
            print (
                (
                    "struct_des['{0:s}'] = des('{1:s}', 'co-segregation configurations; made from " + based_on + "'   )"
                ).format(stname, path)
            )

        write_geometry_files(dlist, in_calc, xcart_pores, segtyp, take_final_rprimd_from, add_typat=add_typat)

    """. Triple cases--------------------------------------------------------"""

    def triples(addatom=("O", 3), dlist=[], tlist=[], in_calc=None, xcart_pores=[], max_dist_to_next_atom=3):
        """
        Add addatom to all configurations in tlist; 

        addatom[1] - type of atom in typat
        dlist - list of configurations with two impurity atoms; Used if tlist == []; the format of dlist is quiet special
        tlist - list of configurations with arbirtary number of atoms;

        RETURN:
        tlist - list of configurations with add atoms
        """
        st = in_calc.init

        if dlist and tlist == []:
            for el in dlist:
                par = el
                print "pair 1", par,
                x1 = par[7]
                x2 = par[8]
                print "x1 = ", x1
                print "x2 = ", x2
                config = Structure()
                config.xcart = [x1, x2]
                config.typat = [2, 3]
                config.name = el[2]
                tlist.append(config)

        tlist_new = []
        for config in tlist:
            xcart = config.xcart
            typat = config.typat
            name = config.name
            print "\n\n\nStart to adding atom to ", name

            i = 1
            dlistlist = []

            diffprec = 0.001

            [dlistlist.append([]) for x in xcart]
            print len(dlistlist)

            for xpor in xcart_pores:

                skip = True
                for j, x in enumerate(xcart):  # list of 2 or 3 initial atoms to which additional atom will be added
                    if all(np.around(xpor, 5) == np.around(x, 5)):
                        skip = True
                        break

                    d1, d2 = image_distance(x, xpor, st.rprimd, 2)  # the minimum distance and the next minimum dist
                    if d1 > max_dist_to_next_atom:
                        skip = True
                        break  # if only one pore is larger from atom than limit, the pore is skiped

                    # suml = d11+d21+par[0]
                    # for dl in dlistlist:
                    # print 'j is ', j

                    i_min, smaller = min_diff(
                        d1, dlistlist[j], diffprec
                    )  # old condition - bad - removes unique configurations
                    # if smaller: skip = True; continue # symmetrical pores deleted

                    dlistlist[j].append(d1)
                    skip = False  # all conditions are fullfilled - this configuration is unique
                # else:
                # print 'List of distances to atoms'
                if skip:
                    continue  #

                # print "Pore can be used", xpor #sum of distances for triple

                new = Structure()
                new.name = name + addatom[0] + str(i)
                new.xcart = copy.deepcopy(xcart)
                new.xcart.append(xpor)
                new.typat = copy.deepcopy(typat)
                new.typat.append(addatom[1])
                # print 'new.typat  =', new.typat

                # calculate sum of lengths
                new.length = 0
                new.lengthCO = 0
                new.lengthCC = 0
                new.lengthOO = 0
                new.xcartC = []
                new.xcartO = []
                for m, x1 in enumerate(new.xcart):
                    if new.typat[m] == 2:
                        new.xcartC.append(x1)
                    if new.typat[m] == 3:
                        new.xcartO.append(x1)

                    for x2 in new.xcart:
                        d1, d2 = image_distance(x1, x2, st.rprimd, 2)
                        new.length += d1

                for xC in new.xcartC:
                    for xO in new.xcartO:
                        d1, d2 = image_distance(xC, xO, st.rprimd, 2)
                        new.lengthCO += d1

                for xC1 in new.xcartC:
                    for xC2 in new.xcartC:

                        d1, d2 = image_distance(xC1, xC2, st.rprimd, 2)
                        new.lengthCC += d1

                for xO1 in new.xcartO:
                    for xO2 in new.xcartO:

                        d1, d2 = image_distance(xO1, xO2, st.rprimd, 2)
                        new.lengthOO += d1

                skip = False
                n = len(new.xcart)

                """additional conditions to leave only unique configurations"""
                for config in tlist_new:
                    if 1:
                        nr = 0
                        for (v1, t1) in zip(new.xcart, new.typat):
                            for (v2, t2) in zip(config.xcart, config.typat):
                                if all(np.around(v1, 8) == np.around(v2, 8)) and t1 == t2:
                                    nr += 1
                        if nr == n:
                            print "The configurations", new.name, "and", config.name, "consist of the same atoms, continue"
                            skip = True
                            break

                    # print  all([ all( np.around(v1, 8) == np.around(v2, 8) ) for (v1, v2) in zip(new.xcart, config.xcart) ])

                    # check identity using sum of distances
                    # i_min, smaller = min_diff(config.length, [new.length], diffprec)
                    # if smaller:
                    #     print "Configuration ", new.name, "has the same sum of lengths as", config.name
                    i_min, smaller1 = min_diff(config.lengthCO, [new.lengthCO], diffprec)
                    i_min, smaller2 = min_diff(config.lengthCC, [new.lengthCC], diffprec)
                    i_min, smaller3 = min_diff(config.lengthOO, [new.lengthOO], diffprec)
                    # print 'Compare', new.name, config.name, smaller1, smaller2, smaller3
                    if smaller1 and smaller2 and smaller3:
                        print "\nConfiguration ", new.name, "has the same sum of C-O, C-C  and O-O lengths as", config.name
                        print
                        skip = True
                        break

                if skip:
                    continue
                print "\nSum of CO lengths in :", new.name, new.lengthCC, new.lengthOO, new.lengthCO

                tlist_new.append(new)

                i += 1

        return tlist_new

    if segtyp == "bulk_triple" or segtyp == "bulk_pairs":

        # max_dist_between_atoms = 4.8

        print "\nSearching pairs ..."
        dlist = pairs(in_calc, xcart_pores, central_atoms, prec, max_dist_between_atoms, pairtyp="gvol")

    if segtyp == "bulk_pairs":
        write_geometry_files(
            dlist, in_calc, xcart_pores, segtyp, take_final_rprimd_from, configver=True, add_typat=add_typat
        )

    if segtyp == "bulk_triple":

        max_dist_to_next_atom = 5.5
        print "\nSearching triples ..."  # , tlist
        tlist = []
        tlist = triples(("O", 3), dlist, tlist, in_calc, xcart_pores, max_dist_to_next_atom)

        tlist = triples(("C", 2), dlist, tlist, in_calc, xcart_pores, max_dist_to_next_atom)

        write_geometry_files(
            dlist,
            in_calc,
            xcart_pores,
            segtyp,
            take_final_rprimd_from,
            tlist=tlist,
            configver=True,
            add_typat=add_typat,
        )

    return dlist_coseg, xcart_pores
Пример #10
0
    def write_geometry_files(dlist,
                             in_calc,
                             xcart_pores,
                             segtyp,
                             take_final_rprimd_from=None,
                             add_name_before='',
                             tlist=[],
                             configver=False,
                             add_typat=None):
        """Creating files
        dlist - list of pairs with distances and numbers
        in_calc - base calculation without pores

        tlist - list of additional atoms in the case of triples; list of structures
        configver - if True each configuration saved as a new version
        add_typat - manually determined; please automatize!
        """

        print "Warning! add_typat", add_typat
        if tlist == []:  #convert dlist to tlist - to do earlier
            for el in dlist:
                config = Structure()
                config.name = el[2]
                config.length = el[0]
                config.typat = add_typat
                config.xcart = [el[7], el[8]]
                tlist.append(config)

        for i, el in enumerate(tlist):  #by all found structures
            print "el name is ", el.name
            stn = copy.deepcopy(in_calc.init)
            calc = copy.deepcopy(in_calc)

            stn.typat.extend(el.typat)
            stn.xcart.extend(el.xcart)

            stn.xred = xcart2xred(stn.xcart, stn.rprimd)

            xcart_check = xred2xcart(stn.xred, stn.rprimd)
            assert len(xcart_check) == len(stn.xcart)  #test

            assert all(
                [
                    all(np.around(v1, 8) == np.around(v2, 8))
                    for (v1, v2) in zip(stn.xcart, xcart_check)
                ]
            )  #check if xcart2xred(stn.xcart,r) and xred2xcart(stn.xred,r) are working correctly up to the eight digits after

            stn.natom = len(stn.xcart)
            """Adapt new rprimd"""
            print "take final rprimd is ", take_final_rprimd_from
            if take_final_rprimd_from:  #read final rprimd and version
                print "Start to read rprimd and version from " + take_final_rprimd_from
                in_calc_rprimd = CalculationVasp()
                in_calc_rprimd.name = 'temp'
                in_calc_rprimd.read_geometry(take_final_rprimd_from)

                stn.rprimd = in_calc_rprimd.init.rprimd
                stn.xcart = xred2xcart(stn.xred, stn.rprimd)

                calc.version = in_calc_rprimd.version
            elif configver:
                calc.version = i + 1

            calc.init = stn

            des = ' was obtained by the insertion of C-O pair into ' + in_calc_name + '; final vectors taken from corresponding ver'

            calc.build.ipairlen = el.length  # Initial length of pair
            if not hasattr(calc.build, 'nadded') or calc.build.nadded == None:
                calc.build.nadded = 2
            else:
                calc.build.nadded += 2
            if not hasattr(calc.build,
                           'listadded') or calc.build.listadded == [None]:
                calc.build.listadded = range(
                    stn.natom - 2, stn.natom)  #list of atoms which were added
            else:
                calc.build.listadded.extend(range(stn.natom - 2, stn.natom))

            structure_name = calc.name + el.name.split('.')[0]
            #calc.name = add_name_before+calc.name+ '.' +el[2]+'.'+str(calc.version)
            print 'Structure_name', structure_name
            if structure_name in struct_des:

                if configver:
                    fname = structure_name  # calc.name+'C2O2'
                    calc.path["input_geo"] = geo_folder + struct_des[
                        fname].sfolder + '/' + fname + '/' + structure_name + '.' + segtyp + '.' + str(
                            calc.version) + '.geo'
                else:
                    calc.path["input_geo"] = geo_folder + struct_des[
                        structure_name].sfolder + '/' + structure_name + '/' + structure_name + '.' + segtyp + '.' + str(
                            calc.version) + '.geo'
                print "write geo to ", calc.path["input_geo"]
                calc.write_geometry('init', des)

            print "write_geometry_files(): name ", el.name
            stn.name = add_name_before + calc.name + '' + str(
                el.name) + '.' + str(calc.version)
            #stn = replic(stn, (1,2,2))
            write_xyz(stn)
            print "__________________________\n\n\n"
        return
Пример #11
0
def find_pairs(base_name,
               segtyp,
               in_calc,
               central_atoms=[],
               xcart1imp=None,
               input_dlist_coseg=None,
               prec=2,
               gvolume_config_num=None,
               gbpos=None,
               take_final_rprimd_from=None,
               main_path=None,
               based_on=None,
               target_znucl=[22, 6, 8],
               max_dist_between_atoms=4.8,
               add_typat=[2, 3]):
    """
    Find uniq pairs of atoms and analyse them
    Input:
    
    segtyp - 
    three regimes for cells with grain boundaries:
    'segreg' assumes that in_calc contains carbon atom in grain volume, and creates all cases; 
    'coseg' assumes pure cell and creates only coseg cases.
    cosegregation cases of course should be the same for two regimes, however co-segregation configuations after 'coseg' is more easy to relax.
    'grainvol' - searching for pairs in grain volume

    two regimes for bulk cells:
    'bulk_triple' - used for bulk cells without grain boundaries; first step is searching for pairs, second step for triples.
    'bulk_pairs' - used for bulk cells without grain boundaries; searching for pairs.



    new_name - name of created structures; at first should be added to struct_des[]
    in_calc - Calculation() type or path to geo file
    region - list of numbers which determine region
    central_atoms - list of atoms for which pairs are constructed (Warinig! numbers in new array xcart_pores!);
    - parameter to change mode;

    xcart1imp - coordinates of first interstitial in the  grain interior 

    input_dlist_coseg - list of configurations with cosegregation cases. Needed to construct corresponding segregation cases. the format is quiet tricky

    prec - precision of lengths used to determine unique positions.

    gvolume_config_num - number of configuration with two atoms in grain volume choosen by user (usually should be the most favourable) 

    gbpos - position of grain boundary

    take_final_rprimd_from - path to geo file from which rprimd will be used


    target_znucl - numbers of target atoms

    max_dist_between_atoms - now at least used for 'bulk_pairs' and 'bulk_triple'; maximum length of found pairs.

    add_typat - mannualy set please update

    """
    def write_geometry_files(dlist,
                             in_calc,
                             xcart_pores,
                             segtyp,
                             take_final_rprimd_from=None,
                             add_name_before='',
                             tlist=[],
                             configver=False,
                             add_typat=None):
        """Creating files
        dlist - list of pairs with distances and numbers
        in_calc - base calculation without pores

        tlist - list of additional atoms in the case of triples; list of structures
        configver - if True each configuration saved as a new version
        add_typat - manually determined; please automatize!
        """

        print "Warning! add_typat", add_typat
        if tlist == []:  #convert dlist to tlist - to do earlier
            for el in dlist:
                config = Structure()
                config.name = el[2]
                config.length = el[0]
                config.typat = add_typat
                config.xcart = [el[7], el[8]]
                tlist.append(config)

        for i, el in enumerate(tlist):  #by all found structures
            print "el name is ", el.name
            stn = copy.deepcopy(in_calc.init)
            calc = copy.deepcopy(in_calc)

            stn.typat.extend(el.typat)
            stn.xcart.extend(el.xcart)

            stn.xred = xcart2xred(stn.xcart, stn.rprimd)

            xcart_check = xred2xcart(stn.xred, stn.rprimd)
            assert len(xcart_check) == len(stn.xcart)  #test

            assert all(
                [
                    all(np.around(v1, 8) == np.around(v2, 8))
                    for (v1, v2) in zip(stn.xcart, xcart_check)
                ]
            )  #check if xcart2xred(stn.xcart,r) and xred2xcart(stn.xred,r) are working correctly up to the eight digits after

            stn.natom = len(stn.xcart)
            """Adapt new rprimd"""
            print "take final rprimd is ", take_final_rprimd_from
            if take_final_rprimd_from:  #read final rprimd and version
                print "Start to read rprimd and version from " + take_final_rprimd_from
                in_calc_rprimd = CalculationVasp()
                in_calc_rprimd.name = 'temp'
                in_calc_rprimd.read_geometry(take_final_rprimd_from)

                stn.rprimd = in_calc_rprimd.init.rprimd
                stn.xcart = xred2xcart(stn.xred, stn.rprimd)

                calc.version = in_calc_rprimd.version
            elif configver:
                calc.version = i + 1

            calc.init = stn

            des = ' was obtained by the insertion of C-O pair into ' + in_calc_name + '; final vectors taken from corresponding ver'

            calc.build.ipairlen = el.length  # Initial length of pair
            if not hasattr(calc.build, 'nadded') or calc.build.nadded == None:
                calc.build.nadded = 2
            else:
                calc.build.nadded += 2
            if not hasattr(calc.build,
                           'listadded') or calc.build.listadded == [None]:
                calc.build.listadded = range(
                    stn.natom - 2, stn.natom)  #list of atoms which were added
            else:
                calc.build.listadded.extend(range(stn.natom - 2, stn.natom))

            structure_name = calc.name + el.name.split('.')[0]
            #calc.name = add_name_before+calc.name+ '.' +el[2]+'.'+str(calc.version)
            print 'Structure_name', structure_name
            if structure_name in struct_des:

                if configver:
                    fname = structure_name  # calc.name+'C2O2'
                    calc.path["input_geo"] = geo_folder + struct_des[
                        fname].sfolder + '/' + fname + '/' + structure_name + '.' + segtyp + '.' + str(
                            calc.version) + '.geo'
                else:
                    calc.path["input_geo"] = geo_folder + struct_des[
                        structure_name].sfolder + '/' + structure_name + '/' + structure_name + '.' + segtyp + '.' + str(
                            calc.version) + '.geo'
                print "write geo to ", calc.path["input_geo"]
                calc.write_geometry('init', des)

            print "write_geometry_files(): name ", el.name
            stn.name = add_name_before + calc.name + '' + str(
                el.name) + '.' + str(calc.version)
            #stn = replic(stn, (1,2,2))
            write_xyz(stn)
            print "__________________________\n\n\n"
        return

    def min_diff(f, list, diffprec):
        """
        calculates difference between one number and list of other numbers. return the index of number with smallest difference.
        if difference is smaller than diffprec returns true as the second argument.  
        """
        #print list
        if list == []: return 0, False
        mind = min([abs(f - l) for l in list])
        with_i = np.asarray([abs(f - l) for l in list]).argmin()
        return with_i, (mind < diffprec)

    def pairs(in_calc,
              xcart_pores,
              central_atoms,
              prec=2,
              max_dist=20,
              max_dist_from_gb=4,
              pairtyp='gvol'):
        """
        Searhing for pairs and make list of distances and numbers of atoms
        prec - precision, allows to control which distances can be related to the same configurations
        max_dist - maximum distance between atoms in pair
        max_dist_from_gb - 
        pairtyp - 'gvol' assumes that central_atoms are in the grain volume, 'gb' assumes that central_atoms are in the grain boundary region

        """
        st = in_calc.init
        st_replic = replic(st, (2, 2, 2))
        st_replic = replic(st_replic, (2, 2, 2),
                           -1)  #replic in negative direction also
        r1x = in_calc.rprimd[0][0]
        r3z = in_calc.rprimd[2][2]
        print "Half length of r1x is", r1x / 2

        if segtyp in ['segreg', 'coseg', 'grainvol']:
            gbpos2 = in_calc.gbpos
            gbpos1 = gbpos2 - r1x / 2.
            print "\n\nPositions of boundaries gb1 and gb2", gbpos1, gbpos2
            print "Maximum possible distance between boundary and impurity", r1x / 4
        else:
            gbpos2 = 0
            gbpos1 = 0

        dlist = []
        d1list = []
        d2list = []
        dgb2list = []

        n_neighbours = 8  # number of atoms to calculate sums

        sumrulist = []  #list of sums (sumr1 or sumr2) of unique pores
        unique_pores = []  #the same list but also with coordinates of pores

        sumrlist = []  #list of sumr1+sumr2

        k = 1
        d2diff = 0
        d1diff = 0
        #z1 = 6 #charge of added impurity
        #z2 = 8

        diffprec = 0.02

        # print xcart_pores

        for i, x1 in enumerate(xcart_pores):
            if i not in central_atoms: continue
            #iz = z1
            for j, x2 in enumerate(xcart_pores):
                if all(x1 == x2): continue

                d = abs(x2[0] - in_calc.gbpos)
                if pairtyp == 'gb' and d > max_dist_from_gb:
                    continue  #second atom is too far from grain boundary

                d1, d2 = image_distance(
                    x1, x2, st.rprimd,
                    2)  # the minimum distance and the next minimum dist
                if d1 > max_dist: continue
                if (d1, d2) != image_distance(x1, x2, st.rprimd, 3):
                    raise RuntimeError  #test, searching in father images

                #d1 = round(d1,prec)
                #d2 = round(d2,prec)
                dgb1 = round(x2[0] - gbpos1, prec)
                dgb2 = round(gbpos2 - x2[0], prec)

                sumr1 = local_surrounding(
                    x1, st_replic,
                    n_neighbours)  # sum of distances to surrounding atoms
                sumr2 = local_surrounding(x2, st_replic, n_neighbours)
                sumr = sumr2 + sumr1

                if sumr1 not in sumrulist:
                    sumrulist.append(sumr1)
                    unique_pores.append((sumr1, x1))  #determine unique pores

                if sumr2 not in sumrulist:
                    sumrulist.append(sumr2)
                    unique_pores.append((sumr2, x2))  #determine unique pores

                #if d1 in d1list: continue
                if sumr in sumrlist:  # new condition based on sumr
                    ind = sumrlist.index(sumr)
                    i_min, smaller = min_diff(d1, d1list, diffprec)
                    if smaller: continue

                # if 0:#d1list:
                #     i_min, smaller = min_diff(d1, d1list, diffprec)# d1 has the smallest difference with di
                #     #print "exist"
                #     d2diff = abs(d2list[i_min]-d2)
                #     #print abs(d2list[i_min]-d2)
                #     #print central_atoms
                #     if smaller and abs(d2list[i_min]-d2) < diffprec*2  : continue #and abs(dgb2list[i_min]-dgb2) < diffprec

                #     i_min, smaller = min_diff(d2, d2list, diffprec)# d1 has the smallest difference with di
                #     d1diff = abs(d1list[i_min]-d1)
                #     if smaller and abs(d1list[i_min]-d1) < diffprec*2  : continue

                #print "skiped"
                #di, smaller = min_diff(d2, d2list, diffprec)
                #if di != None and smaller: continue
                #if min_diff(d2, d2list, diffprec): continue # be carefull here. this condition can pass some unique configrations; should make additional check like below
                #if d2 in d2list and dgb2list[d2list.index(d2)] == dgb2: continue
                #jz = z2

                sumrlist.append(sumr)
                d1list.append(d1)
                # d2list.append(d2)
                # dgb2list.append(dgb2)

                sym = ''
                if 0:  #mannualy switched off
                    if abs(x1[1] - x2[1]) < diffprec:  #Find symmetry
                        if abs(x1[2] - x2[2]) < diffprec:
                            sym = 'ms'  # if y and z are the same, than mirror symmetry
                        elif abs(x1[2] - x2[2]) - r3z < diffprec:
                            sym = 'is'  # inverse symmtry
                        elif abs(
                                x1[2] + x2[2]
                        ) - 0.5 * r3z < diffprec:  # only for t111g; should be extended for general case of existing periods along y or z
                            sym = 'is'

                dlist.append([
                    round(d1, prec),
                    round(d2, prec), sym, sumr1, sumr2, dgb1, dgb2, x1, x2,
                    sumr1, sumr2
                ])  #the first sumr1, sumr2 below replaced by their types

                k += 1

        dlist.sort(key=itemgetter(0))

        unique_pores.sort(key=itemgetter(0))
        sumrulist.sort()
        print 'Number of unique pores     is', len(unique_pores)
        print 'Pores have the following sums: ', unique_pores

        print "Searching for similar pairs but with different distances ..."
        print "number, d1, d2, name,  sumr1, sumr2, dgb1, dgb2; parallel pair with larger distances"

        bname = element_name_inv(target_znucl[1]) + element_name_inv(
            target_znucl[2])
        for i, el1 in enumerate(dlist):

            typ1 = sumrulist.index(el1[3]) + 1  #typ of pore of the first atom
            typ2 = sumrulist.index(el1[4]) + 1
            el1[3] = typ1
            el1[4] = typ2

            if pairtyp == 'gb':
                dlist[i][2] = bname + 'i' + str(i + 1) + '.' + str(
                    el1[3]) + '-' + str(el1[4]) + dlist[i][2]

            elif pairtyp == 'gvol':
                dlist[i][2] = bname + '.v' + str(i + 1) + dlist[i][2]

            print i + 1, el1[:3], el1[-2:], el1[-6], el1[
                -5],  #number, d1, d2, name,  sumr1, sumr2, dgb1, dgb2

            for el2 in dlist:  #this loop looks for pairs which are parallel to the same direction as el1 but have larger interdistances

                if el1 == el2: continue

                mod = el2[0] / el1[0] % 1

                if (mod < 0.005 or mod > 0.995
                    ) and abs(el1[0] - el2[0]) > dlist[0][
                        0]:  #only multiple distances and if difference is larger than smallest distance
                    #if round(el1[2],prec-1) != round(el2[2],prec-1): continue #In either case the sum the distances should be the same for the same direction
                    if el1[0] == el2[1]: continue
                    print el2[0] / el1[
                        0],  # el2, this pair of atoms is analogus to el1 but have larger interdistance
            print
        print 'Total number of structures is', len(dlist)

        if 0:
            print "\n\nSearching for pairs with equal distances by periodic boundary conditions:"
            for el1 in dlist:
                if el1[0] == el1[1]:
                    print el1

            print "\nSearching for pairs with not equal distances by periodic boundary conditions:"
            for el1 in dlist:
                if el1[0] != el1[1]:
                    print el1

            print "\nSearching for pairs with d2/d1>2:"
            for el1 in dlist:
                if el1[1] / el1[0] > 2:
                    print el1

        dlist[0].append(
            unique_pores
        )  # last element of dlist[0] is sum and coordinates of unique pores

        return dlist

    """0. BEGIN-------------------------------------------------------------------------------"""

    hstring = ("%s    #on %s" %
               (traceback.extract_stack(None, 2)[0][3], datetime.date.today()))
    if hstring != header.history[-1]: header.history.append(hstring)

    print_and_log("\n\n------Starting find_pairs()-----------...\n")

    if type(central_atoms) == int:  #not in [tuple, list]:

        central_atoms = [central_atoms]
        #transform to list

    if type(in_calc) == str:
        in_calc_name = in_calc
        in_calc = CalculationVasp()
        #in_calc.name = str(in_calc_name)

        in_calc.name = base_name
        print "in_calc name is ", in_calc.name

        in_calc.read_geometry(in_calc_name)
        if gbpos: in_calc.gbpos = gbpos  #rewrite gbpos

        st = in_calc.init
    else:
        """End relaxed structure is used!!!"""
        st = copy.deepcopy(in_calc.end)
        in_calc_name = str(in_calc.id)
    """1. Create separate list of pores and remove them from xcart--------------------------------------------------------"""

    if "hcp_octa_xred":
        in_calc.init.name = segtyp + '_all_pores'
        rep = replic(in_calc.init, (2, 2, 2), -1)
        write_xyz(rep)  #just to check
        """Coordinates of octapores provided in xcart; znucl = 200;"""
        xcart = st.xcart
        typat = st.typat
        st.typat = []
        st.xcart = []
        xcart_pores = []

        #clean structure from pores with z == 200 and construct xcart_pores
        for i, x in enumerate(xcart):
            z = st.znucl[typat[i] - 1]
            if z == 200:
                xcart_pores.append(x)
                #print "Found pore"
            else:
                st.xcart.append(x)
                st.typat.append(typat[i])
        st.natom = len(st.xcart)
        print 'Number of found pores with znucl = 200 is ', len(xcart_pores)
        for n in central_atoms:
            if n >= len(xcart_pores):
                raise RuntimeError
    """2. Preprocess segreg and grainvol cases--------------------------------------------------------"""
    # in_calc can be of two types: pure and with C in grain volume; using pure we construct co-segregation cases; using carbon in volume we can construct segregation cases

    if segtyp in ('segreg', 'grainvol'):

        if 2 in st.typat:  # impurity in grain volume; (now assume that Carbon)

            iimp = st.typat.index(2)

            xcart1imp = st.xcart[iimp]  #save coordinates of carbon atom

            del st.xcart[iimp]
            del st.typat[iimp]
            st.natom -= 1  #and remove it
            #del st.xred[iimp]
            st.ntypat -= 1
            del st.znucl[1]

            print "Impurity atom was removed from cell"

        if xcart1imp:  #for compatibility with previous cases; better not to use

            imp1 = len(xcart_pores)
            xcart_pores.append(xcart1imp)

            xcart2imp = xcart1imp - 0.5 * st.rprimd[
                0]  #determine coordinates of second impurity assuming that we have mirror symmetry
            if xcart2imp[0] < 0: xcart2imp = xcart1imp + 0.5 * st.rprimd[0]

            imp2 = imp1 + 1
            xcart_pores.append(xcart2imp)

        else:  #new version; both central pores are found in the pure cell!!!

            #We have pure cell here; Find central pore in 1st grain and 2nd grain:
            xcen1 = in_calc.gbpos - 0.25 * st.rprimd[0][
                0]  #x center of the first grain
            xcen2 = in_calc.gbpos - 0.75 * st.rprimd[0][
                0]  #z center of the second grain
            # print "xcen", xcen1, xcen2

            d1l = []
            d2l = []
            rpxx05 = st.rprimd[0][0] * 0.5
            for x in xcart_pores:
                d1 = xcen1 - x[0]
                d2 = xcen2 - x[0]
                if d2 < -rpxx05:
                    d2 += st.rprimd[0][
                        0]  # assuming that periodic boundary conditions needed only here

                d1l.append(abs(d1))
                d2l.append(abs(d2))
                # print d1,d2
            imp1 = np.argmin(d1l)  #needed numbers of pores
            imp2 = np.argmin(d2l)
            # print imp1, imp2
            xcart1imp = xcart_pores[imp1]
            xcart2imp = xcart_pores[imp2]
            # print "xcartimp", xcart1imp, xcart2imp
    """3. Define central atoms for segregation and co-segregation cases--------------------------------------------------------"""
    max_dist_from_gb = 100
    if segtyp in ('segreg', 'coseg'):

        # central_atoms = []

        max_dist_between_atoms = 4.8
        max_dist_from_gb = 3  #main controls

        for i, x in enumerate(xcart_pores):  #generate central atoms
            d = abs(x[0] - in_calc.gbpos)
            if d < max_dist_from_gb:
                central_atoms.append(i)
    """4. Assume that we always have target_znucl, but only three !!!--------------------------------------------------------"""

    st.znucl = target_znucl  #Please make this part more general
    st.ntypat = len(set(st.znucl))
    print 'Warning! Found only ', st.ntypat, 'of unique atoms in target_znucl'

    st.xred = xcart2xred(st.xcart, st.rprimd)
    """5. Find segreg and co-segreg cases--------------------------------------------------------"""
    in_calc.init = st

    dlist_coseg = []
    if segtyp == 'coseg':
        print "\nStart searching pairs in  gb"
        # main_path = 'T2/CO/' #! please make more general

        dlist_coseg = pairs(in_calc,
                            xcart_pores,
                            central_atoms,
                            prec,
                            max_dist_between_atoms,
                            max_dist_from_gb,
                            pairtyp='gb')

        dlist_coseg_exc = []
        for el in copy.deepcopy(
                dlist_coseg):  #Exchange C and O only for unsymmetrical cases
            if 's' in el[2]: continue  # not needed for symmetrical cases
            el[2] = el[2].replace('C', 'x')
            el[2] = el[2].replace('O', 'C')
            el[2] = el[2].replace('x', 'O')
            el[7], el[8] = el[8], el[7]
            el[3], el[4] = el[4], el[3]
            dlist_coseg_exc.append(el)

        for el in dlist_coseg + dlist_coseg_exc:  # Helper
            stname = base_name + el[2]
            path = main_path + base_name + '_coseg'
            print((
                "struct_des['{0:s}'] = des('{1:s}', 'co-segregation configurations; made from "
                + based_on + "'   )").format(stname, path))

        for el in dlist_coseg + dlist_coseg_exc:  # Helper
            stname = base_name + el[2]
            path = main_path + base_name + '_coseg'
            print "add_loop('" + stname + "','" + based_on.split(
                '.'
            )[1] + "',range(1,5),calc,conv,varset, 'up1', inherit_option = 'inherit_xred')"

        write_geometry_files(dlist_coseg + dlist_coseg_exc,
                             in_calc,
                             xcart_pores,
                             segtyp,
                             take_final_rprimd_from,
                             add_typat=add_typat)

    elif segtyp == 'segreg':
        """Produce segregation cases only in the case of segreg"""
        print "\nStart producing segragation cases"

        dlist_segreg = []
        # dlist_segreg1 = copy.deepcopy(input_dlist_coseg) #in this case we use input_dlist with co-segragation cases from pure cell.
        # dlist_segreg2 = copy.deepcopy(input_dlist_coseg) #There is small error, because positions of pores at grain boundary
        #                                            #differs in pure cell and cell with impurity in grain volume
        # for i, el in enumerate(input_dlist_coseg):
        #     sym = ''
        #     if   'is' in el[2]: sym = 'is'
        #     elif 'ms' in el[2]: sym = 'ms'
        #     dlist_segreg1[i][7] =  xcart1imp
        #     dlist_segreg1[i][2] = 'CvOi'+str(i+1)+sym

        #     dlist_segreg2[i][8] =  xcart1imp

        #     dlist_segreg2[i][2] = 'CiOv'+str(i+1)+sym
        """new determination based on input_dlist_coseg[0][-1]"""
        el = copy.deepcopy(input_dlist_coseg[0])
        unique = el[-1]  #sums and coordinates of unique pores
        print "unique", unique
        for i, sx in enumerate(unique):
            el[2] = 'Ci' + str(i + 1) + 'Ov'
            el[7] = sx[1]
            d1, dnext = image_distance(sx[1], xcart1imp, st.rprimd, 2)
            d2, dnext = image_distance(sx[1], xcart2imp, st.rprimd, 2)
            if d1 > d2:
                el[8] = xcart1imp
            else:
                el[8] = xcart2imp  # the farthest impurity in grain volume is used

            dlist_segreg.append(copy.deepcopy(el))

        #dlist_segreg = dlist_segreg1 + dlist_segreg2 #Segregation of the first impurity and of the second

        dlist_segreg_exc = []
        for el in copy.deepcopy(
                dlist_segreg):  #Exchange C and O only for unsymmetrical cases
            if 's' in el[2]: continue  # not needed for symmetrical cases
            el[2] = el[2].replace('C', 'x')
            el[2] = el[2].replace('O', 'C')
            el[2] = el[2].replace('x', 'O')
            el[7], el[8] = el[8], el[7]
            el[3], el[4] = el[4], el[3]
            dlist_segreg_exc.append(el)

        #helper
        for el in dlist_segreg + dlist_segreg_exc:
            stname = base_name + el[2]
            path = main_path + base_name + '_segreg'
            print((
                "struct_des['{0:s}'] = des('{1:s}', 'co-segregation configurations; made from "
                + based_on + "'   )").format(stname, path))

        for el in dlist_segreg + dlist_segreg_exc:
            stname = base_name + el[2]
            path = main_path + base_name + '_segreg'

            print "add_loop('" + stname + "','" + based_on.split(
                '.'
            )[1] + "',range(1,5),calc,conv,varset, 'up1', inherit_option = 'inherit_xred')"

        write_geometry_files(dlist_segreg + dlist_segreg_exc,
                             in_calc,
                             xcart_pores,
                             segtyp,
                             take_final_rprimd_from,
                             add_typat=add_typat)
    """6. Find volume cases--------------------------------------------------------"""
    # this part for construction volume cases
    if segtyp == "grainvol":  #take care that you have only one carbon atom in the grain
        print "\nStart searching pairs in the volume"
        central_atoms = [imp1]
        max_dist_between_atoms = 4.
        #gvolume_config_num = 0 #please choose manually

        dlist = pairs(in_calc,
                      xcart_pores,
                      central_atoms,
                      prec,
                      max_dist_between_atoms,
                      max_dist_from_gb,
                      pairtyp='gvol')

        #dlist = [dlist[0], copy.deepcopy(dlist[gvolume_config_num-1])  ]

        #dlist[0][4] = imp2 #no matter wht was dlist[0]; used for vv case
        dlist.append(copy.deepcopy(dlist[0]))
        dlist[-1][8] = xcart2imp  #last element for both atoms in grain volumes
        dlist[-1][2] = 'CvOvms'

        #helper
        for el in dlist:
            stname = base_name + el[2]
            path = main_path + base_name + '_gvol'  #grain volume
            print "add_loop('" + stname + "','" + based_on.split(
                '.'
            )[1] + "',range(1,5),calc,conv,varset, 'up1', inherit_option = 'inherit_xred')"

        for el in dlist:
            stname = base_name + el[2]
            path = main_path + base_name + '_gvol'  #grain volume
            print((
                "struct_des['{0:s}'] = des('{1:s}', 'co-segregation configurations; made from "
                + based_on + "'   )").format(stname, path))

        write_geometry_files(dlist,
                             in_calc,
                             xcart_pores,
                             segtyp,
                             take_final_rprimd_from,
                             add_typat=add_typat)
    """. Triple cases--------------------------------------------------------"""

    def triples(addatom=('O', 3),
                dlist=[],
                tlist=[],
                in_calc=None,
                xcart_pores=[],
                max_dist_to_next_atom=3):
        """
        Add addatom to all configurations in tlist; 

        addatom[1] - type of atom in typat
        dlist - list of configurations with two impurity atoms; Used if tlist == []; the format of dlist is quiet special
        tlist - list of configurations with arbirtary number of atoms;

        RETURN:
        tlist - list of configurations with add atoms
        """
        st = in_calc.init

        if dlist and tlist == []:
            for el in dlist:
                par = el
                print 'pair 1', par,
                x1 = par[7]
                x2 = par[8]
                print 'x1 = ', x1
                print 'x2 = ', x2
                config = Structure()
                config.xcart = [x1, x2]
                config.typat = [2, 3]
                config.name = el[2]
                tlist.append(config)

        tlist_new = []
        for config in tlist:
            xcart = config.xcart
            typat = config.typat
            name = config.name
            print '\n\n\nStart to adding atom to ', name

            i = 1
            dlistlist = []

            diffprec = 0.001

            [dlistlist.append([]) for x in xcart]
            print len(dlistlist)

            for xpor in xcart_pores:

                skip = True
                for j, x in enumerate(
                        xcart
                ):  # list of 2 or 3 initial atoms to which additional atom will be added
                    if all(np.around(xpor, 5) == np.around(x, 5)):
                        skip = True
                        break

                    d1, d2 = image_distance(
                        x, xpor, st.rprimd,
                        2)  # the minimum distance and the next minimum dist
                    if d1 > max_dist_to_next_atom:
                        skip = True
                        break  #if only one pore is larger from atom than limit, the pore is skiped

                    # suml = d11+d21+par[0]
                    # for dl in dlistlist:
                    # print 'j is ', j

                    i_min, smaller = min_diff(
                        d1, dlistlist[j], diffprec
                    )  #old condition - bad - removes unique configurations
                    #if smaller: skip = True; continue # symmetrical pores deleted

                    dlistlist[j].append(d1)
                    skip = False  # all conditions are fullfilled - this configuration is unique
                # else:
                # print 'List of distances to atoms'
                if skip: continue  #

                #print "Pore can be used", xpor #sum of distances for triple

                new = Structure()
                new.name = name + addatom[0] + str(i)
                new.xcart = copy.deepcopy(xcart)
                new.xcart.append(xpor)
                new.typat = copy.deepcopy(typat)
                new.typat.append(addatom[1])
                # print 'new.typat  =', new.typat

                #calculate sum of lengths
                new.length = 0
                new.lengthCO = 0
                new.lengthCC = 0
                new.lengthOO = 0
                new.xcartC = []
                new.xcartO = []
                for m, x1 in enumerate(new.xcart):
                    if new.typat[m] == 2: new.xcartC.append(x1)
                    if new.typat[m] == 3: new.xcartO.append(x1)

                    for x2 in new.xcart:
                        d1, d2 = image_distance(x1, x2, st.rprimd, 2)
                        new.length += d1

                for xC in new.xcartC:
                    for xO in new.xcartO:
                        d1, d2 = image_distance(xC, xO, st.rprimd, 2)
                        new.lengthCO += d1

                for xC1 in new.xcartC:
                    for xC2 in new.xcartC:

                        d1, d2 = image_distance(xC1, xC2, st.rprimd, 2)
                        new.lengthCC += d1

                for xO1 in new.xcartO:
                    for xO2 in new.xcartO:

                        d1, d2 = image_distance(xO1, xO2, st.rprimd, 2)
                        new.lengthOO += d1

                skip = False
                n = len(new.xcart)
                """additional conditions to leave only unique configurations"""
                for config in tlist_new:
                    if 1:
                        nr = 0
                        for (v1, t1) in zip(new.xcart, new.typat):
                            for (v2, t2) in zip(config.xcart, config.typat):
                                if all(np.around(v1, 8) == np.around(
                                        v2, 8)) and t1 == t2:
                                    nr += 1
                        if nr == n:
                            print "The configurations", new.name, 'and', config.name, 'consist of the same atoms, continue'
                            skip = True
                            break

                    # print  all([ all( np.around(v1, 8) == np.around(v2, 8) ) for (v1, v2) in zip(new.xcart, config.xcart) ])

                    #check identity using sum of distances
                    # i_min, smaller = min_diff(config.length, [new.length], diffprec)
                    # if smaller:
                    #     print "Configuration ", new.name, "has the same sum of lengths as", config.name
                    i_min, smaller1 = min_diff(config.lengthCO, [new.lengthCO],
                                               diffprec)
                    i_min, smaller2 = min_diff(config.lengthCC, [new.lengthCC],
                                               diffprec)
                    i_min, smaller3 = min_diff(config.lengthOO, [new.lengthOO],
                                               diffprec)
                    # print 'Compare', new.name, config.name, smaller1, smaller2, smaller3
                    if smaller1 and smaller2 and smaller3:
                        print "\nConfiguration ", new.name, "has the same sum of C-O, C-C  and O-O lengths as", config.name
                        print
                        skip = True
                        break

                if skip: continue
                print '\nSum of CO lengths in :', new.name, new.lengthCC, new.lengthOO, new.lengthCO

                tlist_new.append(new)

                i += 1

        return tlist_new

    if segtyp == "bulk_triple" or segtyp == "bulk_pairs":

        # max_dist_between_atoms = 4.8

        print "\nSearching pairs ..."
        dlist = pairs(in_calc,
                      xcart_pores,
                      central_atoms,
                      prec,
                      max_dist_between_atoms,
                      pairtyp='gvol')

    if segtyp == "bulk_pairs":
        write_geometry_files(dlist,
                             in_calc,
                             xcart_pores,
                             segtyp,
                             take_final_rprimd_from,
                             configver=True,
                             add_typat=add_typat)

    if segtyp == "bulk_triple":

        max_dist_to_next_atom = 5.5
        print "\nSearching triples ..."  #, tlist
        tlist = []
        tlist = triples(('O', 3), dlist, tlist, in_calc, xcart_pores,
                        max_dist_to_next_atom)

        tlist = triples(('C', 2), dlist, tlist, in_calc, xcart_pores,
                        max_dist_to_next_atom)

        write_geometry_files(dlist,
                             in_calc,
                             xcart_pores,
                             segtyp,
                             take_final_rprimd_from,
                             tlist=tlist,
                             configver=True,
                             add_typat=add_typat)

    return dlist_coseg, xcart_pores
Пример #12
0
def get_from_database(x1,
                      x2,
                      mat,
                      inquiry_keys=None,
                      silent=None,
                      ssh_object=None):
    """
    inquiry_keys (list) - list of keys that should exist in filenames both for x1 and x2
    ssh_object (SSHTools) - ssh object based on paramiko with access details

    """
    from classes import CalculationVasp

    def check(key, inquiry_keys):
        return all([k in key for k in inquiry_keys])

    path2database = '/home/Data/CEStorage/'

    hash_dict_file = 'hash_dict.json'

    cluster_path2hash = os.path.join(path2database, hash_dict_file)

    if inquiry_keys is None:
        inquiry_keys = []

    if ssh_object:
        # ssh_object.get()
        tempdir = tempfile.gettempdir()
        local_path2hash = os.path.join(tempdir, hash_dict_file)

        ssh_object.get(cluster_path2hash, local_path2hash)

        # sys.exit()

    with open(local_path2hash, 'r') as fp:
        hash_dict = json.load(fp)

    # print(hash_dict)
    x1s = []
    x2s = []
    # print(hash_dict)
    for key, val in hash_dict.items():
        if check(key, inquiry_keys + [x1, mat]):
            x1s.append(key)

        if check(key, inquiry_keys + [x2, mat]):
            x2s.append(key)

    x1s = sorted(x1s, key=lambda el: len(el))
    x2s = sorted(x2s, key=lambda el: len(el))

    for xi, xis in (x1, x1s), (x2, x2s):
        if not silent:
            print('\nFiles for', xi, ':')
        for i, f in enumerate(xis):
            if not silent:

                print(i + 1, f)

    if len(x1s) == 0 or len(x2s) == 0:
        print('No information in database for this inquire:', x1, x2, mat,
              str(inquiry_keys))
        return None, None

    key1 = x1s[0]
    key2 = x2s[0]

    if not silent:

        print('\nI choose first entries for both concentrations:', key1, 'and',
              key2, '\n')
    # print('Use *inquiry_keys* arg to clarify the output results.\n')

    #get files
    loc1 = os.path.join(tempdir, hash_dict[key1])
    loc2 = os.path.join(tempdir, hash_dict[key2])
    makedir(loc1)
    makedir(loc2)
    # print()/

    ssh_object.get(os.path.join(path2database, hash_dict[key1]), loc1)
    ssh_object.get(os.path.join(path2database, hash_dict[key2]), loc2)

    cl1 = CalculationVasp().deserialize(loc1)
    cl2 = CalculationVasp().deserialize(loc2)

    return cl1, cl2
Пример #13
0
if 1:
    walk = os.walk(path2database)
    materials = next(walk)[1]
    # print(materials)
    hash_dict = {}
    for mat in walk:
        for outcar in mat[2]:
            if '.out' in outcar:
                mat_folder = os.path.relpath(mat[0], path2database)
                # print(mat_folder)

                iid = outcar.replace('.out', '')

                pickle_file = os.path.join(mat_folder, 'bin', iid)
                if not os.path.isfile(pickle_file + '.pickle'):
                    cl = CalculationVasp(
                        output=os.path.join(mat_folder, outcar))
                    # print(cl.path['output'])
                    cl.read_results()
                    # material = os.path.basename(mat_folder)
                    # print(mat_folder, material)
                    material = mat_folder.split('/')[0]
                    # print(mat_folder.split('/')[0])
                    cl.name = material

                    print(pickle_file)
                    pickle_file = cl.serialize(
                        os.path.join(mat_folder, 'bin', iid))
                else:
                    print('pickle file', pickle_file, 'exist')
                # concentr = outcar.split('_')[0]
                # hash_dict[material+'_'+iid] = pickle_file