Exemple #1
0
    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_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
Exemple #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
Exemple #3
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 
Exemple #4
0
def local_surrounding(x_central,
                      st,
                      n_neighbours,
                      control='sum',
                      periodic=False,
                      only_elements=None,
                      only_numbers=None,
                      round_flag=1):
    """
    Return list of distances to n closest atoms around central atom. (By defauld sum of distances)
    
    Input:
    - x_central - cartesian coordinates of central atom; vector
    - st - structure with xcart list of coordinates of all atoms in system
    - n_neighbours - number of needed closest neighbours

    - control - type of output; 
              sum - sum of distances, 
              av - average distance, 
              avsq - average squared dist
              'mavm': #min, av, max, av excluding min and max
              av_dev - return (average deviation, maximum deviation) from average distance in mA.
              list - list of distances; 
              atoms  - coordinates of neighbours

    - periodic - if True, then cell is additionaly replicated; needed for small cells
    Only for control = atoms
        - *only_elements* - list of z of elements to which only the distances are needed; 
        - only_numbers  (list of int) - calc dist only to this atoms 

    round_flag (bool) - if 1 than reduce distance prec to 2 points


    #TODO:
    the periodic boundary conditions realized very stupid by replicating the cell!

    """
    # round_orig = round
    if not round_flag:
        # overwrite round function with wrapper that do nothing
        def my_round(a, b):
            return a
    else:
        my_round = round

    def av_dev():
        nonlocal n_neighbours
        n_neighbours = float(n_neighbours)
        dav = sum(dlistnn) / n_neighbours
        av_dev = sum([abs(d - dav) for d in dlistnn]) / n_neighbours
        max_dev = max([abs(d - dav) for d in dlistnn])

        return my_round(av_dev * 1000, 0), my_round(max_dev * 1000, 0)

    st_original = copy.deepcopy(st)
    st.init_numbers = None
    if periodic:
        st = replic(st, mul=(2, 2, 2),
                    inv=1)  # to be sure that impurity is surrounded by atoms
        st = replic(st, mul=(2, 2, 2), inv=-1)

    xcart = st.xcart
    typat = st.typat
    natom = st.natom
    # print x_central

    #print len(xcart)
    if only_elements:
        only_elements = list(set(only_elements))
        # print(only_elements)
        # sys.exit()

    zlist = [int(st.znucl[t - 1]) for t in st.typat]

    dlist_unsort = [np.linalg.norm(x_central - x) for x in xcart
                    ]  # if all (x != x_central)] # list of all distances

    if only_elements:
        dlist = [
            np.linalg.norm(x_central - x) for x, z in zip(xcart, zlist)
            if z in only_elements
        ]
    else:
        dlist = copy.deepcopy(dlist_unsort)
    dlist.sort()
    # print('local_surrounding(): dlist', dlist)

    if len(dlist) > 0 and abs(dlist[0]) < 0.01:
        dlistnn = dlist[1:n_neighbours +
                        1]  #without first impurity which is x_central
    else:
        dlistnn = dlist[:n_neighbours]

    # print('dlistnn', dlistnn)
    # os._exit(1)

    if control == 'list':
        output = dlistnn

    elif control == 'sum':

        output = my_round(sum(dlistnn), 2)

    elif control == 'av':
        n_neighbours = float(n_neighbours)
        dav = sum(dlistnn) / n_neighbours
        output = my_round(dav, 2)

    elif control == 'avsq':
        n_neighbours = float(n_neighbours)
        # print(dlistnn)
        davsq = sum([d * d for d in dlistnn]) / n_neighbours
        davsq = davsq**(0.5)
        output = my_round(davsq, 2)

    elif control == 'mavm':  #min, av, max
        dsort = sorted(dlistnn)
        if n_neighbours > 2:
            output = (my_round(dsort[0],
                               2), sum(dsort[1:-1]) / (n_neighbours - 2),
                      my_round(dsort[-1],
                               2))  #min, av excluding min and max, max
        else:
            output = (my_round(dsort[0], 2), 0, my_round(dsort[-1], 2)
                      )  #min, av excluding min and max, max

    elif control == 'av_dev':
        output = av_dev()

    elif control == 'sum_av_dev':
        output = (my_round(sum(dlistnn), 2), av_dev())

    elif control == 'atoms':
        # print dlist_unsort
        if hasattr(st, 'init_numbers') and st.init_numbers:
            numbers = st.init_numbers
        else:
            numbers = range(natom)
        temp = list(zip(dlist_unsort, xcart, typat, numbers, zlist))

        temp.sort(key=itemgetter(0))

        if only_elements:
            centr_type = temp[0][4]
            if centr_type in only_elements:
                first = []
            else:
                first = temp[0:1]
            temp = first + [
                t for t in temp if t[4] in only_elements
            ]  #including central; included ionce even if only elements are and central are the same

        if only_numbers:
            temp = temp[0:1] + [t for t in temp if t[3] in only_numbers]

        temp2 = list(zip(*temp))
        dlist = temp2[0][:n_neighbours + 1]
        xcart_local = temp2[1][:n_neighbours + 1]
        typat_local = temp2[2][:n_neighbours + 1]
        numbers = temp2[3][:n_neighbours + 1]
        # print temp2[0][:n_neighbours]
        # print xcart_local[:n_neighbours]

        #check if atoms in output are from neighboring cells
        if 0:
            xred_local = xcart2xred(xcart_local, st_original.rprimd)
            # print 'xred_local', xred_local
            for x_l in xred_local:
                for i, x in enumerate(x_l):
                    if x > 1:
                        x_l[i] -= 1
                        # print 'returning to prim cell', x,x_l[i]
                    if x < 0:
                        x_l[i] += 1
                        # print 'returning to prim cell', x,x_l[i]
            xcart_local = xred2xcart(xred_local, st_original.rprimd)

        # print 'Warning! local_surrounding() can return several atoms in one position due to incomplete PBC implementation; Improve please\n'

        output = (xcart_local, typat_local, numbers, dlist)

    return output
