示例#1
0
def determine_unique_final(st_pores, sums, avds, x_m):

    final_table = []
    insert_positions = []
    """Please determine unique positions with similar distances taking into acc PBC!!!
    below is incorrect
    """
    # 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', imp = 'y')

    # xcart_unique = []
    # avds_unique  = []
    # sums_unique  = []

    # for i, s in enumerate(sums_crude):
    #     index_of_first =  np.where(sums.round(crude_prec)==s)[0][0]
    #     xcart_unique.append(st_pores.xcart[index_of_first])
    #     avds_unique.append(avds[index_of_first] )
    #     sums_unique.append(sums[index_of_first] )

    # st_pores_unique = copy.deepcopy(st_pores)

    # st_pores_unique.xcart = xcart_unique
    # st_pores_unique.xcart2xred()

    sur = local_surrounding(x_m,
                            st_pores,
                            n_neighbours=len(st_pores.xcart),
                            control='atoms',
                            periodic=True)

    # print('neb.determine_unique_final(): sur',  sur)

    print_and_log('I can suggest you ' + str(len(sur[0])) + ' end positions.',
                  imp='y')

    for i, (x, d, ind) in enumerate(zip(sur[0], sur[3], sur[2])):
        # if i == 0:
        #     continue
        final_table.append(
            [i, np.array(x).round(2),
             round(d, 2), avds[ind], sums[ind]])

    print_and_log(tabulate(final_table,
                           headers=['void #', 'Cart.', 'Dist', 'Dev.', 'Sum'],
                           tablefmt='psql'),
                  imp='Y')

    return sur
示例#2
0
def around_alkali(st, nn, alkali_ion_number):
    #return numbers and distances to
    #alkali_ion_number - number of interesting cation from 0
    #nn - number of neighbours

    n_neighbours = nn
    alkali_ions = []
    dist = []
    ifmaglist = st.get_maglist()

    for i, typ, x in zip(range(st.natom), st.typat, st.xcart):
        z = st.znucl[typ - 1]
        if z in header.ALKALI_ION_ELEMENTS:
            alkali_ions.append([i, z, x])

    if len(alkali_ions) > 0:
        if alkali_ion_number:
            kk = alkali_ion_number

            chosen_ion = (kk, st.znucl[st.typat[kk] - 1], st.xcart[kk])
        else:
            chosen_ion = alkali_ions[0]  #just the first one is used
            # alkali_ions[min(alkali_ions)]

        sur = local_surrounding(chosen_ion[2],
                                st,
                                n_neighbours=n_neighbours,
                                control='atoms',
                                periodic=True,
                                only_elements=header.TRANSITION_ELEMENTS)

        # print (sur)
        dist = np.array(sur[3]).round(2)
        numb = np.array(sur[2])

    else:
        numb = ifmaglist  # if no alk ions show for all mag atoms
        chosen_ion = None

    return numb, dist, chosen_ion
示例#3
0
def plot_dos(
    cl1,
    cl2=None,
    dostype=None,
    iatom=None,
    iatom2=None,
    orbitals=('s'),
    up=None,
    neighbors=6,
    show=1,
    labels=None,
    path='dos',
    xlim=(None, None),
    ylim=(None, None),
    savefile=True,
    plot_param={},
    suf2='',
    fontsize=8,
    nsmooth=12,
    lts2='--',
    split_type='octa',
    plot_spin_pol=1,
    show_gravity=None,
):
    """
    cl1 (CalculationVasp) - object created by add_loop()
    dostype (str) - control which dos to plot:
        'total'   - plot total dos
        'diff_total' - difference of total dos, use cl2 for second calculation
        'partial' - partial dos

    orbitals (list of str) - 
        any from 's, p, d, py, pz, px, dxy, dyz, dz2, dxz, dx2' where 'p' and 'd' are sums of projections
        also to sum around neigbours use p6 and d6 and neighbors parameter

    up - 'up2' allows to download the file once again
    labels - two manual labels for cl1 and cl2 instead of auto

    iatom (int) - number of atom starting from 1 to plot DOS;
    iatom ([float]*3) - cartesian coordinates of point around which atoms will be found
    show (bool) - whether to show the dos 
    path (str)  - path to folder with images

    neighbors - number of neighbours around iatom to plot dos on them using p6 or d6; only p6 is implemented to the moment in plot section

    xlim, ylim (tuple)- limits for plot

    plot_param - dict of parameters to fit_and_plot
        dashes - control of dahsed lines

    suf2 - additional suffix

    # nsmooth = 15 # smooth of dos
    lts2 - style of lines for cl2

    split_type - 
        octa  - the names are t2g and eg
        tetra - the names are t2 and e


    plot_spin_pol -
        0 - spin-polarized components are summed up

    show_gravity (list) - print gravity centers (i, type, range, ); i - 1 or 2 cl
        type (str)
            'p6' - for p orbitals of neighbors
            'p'


    #0 s     1 py     2 pz     3 px    4 dxy    5 dyz    6 dz2    7 dxz    8 dx2 
    #In all cases, the units of the l- and site projected DOS are states/atom/energy.

    """
    if fontsize:
        header.mpl.rcParams.update({'font.size': fontsize + 4})
        header.mpl.rc('legend', fontsize=fontsize)

    if dostype == 'partial':
        eld1, eld2 = {}, {}
        for i, el in enumerate(cl1.end.get_elements()):
            eld1[i + 1] = el

        if cl2:
            for i, el in enumerate(cl2.end.get_elements()):
                eld2[i + 1] = el

        if not iatom:
            printlog(
                'Warning! Please choose atom number *iatom* from the following list:\n'
            )
            printlog(eld)
            sys.exit()
        else:
            printlog('cl1: Atom',
                     iatom,
                     'of type',
                     eld1[iatom],
                     'is choosen',
                     imp='y')
            printlog('cl1: Atom numbers:', eld1, imp='y')
            printlog('cl1:',
                     determine_symmetry_positions(cl1.end, eld1[iatom]),
                     imp='y')

            # print(cl2)
            if cl2:
                if not iatom2:
                    printlog('Error! provide iatom2!')
                printlog('cl2: Atom',
                         iatom2,
                         'of type',
                         eld2[iatom2],
                         'is choosen',
                         imp='y')

                printlog('cl2:',
                         determine_symmetry_positions(cl2.end, eld2[iatom2]),
                         imp='y')

    if iatom:
        iatom -= 1

    if cl2:
        if not iatom2:
            printlog('Error!, provide *iatom2*!')
        iatom2 -= 1

    if 'figsize' not in plot_param:
        plot_param['figsize'] = (4, 6)
    if 'legend' not in plot_param:
        plot_param['legend'] = 'best'
    """1. Read dos"""
    printlog("------Start plot_dos()-----", imp='Y')

    dos = []  # main list for cl1 and cl2

    for cl in cl1, cl2:
        if cl == None:
            continue

        if not hasattr(cl, "efermi"):
            cl.read_results('o')

        printlog(cl.name, 'e_fermi', cl.efermi, imp='Y')

        DOSCAR = cl.get_file('DOSCAR', nametype='asoutcar')
        printlog('DOSCAR file is ', DOSCAR)

        dos.append(VaspDos(DOSCAR, cl.efermi))

    #determine number of zero energy
    i_efermi = int(
        len(dos[0].energy) * -dos[0].energy[0] /
        (dos[0].energy[-1] -
         dos[0].energy[0]))  # number of point with zero fermi energy
    if cl2:
        i_efermi_e = int(
            len(dos[1].energy) * -dos[1].energy[0] /
            (dos[1].energy[-1] -
             dos[1].energy[0]))  # number of point with zero fermi energy

    if len(dos[0].dos) == 2:
        spin_pol = True
    else:
        spin_pol = False

    gc = None
    """2. Plot dos for different cases"""
    if dostype == 'total':
        # print(dos[0].dos)
        ylabel = "DOS (states/eV)"

        if spin_pol:
            dosplot = {
                'Tot up': {
                    'x': dos[0].energy,
                    'y': smoother(dos[0].dos[0], 10),
                    'c': 'b',
                    'ls': '-'
                },
                'Tot down': {
                    'x': dos[0].energy,
                    'y': -smoother(dos[0].dos[1], 10),
                    'c': 'r',
                    'ls': '-'
                }
            }
        else:
            dosplot = {
                'Total': {
                    'x': dos[0].energy,
                    'y': smoother(dos[0].dos, 10),
                    'c': 'b',
                    'ls': '-'
                }
            }

        # args[nam_down] = {'x':d.energy, 'y':-smoother(d.site_dos(iat, i_orb_down[orb]), nsmooth), 'c':color[orb], 'ls':l, 'label':None}