Exemple #5
0
def write_xyz(st=None,
              path=None,
              filename=None,
              file_name=None,
              include_vectors=True,
              repeat=1,
              shift_2view=1.0,
              replications=None,
              full_cell=False,
              analysis=None,
              show_around=None,
              show_around_x=None,
              nnumber=6,
              only_elements=None,
              gbpos2=None,
              gbwidth=1,
              withgb=False,
              include_boundary=2,
              imp_positions=[],
              imp_sub_positions=None,
              jmol=None,
              specialcommand=None,
              jmol_args=None,
              sts=None):
    """Writes st structure in xyz format in the folder xyz/path

    if repeat == 2: produces jmol script
    shift_2view - in rprimd[1][1] - shift of the second view
    gbpos2 - position of grain boundary in A
    gbwidth - atoms aroung gbpos2 will be colored differently

    imp_positions - (x1,x2,x3, element, label)- xcart and element name coordinates additionally to be added to structure; to visulaze all impurity positions: for jmol, additional key 's', 'i' can be added after element
    imp_sub_positions - list of atom numbers; the typat of these atoms is changed: not used now


    analysis - additional processing, allows to show only specifice atoms, 
        'imp_surrounding' - shows Ti atoms only around impurity
        nnumber - number of neighbours to show
        show_around - choose atom number around which to show, from 1
        show_around_x - show atoms around point, has higher priority
        only_elements - see local_surrounding

    replications - list of replications, (2,2,2) 

    full_cell - returns atoms to cell and replicate boundary atoms

    include_vectors (bool) - write primitive vectors to xyz

    jmol - 1,0 -  use jmol to produce png picture
    jmol_args - see write_jmol()

    specialcommand - any command at the end of jmol script


    sts - list of Structure - write several structures to xyz file - other options are not working in this regime
    """

    if jmol_args == None:
        jmol_args = {}

    if st == None:
        st = sts[0]

    if replications:
        st = replic(st, mul=replications, inv=1)

    def update_var(st):
        if st.natom != len(st.xred) != len(st.xcart) != len(st.typat) or len(
                st.znucl) != max(st.typat):
            printlog("Error! write_xyz: check your arrays.\n\n")

        if st.xcart == [] or len(st.xcart) != len(st.xred):
            printlog(
                "Warining! write_xyz: len(xcart) != len(xred) making xcart from xred.\n"
            )
            st.xcart = xred2xcart(st.xred, st.rprimd)
            #print xcart[1]

        return st.rprimd, st.xcart, st.xred, st.typat, st.znucl, len(st.xred)

    rprimd, xcart, xred, typat, znucl, natom = update_var(st)

    if file_name:
        name = file_name
    elif filename:
        name = filename
    else:
        name = st.name

    if sts:
        name += '_traj'

    printlog("write_xyz(): Name is", name, important='n')

    if name == '':
        name = 'noname'

    if path:
        basepath = path
    else:
        basepath = 'xyz/'

    suf = ''
    """Processing section"""

    if analysis == 'imp_surrounding':

        if show_around == 0:
            printlog('Error! number of atom *show_around* should start from 1')

        suf = '_loc' + str(show_around)
        lxcart = []
        ltypat = []
        i = 0

        if is_list_like(show_around_x):
            x = show_around_x
            x_t = local_surrounding(x,
                                    st,
                                    nnumber,
                                    control='atoms',
                                    periodic=True,
                                    only_elements=only_elements)
            # print('write_xyz: local_surround:', x_t)
            lxcart += x_t[0]
            ltypat += x_t[1]
        else:

            for t, x in zip(typat, xcart):

                condition = False
                # print show_around, 'show'
                if show_around:
                    # print i, condition
                    condition = (i + 1 == show_around)
                    # print i, condition

                else:
                    condition = (
                        t > 1
                    )  # compat with prev behav, to show around any impurities (all atoms with typat more than one)

                # print 'se', condition

                if condition:
                    # lxcart.append(x)
                    # ltypat.append(t)
                    # print x, ' x'
                    x_t = local_surrounding(x,
                                            st,
                                            nnumber,
                                            control='atoms',
                                            periodic=True,
                                            only_elements=only_elements)
                    # print x_t[1]
                    lxcart += x_t[0]
                    ltypat += x_t[1]
                i += 1

        xcart = lxcart
        typat = ltypat
        natom = len(typat)
        # print natom, 'nat'

    name += suf
    xyzfile = os.path.join(basepath, name + ".xyz")
    makedir(xyzfile)
    """Include atoms on the edge of cell"""
    if full_cell:
        # print xred
        # print natom
        # st = return_atoms_to_cell(st)
        # print xred
        st = replic(st,
                    mul=(1, 1, 2),
                    inv=0,
                    cut_one_cell=1,
                    include_boundary=include_boundary)
        # print natom, st.natom

        # print st.xred

        rprimd, xcart, xred, typat, znucl, natom = update_var(st)

    # asdegf
    """Writing section"""
    # printlog("Writing xyz: "+xyzfile, imp = 'y')

    #analyze imp_positions
    if imp_sub_positions == None:
        imp_sub_positions = []
    nsub = 0
    for pos in imp_positions:
        # if len(pos) > 4:
        #     if 's' not in pos[4]: continue # skip interstitial positions

        xs = np.asarray([pos[0], pos[1], pos[2]])
        nsub += 1
        # print xs
        for i, x in enumerate(xcart):
            # print np.linalg.norm( x-xs)
            if np.linalg.norm(x - xs) < 1:
                imp_sub_positions.append(i)

    if imp_sub_positions:
        printlog(imp_sub_positions, ': numbers of found atoms to be changed ')

    # for i in sorted(indices, reverse=True):
    #     del somelist[i]

    if include_vectors:
        nvect = 3
    else:
        nvect = 0

    def write(st):
        rprimd, xcart, xred, typat, znucl, natom = update_var(st)

        f.write(str(natom + len(imp_positions) - nsub + nvect) +
                "\n")  #+3 vectors
        f.write(name + "\n")
        if imp_positions:
            for i, el in enumerate(imp_positions):
                # if len(el) != 4: continue
                f.write("%s %.5f %.5f %.5f \n" % (el[3], el[0], el[1], el[2]))
                # print 'composite -pointsize 60 label:{0:d} -geometry +{1:d}+{2:d} 1.png 2.png'.format(i, el[0], el[1])

        for i in range(natom):
            typ = typat[i] - 1

            z = int(znucl[typ])

            if i in imp_sub_positions:
                # f.write( "Be " )
                continue
            else:
                el = element_name_inv(z)
                f.write(el + " ")

            f.write("%.5f %.5f %.5f \n" %
                    (xcart[i][0], xcart[i][1], xcart[i][2]))

        if include_vectors:
            for r in st.rprimd:
                f.write('Tv {:.10f} {:.10f} {:.10f}\n'.format(*r))

    with open(xyzfile, 'w') as f:
        if sts:
            for st in sts:
                write(st)
        else:
            for i in range(repeat):
                write(st)

    # os._exit(1)
    printlog('File', xyzfile, 'was written', imp='y')

    pngfile = None
    if jmol:
        """
        script mode for jmol. Create script file as well for elobarate visualization
        """
        """Choose gb atoms to change their color"""
        printlog('position of boundary 2', gbpos2)
        atomselection = ''

        #create consistent xcart_new list like it will be in Jmol
        xcart_new = []
        for i, x in enumerate(xcart):
            if i in imp_sub_positions: continue
            xcart_new.append(x)

        if gbpos2:

            gbpos1 = gbpos2 - rprimd[0][0] / 2.
            gbatoms = []

            for i, x in enumerate(xcart_new):
                # print i
                # if x[0] > gbpos1 - gbwidth/2. and x[0] < gbpos1 + gbwidth/2.:
                if abs(x[0] - gbpos1) < gbwidth / 2.:
                    gbatoms.append(i)
                    # print i, x[0], abs(x[0] - gbpos1)
                if abs(x[0] - gbpos2) < gbwidth / 2.:
                    # if x[0] > gbpos2 - gbwidth/2. and x[0] < gbpos2 + gbwidth/2.:
                    # print i, x[0], abs(x[0] - gbpos2)
                    gbatoms.append(i)
            printlog('Atoms at GB:', gbatoms)
            atomselection = ''
            for i in gbatoms:
                atomselection += 'Ti' + str(i + 1 + len(imp_positions)) + ','
            atomselection = atomselection[:-1]

        # elif withgb: # color half of cell
        # else: # color half of cell
        #     # pass
        # atomselection = 'atomno>'+str(0+len(imp_positions) )+' and atomno<'+str(( natom + len(imp_positions)  )/2-1)

        xyzfile = os.getcwd() + '/' + xyzfile
        scriptfile = basepath + name + ".jmol"
        bn = (basepath + name).replace('.', '_')
        pngfile = os.getcwd() + '/' + bn + ".png"

        printlog('imp_positions = ', imp_positions)
        write_jmol(xyzfile,
                   pngfile,
                   scriptfile,
                   atomselection,
                   rprimd=rprimd,
                   shift=shift_2view,
                   label=[(pos[3], pos[4]) for pos in imp_positions],
                   specialcommand=specialcommand,
                   **jmol_args)

    return xyzfile, pngfile