# xlabel = "Energy (eV)", ylabel = "DOS (states/eV)"
# print(plot_param)
        image_name = os.path.join(path, cl1.name + '.dosTotal')
        fit_and_plot(show=show,
                     image_name=image_name,
                     hor=True,
                     **plot_param,
                     **dosplot)

    elif dostype == 'diff_total':  #no spin-polarized!!!!
        ylabel = "DOS (states/eV)"

        if len(dos) > 1:
            #calculate dos diff
            dosd = [(d0 - d1) * e
                    for d0, d1, e in zip(dos[0].dos, dos[1].dos, dos[0].energy)
                    ]  #calculate difference
            area = trapz(dosd[:i_efermi], dx=1)
            printlog("area under dos difference = ", -area, imp='Y')

            fit_and_plot(show=show,
                         image_name=cl1.name + '--' + cl2.name +
                         '.dosTotal_Diff',
                         xlabel="Energy (eV)",
                         ylabel="DOS (states/eV)",
                         hor=True,
                         **plot_param,
                         Diff_Total=(dos[0].energy, smoother(dosd, 15), 'b-'))
        else:
            printlog(
                'You provided only one calculation; could not use diff_total')

    elif 'partial' in dostype:
        #Partial dos
        #1  p carbon,  d Ti
        #0 s     1 py     2 pz     3 px    4 dxy    5 dyz    6 dz2    7 dxz    8 dx2

        ylabel = "PDOS (states/atom/eV)"

        try:
            dos[0].site_dos(0, 4)
        except:
            printlog(
                'Error! No information about partial dxy dos in DOSCAR; use LORBIT 12 to calculate it'
            )
        """Determine neighbouring atoms """
        # printlog("Number of considered neighbors is ", neighbors, imp = 'y')

        if type(
                iatom
        ) == int:  #for the cases when we need to build surrounding around specific atom in this calculation - just use number of atom
            t = cl1.end.typat[iatom]
            z = cl1.end.znucl[t - 1]
            el = element_name_inv(z)
            printlog('Typat of chosen imp atom in cl1 is ', el, imp='y')
            surround_center = cl1.end.xcart[iatom]
        else:  #for the case when coordinates of arbitary point are provided.
            surround_center = iatom
            el = 'undef'

        local_atoms = local_surrounding(surround_center,
                                        cl1.end,
                                        neighbors,
                                        control='atoms',
                                        periodic=True)

        numbers = local_atoms[2]
        els = cl1.end.get_elements()
        el_sur = els[numbers[1]]  # element of surrounding type

        printlog("Numbers of local atoms:", [n + 1 for n in numbers], imp='Y')

        printlog("Elements of local atoms:", [els[i] for i in numbers],
                 imp='Y')

        printlog("List of distances", [round(d, 2) for d in local_atoms[3]],
                 imp='Y')

        iX = numbers[0]  # first atom is impurity if exist
        # printlog
        numbers_list = [numbers]  # numbers_list is list of lists
        calcs = [cl1]
        if cl2:
            numbers_list.append([iatom2])  # for cl2 only one atom is supported
            calcs.append(cl2)

        for cl, d, numbers in zip(calcs, dos, numbers_list):

            d.p = []  #central and surrounding
            d.d = []
            d.p_up = []
            d.p_down = []
            d.p_down = []  #central and and surrounding
            d.d_up = []  #central atom and surrounding atoms
            d.d_down = []  #central atom and surrounding atoms
            d.t2g_up = []
            d.t2g_down = []
            d.eg_up = []
            d.eg_down = []

            d.p_all = []  #sum over all atoms
            d.d_all = []  #sum over all atoms

            d.p_all_up = []  #sum over all atoms
            d.d_all_up = []  #sum over all atoms
            d.p_all_down = []  #sum over all atoms
            d.d_all_down = []  #sum over all atoms

            if 'p_all' in orbitals or 'd_all' in orbitals:
                #sum over all atoms
                p = []
                p_up = []
                p_down = []
                dd = []
                d_up = []
                d_down = []
                els = cl.end.get_elements()
                for i in range(cl.end.natom):
                    # if 'O' not in els[i]:
                    #     continue

                    if spin_pol:
                        plist_up = [d.site_dos(i, l) for l in (2, 4, 6)]
                        plist_down = [d.site_dos(i, l) for l in (3, 5, 7)]
                        plist = plist_up + plist_down

                        p_up.append([sum(x) for x in zip(*plist_up)])
                        p_down.append([sum(x) for x in zip(*plist_down)])
                        p.append([sum(x) for x in zip(*plist)])

                    else:
                        plist = [d.site_dos(i, l) for l in (1, 2, 3)]
                        p.append([sum(x) for x in zip(*plist)])

                    if spin_pol:
                        dlist_up = [
                            d.site_dos(i, l) for l in (8, 10, 12, 14, 16)
                        ]  #
                        dlist_down = [
                            d.site_dos(i, l) for l in (9, 11, 13, 15, 17)
                        ]  #
                        dlist = dlist_up + dlist_down

                        d_up.append([sum(x) for x in zip(*dlist_up)])
                        d_down.append([sum(x) for x in zip(*dlist_down)])
                        dd.append([sum(x) for x in zip(*dlist)])

                    else:
                        dlist = [d.site_dos(i, l) for l in (4, 5, 6, 7, 8)]  #
                        dd.append([sum(x) for x in zip(*dlist)])

                d.p_all = [sum(pi) for pi in zip(*p)]  #sum over all atoms
                d.d_all = [sum(di) for di in zip(*dd)]

                if spin_pol:
                    d.p_all_up = [sum(pi) for pi in zip(*p_up)]
                    d.p_all_down = [sum(pi) for pi in zip(*p_down)]

                    d.d_all_up = [sum(pi) for pi in zip(*d_up)]
                    d.d_all_down = [sum(pi) for pi in zip(*d_down)]

            #sum by surrounding atoms atoms
            n_sur = len(numbers)
            for i in numbers:  #Now for surrounding atoms in numbers list:

                if spin_pol:
                    plist_up = [d.site_dos(i, l) for l in (2, 4, 6)]
                    plist_down = [d.site_dos(i, l) for l in (3, 5, 7)]
                    d.p_up.append([sum(x) for x in zip(*plist_up)])
                    d.p_down.append([sum(x) for x in zip(*plist_down)])
                    plist = plist_up + plist_down

                    d.p.append([sum(x) for x in zip(*plist)])

                else:
                    plist = [d.site_dos(i, l) for l in (1, 2, 3)]
                    d.p.append([sum(x) for x in zip(*plist)])

                if spin_pol:
                    dlist_up = [d.site_dos(i, l)
                                for l in (8, 10, 12, 14, 16)]  #
                    dlist_down = [
                        d.site_dos(i, l) for l in (9, 11, 13, 15, 17)
                    ]  #

                    dlist = dlist_up + dlist_down

                    d.d.append([sum(x) for x in zip(*dlist)])

                    d.d_up.append([sum(x) for x in zip(*dlist_up)])
                    d.d_down.append([sum(x) for x in zip(*dlist_down)])

                    t2g_down = [d.site_dos(i, l) for l in (9, 11, 15)]
                    eg_down = [d.site_dos(i, l) for l in (13, 17)]

                    t2g_up = [d.site_dos(i, l) for l in (8, 10, 14)]
                    eg_up = [d.site_dos(i, l) for l in (12, 16)]

                    d.t2g_down.append([sum(x) for x in zip(*t2g_down)])
                    d.eg_down.append([sum(x) for x in zip(*eg_down)])
                    d.t2g_up.append([sum(x) for x in zip(*t2g_up)])
                    d.eg_up.append([sum(x) for x in zip(*eg_up)])

                else:
                    dlist = [d.site_dos(i, l) for l in (4, 5, 6, 7, 8)]  #
                    d.d.append([sum(x) for x in zip(*dlist)])

            d.p6 = [sum(pi) / n_sur for pi in zip(*d.p)
                    ]  #sum over neighbouring atoms now only for spin up

            if spin_pol:
                d.p6_up = [sum(pi) / n_sur for pi in zip(*d.p_up)
                           ]  #sum over neighbouring atoms now only for spin up
                d.p6_down = [
                    sum(pi) / n_sur for pi in zip(*d.p_down)
                ]  #sum over neighbouring atoms now only for spin up

            d.d6 = [sum(di) for di in zip(*d.d)]  #sum over neighbouring atoms
        """Plotting"""
        # nsmooth = 15 # smooth of dos
        d1 = dos[0]
        ds = [d1]
        names = []

        names = [cl1.id[0] + '_at_' + eld1[iatom + 1] + str(iatom + 1)]

        atoms = [iatom]
        els = [eld1[iatom + 1]]
        lts = [
            '-',
        ]  #linetypes
        if cl2:
            ds.append(dos[1])
            d2 = dos[1]

            # if labels:
            #     names.append(labels[1])
            # else:
            names.append(cl2.id[0] + '_at_' + eld2[iatom2 + 1] +
                         str(iatom2 + 1))

            lts.append(lts2)
            atoms.append(iatom2)
            els.append(eld2[iatom2 + 1])

        if not spin_pol:
            plot_spin_pol = 0  # could not plot spin polarization for non-spin polarization plot

        if 'dashes' in plot_param:
            dashes = plot_param['dashes']
            del plot_param['dashes']
        else:
            dashes = (5, 1)

        energy1 = dos[0].energy
        args = {}
        if spin_pol:
            i_orb = {
                's': 0,
                'py': 2,
                'pz': 4,
                'px': 6,
                'dxy': 8,
                'dyz': 10,
                'dz2': 12,
                'dxz': 14,
                'dx2': 16
            }
            i_orb_down = {
                's': 1,
                'py': 3,
                'pz': 5,
                'px': 7,
                'dxy': 9,
                'dyz': 11,
                'dz2': 13,
                'dxz': 15,
                'dx2': 17
            }

        else:
            i_orb = {
                's': 0,
                'py': 1,
                'pz': 2,
                'px': 3,
                'dxy': 4,
                'dyz': 5,
                'dz2': 6,
                'dxz': 7,
                'dx2': 8
            }
        # color = {'s':'k', 'p':'#F14343', 'd':'#289191', 'py':'g', 'pz':'b', 'px':'c', 'dxy':'m', 'dyz':'c', 'dz2':'k', 'dxz':'r', 'dx2':'g', 't2g':'b', 'eg':'g', 'p6':'k'}
        color = {
            's': 'k',
            'p': '#FF0018',
            'd': '#138BFF',
            'py': 'g',
            'pz': 'b',
            'px': 'c',
            'dxy': 'm',
            'dyz': 'c',
            'dz2': 'k',
            'dxz': 'r',
            'dx2': 'g',
            't2g': '#138BFF',
            'eg': '#8E12FF',
            'p6': '#FF0018',
            'p_all': 'r',
            'd_all': 'b'
        }  #http://paletton.com/#uid=54-100kwi++bu++hX++++rd++kX
        # color = {'s':'k', 'p':'r', 'd':'g', 'py':'g', 'pz':'b', 'px':'c', 'dxy':'m', 'dyz':'c', 'dz2':'m', 'dxz':'r', 'dx2':'g'}

        for orb in orbitals:
            i = 0
            for n, l, iat, el, d in zip(names, lts, atoms, els, ds):
                if el in ['Fe', 'Co', 'V', 'Mn', 'Ni'] and orb in ['p', 's']:
                    continue
                if el == 'O' and orb in ('d', 't2g', 'eg', 'dxy', 'dyz', 'dxz',
                                         'dz2', 'dx2'):
                    continue
                nam = orb
                nam_down = nam + '_down'
                # print('name', n)
                # print('lts', l)
                if labels:
                    formula = labels[i]
                else:
                    formula = latex_chem(n.split('.')[0])

                i += 1
                if spin_pol:
                    nam += ''
                suf = '; ' + n
                nam += suf
                nam_down += suf

                if orb == 'p':

                    if plot_spin_pol:
                        args[nam] = {
                            'x': d.energy,
                            'y': smoother(d.p_up[0], nsmooth),
                            'c': color[orb],
                            'ls': l,
                            'label': formula + ' ' + el + suf2 + ' ' + orb,
                            'dashes': dashes
                        }

                        args[nam_down] = {
                            'x': d.energy,
                            'y': -smoother(d.p_down[0], nsmooth),
                            'c': color[orb],
                            'ls': l,
                            'label': None,
                            'dashes': dashes
                        }
                        color[orb] = 'c'

                    else:
                        args[nam] = {
                            'x': d.energy,
                            'y': smoother(d.p[0], nsmooth),
                            'c': color[orb],
                            'ls': l,
                            'label': formula + ' ' + el + suf2 + ' ' + orb,
                            'dashes': dashes
                        }

                elif orb == 'p6':

                    # now spin-polarized components could not be shown
                    if plot_spin_pol:
                        args[nam] = {
                            'x': d.energy,
                            'y': smoother(d.p6_up, nsmooth),
                            'c': color[orb],
                            'ls': l,
                            'label': formula + ' ' + el_sur + suf2 + ' p',
                            'dashes': dashes
                        }
                        args[nam_down] = {
                            'x': d.energy,
                            'y': -smoother(d.p6_down, nsmooth),
                            'c': color[orb],
                            'ls': l,
                            'label': None,
                            'dashes': dashes
                        }

                    else:
                        args[nam] = {
                            'x': d.energy,
                            'y': smoother(d.p6, nsmooth),
                            'c': color[orb],
                            'ls': l,
                            'label': formula + ' ' + el_sur + suf2 + ' p',
                            'dashes': dashes
                        }

                elif orb == 'd':

                    if plot_spin_pol:
                        args[nam] = {
                            'x': d.energy,
                            'y': smoother(d.d_up[0], nsmooth),
                            'c': color[orb],
                            'ls': l,
                            'label': formula + ' ' + el + suf2 + ' ' + orb
                        }
                        args[nam_down] = {
                            'x': d.energy,
                            'y': -smoother(d.d_down[0], nsmooth),
                            'c': color[orb],
                            'ls': l,
                            'label': None
                        }
                        color[orb] = 'm'

                    else:
                        args[nam] = {
                            'x': d.energy,
                            'y': smoother(d.d[0], nsmooth),
                            'c': color[orb],
                            'ls': l,
                            'label': formula + ' ' + el + suf2 + ' ' + orb
                        }

                elif orb == 't2g':
                    if split_type == 'octa':
                        orb_name = orb
                    elif split_type == 'tetra':
                        orb_name = 't2'

                    args[nam] = {
                        'x': d.energy,
                        'y': smoother(d.t2g_up[0], nsmooth),
                        'c': color[orb],
                        'ls': l,
                        'label': formula + ' ' + el + suf2 + ' ' + orb_name
                    }
                    if spin_pol:
                        args[nam_down] = {
                            'x': d.energy,
                            'y': -smoother(d.t2g_down[0], nsmooth),
                            'c': color[orb],
                            'ls': l,
                            'label': None
                        }

                elif orb == 'eg':
                    if split_type == 'octa':
                        orb_name = orb
                    elif split_type == 'tetra':
                        orb_name = 'e'

                    args[nam] = {
                        'x': d.energy,
                        'y': smoother(d.eg_up[0], nsmooth),
                        'c': color[orb],
                        'ls': l,
                        'label': formula + ' ' + el + suf2 + ' ' + orb_name
                    }
                    if spin_pol:
                        args[nam_down] = {
                            'x': d.energy,
                            'y': -smoother(d.eg_down[0], nsmooth),
                            'c': color[orb],
                            'ls': l,
                            'label': None
                        }

                elif orb == 'p_all':

                    if plot_spin_pol:
                        args[nam] = {
                            'x': d.energy,
                            'y': smoother(d.p_all_up, nsmooth),
                            'c': color[orb],
                            'ls': l,
                            'label': formula + ' ' + el + suf2 + ' ' + orb
                        }
                        args[nam_down] = {
                            'x': d.energy,
                            'y': -smoother(d.p_all_down, nsmooth),
                            'c': color[orb],
                            'ls': l,
                            'label': None
                        }
                        # color[orb] = 'm'

                    else:
                        args[nam] = {
                            'x': d.energy,
                            'y': smoother(d.p_all, nsmooth),
                            'c': color[orb],
                            'ls': l,
                            'label': formula + ' ' + el + suf2 + ' ' + orb
                        }

                elif orb == 'd_all':

                    if plot_spin_pol:
                        args[nam] = {
                            'x': d.energy,
                            'y': smoother(d.d_all_up, nsmooth),
                            'c': color[orb],
                            'ls': l,
                            'label': formula + ' ' + el + suf2 + ' ' + orb
                        }
                        args[nam_down] = {
                            'x': d.energy,
                            'y': -smoother(d.d_all_down, nsmooth),
                            'c': color[orb],
                            'ls': l,
                            'label': None
                        }
                        # color[orb] = 'm'

                    else:
                        args[nam] = {
                            'x': d.energy,
                            'y': smoother(d.d_all, nsmooth),
                            'c': color[orb],
                            'ls': l,
                            'label': formula + ' ' + el + suf2 + ' ' + orb
                        }

                else:
                    # args[nam] = (d.energy, smoother(d.site_dos(iat, i_orb[orb]), nsmooth), color[orb]+l)
                    args[nam] = {
                        'x': d.energy,
                        'y': smoother(d.site_dos(iat, i_orb[orb]), nsmooth),
                        'c': color[orb],
                        'ls': l,
                        'label': formula + ' ' + el + suf2 + ' ' + orb
                    }

                    if spin_pol:
                        args[nam_down] = {
                            'x':
                            d.energy,
                            'y':
                            -smoother(d.site_dos(iat, i_orb_down[orb]),
                                      nsmooth),
                            'c':
                            color[orb],
                            'ls':
                            l,
                            'label':
                            None
                        }

                        # args[nam_down] = (d.energy, -smoother(d.site_dos(iat, i_orb_down[orb]), nsmooth), color[orb]+l)
        """Additional dos analysis; to be refined"""
        gc = None
        if show_gravity:
            if show_gravity[0] == 1:
                d = d1
            elif show_gravity[0] == 2:
                d = d2

            if show_gravity[2]:
                erange = show_gravity[2]
            else:
                erange = (-100, 0)

            mod = show_gravity[1]

            if mod == 'p6':

                gc = det_gravity2(d.energy, d.p6, erange)
                # gc = det_gravity2(d.energy, d.d[0], erange)
                # printlog('Gravity center for cl1 for d for {:} is {:5.2f}'.format(erange, gc), imp = 'Y')

            elif show_gravity[1] == 'p':
                gc = det_gravity2(d.energy, d.p[0],
                                  erange)  # for first atom for cl2

            elif show_gravity[1] == 'p_all':
                gc = det_gravity2(d.energy, d.p_all,
                                  erange)  # for first atom for cl2

            elif mod == 'd':
                gc = det_gravity2(d.energy, d.d[0],
                                  erange)  # for first atom for cl2

            printlog(
                'Gravity center for cl1 for {:} for {:} is {:5.2f}'.format(
                    mod, erange, gc),
                imp='Y')

            plot_param['ver_lines'] = [{'x': gc, 'c': 'k', 'ls': '--'}]
        """Plot everything"""

        image_name = os.path.join(
            path, '_'.join(names) + '.' + ''.join(orbitals) + '.' + el +
            str(iat + 1))

        if 'xlabel' not in plot_param:
            plot_param['xlabel'] = "Energy (eV)"

        if 'ylabel' not in plot_param:
            plot_param['ylabel'] = ylabel

        fit_and_plot(
            show=show,
            image_name=image_name,
            hor=True,
            # title = cl1.name.split('.')[0]+'; V='+str(round(cl1.vol) )+' $\AA^3$; Impurity: '+el,
            **plot_param,
            **args)
        # printlog("Writing file", image_name, imp = 'Y')

        if 0:
            """Calculate d DOS at Fermi level"""
            nn = 50  #number to integrate in both directions
            x1 = dos[0].energy[i_efermi - nn:i_efermi + nn]
            y1 = smoother(dos[0].d6, nsmooth)[i_efermi - nn:i_efermi + nn]
            x2 = dos[1].energy[i_efermi_e - nn:i_efermi_e + nn]
            y2 = smoother(dos[1].d6, nsmooth)[i_efermi_e - nn:i_efermi_e + nn]
            f1 = interp1d(x1, y1, kind='cubic')
            f2 = interp1d(x2, y2, kind='cubic')
            # if debug: print '\n'
            # if debug: print dos[0].d6[i_efermi] - dos[1].d6[i_efermi_e], " - by points; change of d Ti DOS at the Fermi level due to the carbon"
            # if debug: print f2(0), f1(0)
            e_at_Ef_shift = f1(0) - f2(0)

            printlog(
                "{:5.2f} reduction of d dos at Fermi level; smoothed and interpolated"
                .format(e_at_Ef_shift),
                imp='Y')

        if 0:
            """Calculate second derivative of d at the Fermi level"""
            # tck1 = interpolate.splrep(x1, y1, s=0)
            # tck2 = interpolate.splrep(x2, y2, s=0)
            # e_at_Ef_shift_spline = interpolate.splev(0, tck1, der=0) - interpolate.splev(0, tck2, der=0)
            # if debug: print "{:5.2f} smoothed and interpolated from spline".format( e_at_Ef_shift_spline )
            # # if debug: print type(interpolate.splev(0, tck1, der=2))
            # if debug: print "{:5.2f} {:5.2f} gb and bulk second derivative at Fermi from spline".format( float(interpolate.splev(0, tck1, der=2)), float(interpolate.splev(0, tck2, der=2)) )

        if 0:
            """Calculate shift of d orbitals after adding impurity"""
            d_shift = det_gravity(dos[0], Erange=(-2.8, 0)) - det_gravity(
                dos[1], Erange=(-2.8, 0)
            )  #negative means impurity shifts states to negative energies, which is favourable
            printlog("{:5.2f} Shift of Ti d center of gravity".format(d_shift),
                     imp='Y')
            # if debug: print det_gravity(dos[0],  Erange = (-2.8, 0)), det_gravity(dos[1],  Erange = (-2.8, 0))
            """Calculate correlation between imp p and matrix d"""
            def rmsdiff(a, b):
                # rms difference of vectors a and b:
                #Root-mean-square deviation
                rmsdiff = 0
                for (x, y) in zip(a, b):
                    rmsdiff += (
                        x -
                        y)**2  # NOTE: overflow danger if the vectors are long!

                return math.sqrt(rmsdiff / min(len(a), len(b)))

            pd_drms = 1 / rmsdiff(
                dos[0].p,
                dos[0].d6)  # the higher the number the higher hybridization
            printlog("{:5.2f} p-d hybridization estimate".format(pd_drms),
                     imp='Y')

            # if debug: print "sqeuclidean", sqeuclidean(dos[0].p, dos[0].d6)/len(dos[0].d6)

            # if debug: print "pearsonr", pearsonr(dos[0].p, dos[0].d6) #Pearson correlation coefficient; only shape; the larger number means more similarity in shape

            # def autocorr(x):
            #     result = np.correlate(x, x, mode='full')
            #     return result[result.size/2:]

    printlog("------End plot_dos()-----\n\n")

    return {'name': cl1.name, 'filename': image_name, 'gc': gc}
示例#4
0
def create_segregation_cases(it,
                             ise,
                             verlist,
                             dist_gb,
                             gbpos=None,
                             ise_new=None,
                             option=None,
                             precip_folder=None,
                             use_init=False,
                             precision=None):
    """
    Written for Ti-Fe project.
    Allows to create segregation by substituting atoms;
    dist_gb - distance from gb inside which the atoms are included
    

    option = 'precip'- adding additional impurities to the already existing at gb. Please use 'precip_folder'
    use_init - allows to use initial structure.


    !Warning PBC are not used in determination of seg positions 

    """

    # hstring = ("%s    #on %s"% (traceback.extract_stack(None, 2)[0][3],   datetime.date.today() ) )
    # try:
    #     if hstring != header.history[-1]: header.history.append( hstring  )
    # except:
    #     header.history.append( hstring  )
    def write_local(cl, it_new, it_new_path, el_sub, main_path):
        cl.version = v
        # it_new_path

        cl.name = it_new
        cl.des = 'Obtained from end state of ' + str(
            (it, ise, v)
        ) + ' by substitution of one atom near gb with ' + el_sub + ' impurity '
        path_new_geo = it_new_path + "/" + it_new + "/" + it_new + '.imp.' + el_sub + '.' + str(
            cl.version) + '.' + 'geo'
        cl.init.name = it_new + ".init." + str(cl.version)
        xyzpath = it_new_path + "/" + it_new
        cl.path["input_geo"] = path_new_geo
        print(path_new_geo)
        cl.write_geometry("init", cl.des, override=1)
        write_xyz(cl.init, xyzpath)
        return it_new_path

    if 0:
        res_loop(it, ise, verlist, up=0)

    cl = header.calc[(it, ise, verlist[0])]

    znucl_sub = 3  #atom to be added
    """1. Create list of atoms near gb to substitue"""
    cl.gbpos = gbpos
    # print cl.gbpos
    seg_pos_list = []  # numbers of segregation positions

    if use_init:
        st = cl.init
    else:
        st = cl.end

    # print(st.xcart)
    if len(st.xcart) == 0:
        print(
            'Warning!, xcart is empty',
            cl.id,
        )
    for i, x in enumerate(st.xcart):
        z_cur = st.znucl[st.typat[i] - 1]
        print('z_cur', z_cur)
        if z_cur == znucl_sub:
            printlog('Skipping znucl_sub atom\n')
            continue
        if abs(x[0] - gbpos) < dist_gb:
            print('adding possible seg position')
            seg_pos_list.append(i)
    """2. Substitue"""
    el_sub = invert(znucl_sub)
    base_name = it
    main_path = header.struct_des[it].sfolder
    based_on = it + '.' + ise
    des_list = []
    add_list = []

    cl_list = []
    sumr_list = []

    i = 0
    # print(seg_pos_list)
    for j, replace_atom in enumerate(seg_pos_list):  #

        v = verlist[0]  # the first version from list is used
        cl = calc[(it, ise, v)]
        cl.gbpos = gbpos

        new = copy.deepcopy(cl)
        if use_init:
            new.end = new.init
        else:
            new.init = new.end  #replace init structure by the end structure

        if 1:  #atom substitution !make function; see TODO

            if znucl_sub not in new.init.znucl:
                new.init.znucl.append(znucl_sub)
                new.init.ntypat += 1
                new.init.typat[replace_atom] = new.init.ntypat
            else:
                ind = new.init.znucl.index(znucl_sub)
                new.init.typat[replace_atom] = ind + 1
            new.init.nznucl = []
            for typ in range(1, new.init.ntypat + 1):
                new.init.nznucl.append(new.init.typat.count(typ))
            printlog("Impurity with Z=" + str(znucl_sub) +
                     " has been substituted in " + new.name + "\n\n")

            it_new = base_name + el_sub + 'is' + str(
                i + 1)  #interface substitution

            if option == 'precip':
                it_new_path = precip_folder

            else:
                it_new_path = main_path + '/' + base_name + '_segreg'

        #Check if configuration is unique
        add = 1
        # for cl in cl_list:
        st = new.end
        st_replic = replic(st, (2, 2, 2))
        st_replic = replic(st_replic, (2, 2, 2),
                           -1)  #replic in negative direction also
        sumr = local_surrounding(
            st.xcart[replace_atom], st_replic,
            n_neighbours=6)  # sum of distances to surrounding atoms
        print("sumr", sumr)
        for ad_sumr in sumr_list:
            if abs(ad_sumr - sumr) < precision:
                add = 0
                printlog("The void is non-equivalent; skipping\n")

        if add:
            i += 1
            sumr_list.append(sumr)
            # cl_list.append(new)
            write_local(new, it_new, it_new_path, el_sub, main_path)
            for v in verlist[1:]:  #write files; versions are scaled
                cl = calc[(it, ise, v)]
                rprimd_scaled = cl.end.rprimd
                new_scaled = copy.deepcopy(new)
                new_scaled.init.rprimd = copy.deepcopy(rprimd_scaled)
                new_scaled.init.xred2xcart()
                write_local(new_scaled, it_new, it_new_path, el_sub, main_path)
            #create names
            des_list.append(
                "struct_des['{0:s}'] = des('{1:s}', 'segregation configurations; made from {2:s}'   )"
                .format(it_new, it_new_path, based_on))
            add_list.append("add_loop('" + it_new + "','" + ise_new + "'," +
                            "range(1,6)" + ", up = 'up1', it_folder = '" +
                            it_new_path + "')")

    for d in des_list:
        print(d)

    for d in add_list:
        print(d)

    return
示例#5
0
文件: inout.py 项目: amatgroup/siman
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,
              mcif=0,
              suf=''):
    """Writes st structure in xyz format in the folder xyz/path
    #void are visualized with Pu
    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()
    mcif - write magnetic cif for jmol


    specialcommand - any command at the end of jmol script
    suf - additional suffix for name

    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)

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

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

    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':
        printlog('analysis = imp_surrounding', imp='y')

        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:
                    # print('Atom at', x, 'used as central')
                    # 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)
                    lxcart += x_t[0]
                    ltypat += x_t[1]
                i += 1

        xcart = lxcart
        typat = ltypat
        natom = len(typat)
        # print natom, 'nat'
        # print('Number of neighbours', natom  )
        st.xcart = xcart
        st.typat = typat
        st.natom = natom
        st.update_xred()
    """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

    # 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
    """Writing section"""
    name += suf
    xyzfile = os.path.join(basepath, name + ".xyz")
    makedir(xyzfile)

    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)
                if el == 'void':
                    el = 'Pu'

                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
        if mcif:
            xyzfile = st.write_cif(mcif=1)
        else:
            xyzfile = st.write_poscar()

        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
示例#6
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,
            calc_method=['neb'],
            inherit_option=None,
            mag_config=None,
            i_void_start=None,
            i_void_final=None,
            atom_to_insert=None,
            atom_to_move=None,
            rep_moving_atom=None,
            end_pos_types_z=None,
            replicate=None,
            it_new_folder=None,
            it_folder=None,
            inherit_magmom=False,
            x_start=None,
            xr_start=None,
            x_final=None,
            xr_final=None,
            upload_vts=False,
            center_on_moving=True,
            run=False,
            add_loop_dic=None,
            old_behaviour=None,
            params=None):
    """
    Prepare needed files for NEB
    Provides several regimes controlled by *search_type* flag:
        - existing_voids - search for voids around atom and use them as a final position 
        - vacancy_creation - search for neighbors of the same type and make a vacancy as a start position
        - interstitial_insertion - search for two neighboring voids; use them as start and final positions
                                    by inserting atom *atom_to_insert*
        - None - just use st and st2 as initial and final

    ###INPUT:
        - starting_calc (Calculation) - Calculation object with structure
        - st (Structure) - structure, can be used instead of Calculation
            - it_new (str) - name for calculation
        - st_end (Structure) - final structure

        - i_atom_to_move (int) - number of atom for moving starting from 0;
        - *mag_config* (int ) - choose magnetic configuration - allows to obtain different localizations of electron
        - *replicate* (tuple 3*int) - replicate cell along rprimd
        - i_void_start,  i_void_final (int) - position numbers of voids (or atoms) from the suggested lists
        - atom_to_insert  (str) - element name of atom to insert
        - atom_to_move (str) - element name of atom to move
        - it_new_folder or it_folder  (str) - section folder
        - inherit_option (str) - passed only to add_loop
        - inherit_magmom (bool) - if True than magmom from starting_calc is used, else from set

        - end_pos_types_z (list of int) - list of Z - type of atoms, which could be considered as final positions in vacancy creation mode

        - calc_method (list)
            - 'neb'
            - 'only_neb' - run only footer

        - x_start, x_final (array) - explicit xcart coordinates of moving atom for starting and final positions, combined with atom_to_insert
        - xr_start, xr_final (array) - explicit xred
        - rep_moving_atom (str)- replace moving atom by needed atom - can be useful than completly different atom is needed. 

        - upload_vts (bool) - if True upload Vasp.pm and nebmake.pl to server
        - run (bool)  - run on server

        - old_behaviour (str) - choose naming behavior before some date in the past for compatibility with your projects
            '020917'
            '261018' - after this moment new namig convention applied if end_pos_types_z is used

        - add_loop_dic - standart parameters of add()
        - params (dic) - provide additional parameters to add() # should be removed

    ###RETURN:
        None

    ###DEPENDS:

    ###TODO
    1. Take care of manually provided i_atom_to_move in case of replicate flag using init_numbers 
    2. For search_type == None x_m and x_del should be determined for magnetic searching and for saving their coordinates
    to struct_des; now their just (0,0,0) 


    """
    naming_conventions209 = True  # set False to reproduce old behavior before 2.09.2017
    if old_behaviour == '020917':
        naming_conventions209 = False  #

    # print('atom_to_insert', atom_to_insert)
    # sys.exit()

    calc = header.calc
    struct_des = header.struct_des
    varset = header.varset

    if not add_loop_dic:
        add_loop_dic = {}

    if not end_pos_types_z:
        end_pos_types_z = []
        end_pos_types_z = sorted(end_pos_types_z)

    if not hasattr(calc_method, '__iter__'):
        calc_method = [calc_method]

    if starting_calc and st:
        printlog(
            'Warning! both *starting_calc* and *st* are provided. I use *starting_calc*'
        )
        st = copy.deepcopy(starting_calc.end)

    elif starting_calc:
        st = copy.deepcopy(starting_calc.end)
        printlog('I use *starting_calc*')

    elif st:
        ''
        printlog('I use *st*')

    else:
        printlog(
            'Error! no input structure. Use either *starting_calc* or *st*')

    corenum = add_loop_dic.get('corenum')
    # print(corenum)
    # sys.exit()

    if corenum == None:
        if images == 3:
            corenum = 15
        elif images == 5:
            corenum = 15
        elif images == 7:
            corenum = 14
        else:
            printlog('add_neb(): Error! number of images', images,
                     'is unknown to me; please provide corenum!')

    # print(corenum)
    # sys.exit()

    # print(atom_to_insert)
    # sys.exit()

    if corenum:
        # header.corenum = corenum
        ''
    else:
        corenum = header.CORENUM

    if corenum % images > 0:
        print_and_log(
            'Error! Number of cores should be dividable by number of IMAGES',
            images, corenum)

    if not ise_new:
        ise_new = starting_calc.id[1]
        printlog('I use', ise_new, 'as ise_new', imp='y')

    name_suffix = ''
    st_pores = []

    name_suffix += 'n' + str(images)
    """Replicate cell """
    if replicate:
        print_and_log('You have chosen to replicate the structure by',
                      replicate)

        st = replic(st, mul=replicate)
        name_suffix += str(replicate[0]) + str(replicate[1]) + str(
            replicate[2])

    printlog('Search type is ', search_type)
    if search_type == None:

        if st_end == None:
            printlog(
                'Error! You have provided search_type == None, st_end should be provided!'
            )

        st1 = st
        st2 = st_end

        x_m = (0, 0, 0)
        x_del = (0, 0, 0)

    else:
        """1. Choose  atom (or insert) for moving """

        if is_list_like(xr_start):
            x_start = xred2xcart([xr_start], st.rprimd)[0]
            # print('atom_to_insert', atom_to_insert)
            # sys.exit()

            st1, i_m = st.add_atoms([x_start], atom_to_insert, return_ins=1)
            x_m = x_start
            # i_m = st1.find_atom_num_by_xcart(x_start)
            # print(st1.get_elements()[i_m])
            # sys.exit()

            if i_atom_to_move:
                nn = str(i_atom_to_move + 1)
            else:
                nn = str(i_void_start)

            name_suffix += atom_to_insert + nn
            write_xyz(st1, file_name=st.name + '_manually_start')
            printlog('Start position is created manually by adding xr_start',
                     xr_start, x_start)
            type_atom_to_move = atom_to_insert
            el_num_suffix = ''

        else:

            atoms_to_move = []
            atoms_to_move_types = []

            # print('d', i_atom_to_move)
            # sys.exit()

            if i_atom_to_move:
                typ = st.get_elements()[i_atom_to_move]
                printlog('add_neb(): atom', typ, 'will be moved', imp='y')
                atoms_to_move.append(
                    [i_atom_to_move, typ, st.xcart[i_atom_to_move]])
                atoms_to_move_types.append(typ)

                if naming_conventions209:
                    name_suffix += typ + str(i_atom_to_move + 1)

            else:
                #try to find automatically among alkali - special case for batteries
                for i, typ, x in zip(range(st.natom), st.get_elements(),
                                     st.xcart):
                    if typ in ['Li', 'Na', 'K', 'Rb', 'Mg']:
                        atoms_to_move.append([i, typ, x])
                        if typ not in atoms_to_move_types:
                            atoms_to_move_types.append(typ)

            if atoms_to_move:
                # print(atom_to_move)
                # sys.exit()
                if not atom_to_move:
                    atom_to_move = atoms_to_move_types[
                        0]  # taking first found element
                    if len(atoms_to_move_types) > 1:
                        printlog(
                            'Error! More than one type of atoms available for moving detected',
                            atoms_to_move_types,
                            'please specify needed atom with *atom_to_move*')

                type_atom_to_move = atom_to_move  #atoms_to_move[0][1]

                # printlog('atom ', type_atom_to_move, 'will be moved', imp ='y')

                if i_atom_to_move:
                    printlog('add_neb(): *i_atom_to_move* = ',
                             i_atom_to_move,
                             'is used',
                             imp='y')
                    numbers = [[i_atom_to_move]]
                    i_void_start = 1
                else:
                    printlog('add_neb(): determine_symmetry_positions ...',
                             imp='y')

                    numbers = determine_symmetry_positions(st, atom_to_move)

                # print(numbers)
                # sys.exit()
                if len(numbers) > 0:
                    printlog('Please choose position using *i_void_start* :',
                             [i + 1 for i in range(len(numbers))],
                             imp='y')
                    printlog('*i_void_start* = ', i_void_start)
                    i_m = numbers[i_void_start - 1][0]
                    printlog('Position',
                             i_void_start,
                             'chosen, atom:',
                             i_m + 1,
                             type_atom_to_move,
                             imp='y')

                else:
                    i_m = numbers[0][0]

                x_m = st.xcart[i_m]

                el_num_suffix = type_atom_to_move + str(i_m + 1)
                atom_to_insert = atom_to_move

                st1 = st
            # elif atom_to_replace:
            #     num = st.get_specific_elements(atom_to_replace)

            #     if len(n)>0:
            #         printlog('Please choose position using *i_void_start* :', [i+1 for i in range(len(num))],imp = 'y' )
            #         printlog('*i_void_start* = ', i_void_start)
            #         i_m = num[i_void_start-1]
            #         printlog('Position',i_void_start,'chosen, atom to replace:', i_m+1, atom_to_replace, imp = 'y' )
            #         sys.exit()

            else:

                print_and_log(
                    'No atoms to move found, you probably gave me deintercalated structure',
                    important='y')

                st_pores, sums, avds = determine_voids(st,
                                                       r_impurity,
                                                       step_dec=0.1,
                                                       fine=2)

                insert_positions = determine_unique_voids(st_pores, sums, avds)

                print_and_log(
                    'Please use *i_void_start* to choose the void for atom insertion from the Table above:',
                    end='\n',
                    imp='Y')

                if i_void_start == None:
                    sys.exit()
                if atom_to_insert == None:
                    printlog('Error! atom_to_insert = None')

                st = st.add_atoms([
                    insert_positions[i_void_start],
                ], atom_to_insert)

                name_suffix += 'i' + str(i_void_start)

                i_m = st.natom - 1
                x_m = st.xcart[i_m]

                search_type = 'existing_voids'
                type_atom_to_move = atom_to_insert
                el_num_suffix = ''

                st1 = st
        """2. Choose final position"""

        if is_list_like(xr_final):
            x_final = xred2xcart([xr_final], st.rprimd)[0]

            #old
            #check if i_atom_to_move should be removed
            # st2 = st1.del_atom(i_m)
            # st2 = st2.add_atoms([x_final], atom_to_insert)

            #new
            st2 = st1.mov_atoms(i_m, x_final)

            # st1.printme()
            # st2.printme()
            # sys.exit()

            x_del = x_final
            search_type = 'manual_insertion'
            name_suffix += 'v' + str(i_void_final)
            write_xyz(st2, file_name=st.name + '_manually_final')
            printlog('Final position is created manually by adding xr_final',
                     xr_final, x_del)

        elif search_type == 'existing_voids':
            #Search for voids around choosen atoms

            if not st_pores:
                st_pores, sums, avds = determine_voids(st, r_impurity)

            sur = determine_unique_final(st_pores, sums, avds, x_m)

            print_and_log('Please choose *i_void_final* from the Table above:',
                          end='\n',
                          imp='Y')

            if i_void_final == None:
                sys.exit()

            x_final = sur[0][i_void_final]  #

            printlog('You chose:',
                     np.array(x_final).round(2),
                     end='\n',
                     imp='Y')

            x_del = x_final  #please compare with vacancy creation mode

            write_xyz(st.add_atoms([x_final], 'H'),
                      replications=(2, 2, 2),
                      file_name=st.name + '_possible_positions2_replicated')

            print_and_log('Choosing the closest position as end',
                          important='n')

            st1 = st

            st2 = st.mov_atoms(i_m, x_final)

            name_suffix += el_num_suffix + 'e' + str(
                i_void_final) + atom_to_insert

            st1 = return_atoms_to_cell(st1)
            st2 = return_atoms_to_cell(st2)

            write_xyz(st1, file_name=st1.name + name_suffix + '_start')

            write_xyz(st2, file_name=st2.name + name_suffix + '_final')

        elif search_type == 'vacancy_creation':
            #Create vacancy by removing some neibouring atom of the same type

            print_and_log(
                'You have chosen vacancy_creation mode of add_neb tool',
                imp='Y')

            print_and_log('Type of atom to move = ',
                          type_atom_to_move,
                          imp='y')
            # print 'List of left atoms = ', np.array(st.leave_only(type_atom_to_move).xcart)

            final_pos_z = end_pos_types_z or [
                invert(type_atom_to_move)
            ]  # by default only moving atom is considered
            end_pos_types_el = [invert(z) for z in end_pos_types_z]

            sur = local_surrounding(x_m,
                                    st,
                                    n_neighbours=14,
                                    control='atoms',
                                    only_elements=final_pos_z,
                                    periodic=True)  #exclude the atom itself

            # print(x_m)
            # print(sur)

            # st.nn()
            end_pos_n = sur[2][1:]
            print_and_log(
                'I can suggest you ' + str(len(end_pos_n)) +
                ' end positions. The distances to them are : ',
                np.round(sur[3][1:], 2),
                ' A\n ',
                'They are ', [invert(z) for z in final_pos_z],
                'atoms, use *i_void_final* to choose required: 1, 2, 3 ..',
                imp='y')

            i_sym_final_l = []
            for j in end_pos_n:
                for i, l in enumerate(numbers):
                    if j in l:
                        i_sym_final_l.append(i + 1)
            printlog('Their symmetry positions are ', i_sym_final_l, imp='y')

            # sys.exit()

            if not i_void_final:
                printlog('Changing i_void_final: None -> 1', imp='y')
                i_void_final = 1  #since zero is itself
            chosen_dist = sur[3][i_void_final]
            print_and_log('Choosing position ',
                          i_void_final,
                          'with distance',
                          round(chosen_dist, 2),
                          'A',
                          imp='y')

            # print(end_pos_n)
            i_sym_final = 0
            n_final = sur[2][i_void_final]
            for i, l in enumerate(numbers):
                if n_final in l:
                    i_sym_final = i + 1
            printlog('It is symmetrically non-equiv position #',
                     i_sym_final,
                     imp='y')

            # sys.exit()

            header.temp_chosen_dist = chosen_dist

            if old_behaviour == '261018':
                name_suffix += el_num_suffix + 'v' + str(i_void_final)
            else:

                name_suffix += el_num_suffix + 'v' + str(
                    i_void_final) + list2string(end_pos_types_el, joiner='')

                # print(name_suffix)
                # sys.exit()

            x_del = sur[0][i_void_final]
            printlog('xcart of atom to delete', x_del)
            i_del = st.find_atom_num_by_xcart(x_del)
            # print(x_del)
            # print(st.xcart)
            # for x in st.xcart:
            #     if x[0] > 10:
            #         print(x)

            print_and_log('number of atom to delete = ', i_del, imp='y')
            if i_del == None:
                printlog('add_neb(): Error! I could find atom to delete!')

            # print st.magmom
            # print st1.magmom

            # try:
            if is_list_like(xr_start):
                st2 = st1.mov_atoms(
                    i_m, x_del)  # i_m and sur[0][neb_config] should coincide
                # i_del = st1.find_atom_num_by_xcart(x_del)

                st1 = st1.del_atom(i_del)

            else:
                print_and_log(
                    'Making vacancy at end position for starting configuration',
                    imp='y')
                st1 = st.del_atom(i_del)

                print_and_log(
                    'Making vacancy at start position for final configuration',
                    important='n')
                st2 = st.mov_atoms(
                    i_m, x_del)  # i_m and sur[0][neb_config] should coincide
            # except:
            # st2 = st

            st2 = st2.del_atom(i_del)  # these two steps provide the same order
    """Checking correctness of path"""
    #if start and final positions are used, collisions with existing atoms are possible
    if is_list_like(xr_start) and is_list_like(xr_final):
        printlog('Checking correctness')
        st1, _, _ = st1.remove_close_lying()

        stt = st1.add_atoms([
            x_final,
        ], 'Pu')
        stt, x, _ = stt.remove_close_lying(
            rm_both=True
        )  # now the final position is empty for sure; however the order can be spoiled
        # print(st._removed)
        if stt._removed:
            st1 = stt  # only if overlapping was found we assign new structure

        st2, _, _ = st2.remove_close_lying(rm_first=stt._removed)
        stt = st2.add_atoms([
            x_start,
        ], 'Pu')
        stt, x, _ = stt.remove_close_lying(
            rm_both=True)  # now the start position is empty for sure
        if stt._removed:
            st2 = stt

        print(st2.get_elements())
        # sys.exit()

    elif is_list_like(xr_final) and not is_list_like(xr_start) or is_list_like(
            xr_start) and not is_list_like(xr_final):
        printlog(
            'Attention! only start or final position is provided, please check that everything is ok with start and final states!!!'
        )
    """ Determining magnetic moments  """
    vp = varset[ise_new].vasp_params

    if 'ISPIN' in vp and vp['ISPIN'] == 2:
        print_and_log(
            'Magnetic calculation detected. Preparing spin modifications ...',
            imp='y')
        cl_test = CalculationVasp(varset[ise_new])
        cl_test.init = st1
        # print 'asdfsdfasdfsadfsadf', st1.magmom
        if inherit_magmom and hasattr(st, 'magmom') and st.magmom and any(
                st.magmom):
            print_and_log(
                'inherit_magmom=True: You have chosen MAGMOM from provided structure',
                imp='y')
            name_suffix += 'mp'  #Magmom from Previous
        else:
            cl_test.init.magmom = None
            print_and_log(
                'inherit_magmom=False or no magmom in input structure : MAGMOM will be determined  from set',
                imp='y')
            name_suffix += 'ms'  #Magmom from Set

        cl_test.actualize_set()  #find magmom for current structure

        st1.magmom = copy.deepcopy(cl_test.init.magmom)
        st2.magmom = copy.deepcopy(cl_test.init.magmom)

        # sys.exit()
        # print_and_log('The magnetic moments from set:')
        # print cl_test.init.magmom
        if search_type != None:  # for None not implemented; x_m should be determined first for this
            #checking for closest atoms now only for Fe, Mn, Ni, Co
            sur = local_surrounding(x_m,
                                    st1,
                                    n_neighbours=3,
                                    control='atoms',
                                    periodic=True,
                                    only_elements=header.TRANSITION_ELEMENTS)

            dist = np.array(sur[3]).round(2)
            numb = np.array(sur[2])
            a = zip(numb, dist)

            # a=  np.array(a)
            # print a[1]
            # a = np.apply_along_axis(np.unique, 1, a)
            # print a
            def unique_by_key(elements, key=None):
                if key is None:
                    # no key: the whole element must be unique
                    key = lambda e: e
                return list({key(el): el for el in elements}.values())

            # print a
            mag_atoms_dists = unique_by_key(a, key=itemgetter(1))
            # print (mag_atoms_dists)
            # a = unique_by_key(a, key=itemgetter(1))
            print_and_log(
                'I change spin for the following atoms:\ni atom     dist\n',
                np.round(mag_atoms_dists, 2),
                imp='y')
            # print 'I have found closest Fe atoms'
            muls = [(1.2, 0.6), (0.6, 1.2)]
            mag_moments_variants = []
            for mm in muls:
                mags = copy.deepcopy(cl_test.init.magmom)
                # print mags
                for a, m in zip(mag_atoms_dists, mm):
                    # print t[1]
                    mags[a[0]] = mags[a[0]] * m
                mag_moments_variants.append(mags)

            print_and_log('The list of possible mag_moments:', imp='y')
            for i, mag in enumerate(mag_moments_variants):
                print_and_log(i, mag)

            print_and_log(
                'Please use *mag_config* arg to choose desired config',
                imp='y')

        if mag_config != None:

            st1.magmom = copy.deepcopy(mag_moments_variants[mag_config])
            st2.magmom = copy.deepcopy(mag_moments_variants[mag_config])

            name_suffix += 'm' + str(mag_config)

            print_and_log('You have chosen mag configuration #',
                          mag_config,
                          imp='y')

    else:
        print_and_log('Non-magnetic calculation continue ...')
    """3. Add to struct_des, create geo files, check set, add_loop """

    if starting_calc:
        it = starting_calc.id[0]
        it_new = it + 'v' + str(starting_calc.id[2]) + '.' + name_suffix

        if not it_new_folder:
            it_new_folder = struct_des[it].sfolder + '/neb/'
        obtained_from = str(starting_calc.id)

        if not ise_new:
            print_and_log('I will run add_loop() using the same set',
                          important='Y')
            ise_new = cl.id[1]

    elif st:
        if not it_new:
            printlog(
                'Error! please provide *it_new* - name for your calculation',
                important='Y')

        it = None
        it_new += '.' + name_suffix
        obtained_from = st.name

        if not ise_new:
            printlog('Error! please provide *ise_new*', important='Y')

        if not it_new_folder and not it_folder:

            printlog(
                'Error! please provide *it_new_folder* - folder for your new calculation',
                important='Y')
        if it_folder:
            it_new_folder = it_folder

    if rep_moving_atom:
        it_new += 'r' + rep_moving_atom

    if it_new not in struct_des:
        add_des(struct_des, it_new, it_new_folder,
                'Automatically created and added from ' + obtained_from)

    print_and_log(
        'Creating geo files for starting and final configurations (versions 1 and 2) ',
        important='y')

    # if starting_calc:
    #     cl = copy.deepcopy(starting_calc)
    # else:

    cl = CalculationVasp()

    #write start position
    if search_type is not None:
        struct_des[it_new].x_m_ion_start = x_m
        struct_des[it_new].xr_m_ion_start = xcart2xred([x_m], st1.rprimd)[0]

        # st1, _, _ = st1.remove_close_lying()
        # st2, _, _ = st2.remove_close_lying()
        print('Trying to find x_m', x_m)
        i1 = st1.find_atom_num_by_xcart(
            x_m,
            prec=0.45,
        )

        # sys.exit()
        print('Trying to find x_del', x_del)

        i2 = st2.find_atom_num_by_xcart(
            x_del,
            prec=0.45,
        )

        if rep_moving_atom:  #replace the moving atom by required
            st1 = st1.replace_atoms([i1], rep_moving_atom)
            st2 = st2.replace_atoms([i2], rep_moving_atom)
        else:
            #allows to make correct order for nebmake.pl
            st1 = st1.replace_atoms([i1], type_atom_to_move)
            st2 = st2.replace_atoms([i2], type_atom_to_move)

        i1 = st1.find_atom_num_by_xcart(
            x_m,
            prec=0.45)  # the positions were changed # check if this is correct
        i2 = st2.find_atom_num_by_xcart(x_del, prec=0.45)

    cl.end = st1
    ver_new = 1
    cl.version = ver_new
    cl.path["input_geo"] = header.geo_folder + struct_des[it_new].sfolder + '/' + \
        it_new+"/"+it_new+'.auto_created_starting_position_for_neb_'+str(search_type)+'.'+str(ver_new)+'.'+'geo'

    cl.write_siman_geo(geotype='end',
                       description='Starting conf. for neb from ' +
                       obtained_from,
                       override=True)

    #write final position

    struct_des[it_new].x_m_ion_final = x_del
    struct_des[it_new].xr_m_ion_final = xcart2xred([x_del], st2.rprimd)[0]

    cl.end = st2
    ver_new = 2
    cl.version = ver_new
    cl.path["input_geo"] = header.geo_folder + struct_des[it_new].sfolder + '/' + \
        it_new+"/"+it_new+'.auto_created_final_position_for_neb_'+str(search_type)+'.'+str(ver_new)+'.'+'geo'

    cl.write_siman_geo(geotype='end',
                       description='Final conf. for neb from ' + obtained_from,
                       override=True)

    if not rep_moving_atom and search_type is not None:
        st1s = st1.replace_atoms([i1], 'Pu')
        st2s = st2.replace_atoms([i2], 'Pu')
    else:
        st1s = copy.deepcopy(st1)
        st2s = copy.deepcopy(st2)

    if center_on_moving and search_type is not None:

        vec = st1.center_on(i1)
        st1s = st1s.shift_atoms(vec)
        st2s = st2s.shift_atoms(vec)
        write_xyz(st1s, file_name=it_new + '_start')
        write_xyz(st2s, file_name=it_new + '_end')

    st1s.write_poscar('xyz/POSCAR1')
    st2s.write_poscar('xyz/POSCAR2')
    # print(a)
    # runBash('cd xyz; mkdir '+it_new+'_all;'+"""for i in {00..04}; do cp $i/POSCAR """+ it_new+'_all/POSCAR$i; done; rm -r 00 01 02 03 04')

    with cd('xyz'):
        a = runBash(header.PATH2NEBMAKE + ' POSCAR1 POSCAR2 3')
        print(a)
        dst = it_new + '_all'
        makedir(dst + '/any')
        for f in ['00', '01', '02', '03', '04']:
            shutil.move(f + '/POSCAR', dst + '/POSCAR' + f)
            shutil.rmtree(f)

    #prepare calculations
    # sys.exit()

    #Check if nebmake is avail
    # if int(runBash('ssh '+cluster_address+' test -e '+project_path_cluster+'/tools/vts/nebmake.pl; echo $?') ):

    #     ''
    #     print_and_log('Please upload vtsttools to ',cluster_address, project_path_cluster+'/tools/vts/')
    #     raise RuntimeError

    #     copy_to_server(path_to_wrapper+'/vtstscripts/nebmake.pl', to = project_path_cluster+'/tools/',  addr = cluster_address)
    # if  int(runBash('ssh '+cluster_address+' test -e '+project_path_cluster+'/tools/Vasp.pm; echo $?') ):
    #     copy_to_server(path_to_wrapper+'/vtstscripts/Vasp.pm', to = project_path_cluster+'/tools/',  addr = cluster_address)

    inherit_ngkpt(it_new, it, varset[ise_new])

    if run:
        add_loop_dic['run'] = run

    add_loop_dic['corenum'] = corenum
    # print(add_loop_dic)
    add_loop(
        it_new,
        ise_new,
        verlist=[1, 2],
        up=up,
        calc_method=calc_method,
        savefile='oc',
        inherit_option=inherit_option,
        n_neb_images=images,
        # params=params,
        **add_loop_dic)

    if upload_vts:
        siman_dir = os.path.dirname(__file__)
        # print(upload_vts)
        push_to_server([
            siman_dir + '/cluster_tools/nebmake.pl',
            siman_dir + '/cluster_tools/Vasp.pm'
        ],
                       to=header.cluster_home + '/tools/vts',
                       addr=header.cluster_address)

    else:
        print_and_log('Please be sure that vtsttools are at',
                      header.cluster_address,
                      header.cluster_home + '/tools/vts/',
                      imp='Y')

    printlog('add_neb finished')
    return it_new
示例#7
0
    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],
                  end=' ')  #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], end=' '
                    )  # 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