Example #1
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))
Example #2
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')

    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
    """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'] 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"""
        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)

            if show_gravity[1] == 'p6':

                gc = det_gravity2(d.energy, d.p6, erange)
                printlog(
                    'Gravity center for cl1 for p6 for {:} is {:5.2f}'.format(
                        erange, gc),
                    imp='Y')
                # 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
                printlog('Gravity center for cl1 for p_all for {:} is {:5.2f}'.
                         format(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}
Example #3
0
def add_impurity(it_new, impurity_type = None, addtype = 'central', calc = [], r_pore = 0.5,
    it_to = '', ise_to = '', verlist_to = [], copy_geo_from = "", find_close_to = (),add_to_version = 0,
    write_geo = True, only_version = None, fine = 4, put_exactly_to = None, check_pore_vol = 0):

    """
    Add impurities in pores.

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

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

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

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

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

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


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


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

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


    Side effects: creates new geometry folder with input structures; 

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

            rep = copy.deepcopy(init)

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

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

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


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


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

        #new.init = return_atoms_to_cell(new.init)

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

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


        npores = len(pores_xred)
        
        st = new.init

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




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

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



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



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

        new.init = st

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


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

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

        #test_adding_of_impurities(new, new_before, v)

        print_and_log("Impurity with Z="+str(znucl)+" has been added to the found pore in "+new.name+"\n\n")
        
        if write_geo:
            write_xyz(new.init , xyzpath)
            new.write_geometry("init",new.des)

        print "\n"


        return new

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

    znucl = element_name_inv(impurity_type)


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


    #geo_exists = 
    





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

    if verlist_to:         

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

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

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

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

            



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

        

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

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




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

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


        for input_geofile in geofilelist:

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

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

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



    return new.path["input_geo"] #return for last version
Example #4
0
def add_impurity(it_new,
                 impurity_type=None,
                 addtype='central',
                 calc=[],
                 r_pore=0.5,
                 it_to='',
                 ise_to='',
                 verlist_to=[],
                 copy_geo_from="",
                 find_close_to=(),
                 add_to_version=0,
                 write_geo=True,
                 only_version=None,
                 fine=4,
                 put_exactly_to=None,
                 check_pore_vol=0,
                 replace_atom=None,
                 override=False):
    """
    Add impurities in pores.

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

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

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

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

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

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


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


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

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

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


    Side effects: creates new geometry folder with input structures; 

    """

    struct_des = header.struct_des

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

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

            rep = copy.deepcopy(init)

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

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

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

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

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

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

        else:
            new_before = copy.deepcopy(new)

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

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

            npores = len(pores_xred)

            st = new.init

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

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

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

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

            st.xred2xcart()

            new.init = st

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

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

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

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

            #test_adding_of_impurities(new, new_before, v)

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

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

        print_and_log("\n")

        return new

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

    znucl = element_name_inv(impurity_type)

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

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

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

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

    if verlist_to:

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

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

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

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

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

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

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

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

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

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

        for input_geofile in geofilelist:

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

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

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

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

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

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

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

    return new.path["input_geo"]  #return for last version
Example #5
0
def read_xyz(st, filename, rprimd=None):
    """
    Read xyz file into st

    rprimd (list of lists) - if None or [None, ] then Tv are read; if Tv does not exist then create automatically 

    """
    with open(filename, 'r') as f:
        nlines = int(f.readline())
        st.name = f.readline().strip()

        # try:
        if 'SG' in st.name:
            printlog(
                'Error! Space group record detected in xyz, please finish code',
                imp='Y')
            # st.name.split('SG')

        elements = []
        st.xcart = []
        st.rprimd = []
        for i in range(nlines):
            xc = f.readline().split()
            if len(xc) == 0:
                printlog('Warning! xyz file is broken, not enough lines')
                break

            if 'Tv' in xc[0]:
                st.rprimd.append(np.asarray(xc[1:], dtype=float))

            else:
                elements.append(xc[0])
                st.xcart.append(np.asarray(xc[1:], dtype=float))

        st.natom = len(st.xcart)

    st.znucl = [element_name_inv(el) for el in unique_elements(elements)]

    elements_z = [element_name_inv(el) for el in elements]
    st.typat = []
    for z in elements_z:
        st.typat.append(st.znucl.index(z) + 1)

    st.ntypat = len(st.znucl)

    # print(st.rprimd)
    if rprimd == None or None in rprimd or 0 in rprimd or len(rprimd) != 3:
        printlog('None detected in *rprimd*, I use vectors from xyz file')
        if len(st.rprimd) != 3:
            printlog('Only these primitive vectors were found in xyz :\n',
                     np.round(st.rprimd, 3),
                     '\nI take rest from *rprimd*',
                     imp='y')
            if rprimd:
                for r in rprimd:
                    if is_list_like(r):
                        st.rprimd.append(r)
            else:
                printlog('Error! Please provide vector in *rprimd*')

    else:

        printlog('I use vectors from *rprimd*')
        st.rprimd = rprimd

    if len(st.rprimd) != 3:
        printlog('Error! Check *rprimd* or Tv in xyz')

    if st.get_volume() < 0:
        printlog(
            'Warning! rprimd gives negative volume, I exchange vectors 2 and 3',
            imp='y')
        t = st.rprimd[1]
        st.rprimd[1] = st.rprimd[2]
        st.rprimd[2] = t
        if st.get_volume() < 0:
            printlog(
                'Error! still negative volume, check your primitive vectors',
                imp='y')
        st.tmap = [1, 3]
    else:
        st.tmap = [1, 2]

    printlog('Final rprimd = \n', np.round(st.rprimd, 3), imp='y')

    st.nznucl = st.get_nznucl()

    st.recip = st.get_recip()

    st.update_xred()

    st.reorder_for_vasp(inplace=True)

    # print(st.perm)
    return st
Example #6
0
def calc_redox(cl1, cl2, energy_ref = None, value = 0, temp = None, silent = 0):
    """
    Calculated average redox potential and change of volume
    cl1 (Calculation) - structure with higher concentration
    cl2 (Calculation) - structure with lower concentration
    energy_ref (float) - energy in eV per one alkali ion in anode; default value is for Li; -1.31 eV for Na, -1.02 eV for K
    
    temperature (float) - potential at temperature, self.F is expected from phonopy calculations
    """
    if cl1 is None or cl2 is None:
        printlog('Warning! cl1 or cl2 is none; return')
        return
    if not hasattr(cl1.end, 'znucl') or not hasattr(cl2.end, 'znucl') :
        printlog('Warning! cl1 or cl2 is bad')
        return

    energy_ref_dict = {3:-1.9,  11:-1.31,  19:-1.02, 37:-0.93}
    z_alk_ions = [3, 11, 19, 37]


    #normalize numbers of atoms by some element except Li, Na, K
    alk1l = [] 
    alk2l = []
    # print cl1.end.znucl
    for i, z in enumerate(cl1.end.znucl):
        # print i, z
        if z in z_alk_ions: 
            alk1l.append(i)
            # print 'i_alk is found'
            continue
        # print i, z

        for j, zb in enumerate(cl2.end.znucl):
            if zb in z_alk_ions: 
                # j_alk = j
                alk2l.append(j)
                continue

            if z == zb:
                # print "I use ", z, " to normalize"
                i_n1 = i
                i_n2 = j

    n1  = cl1.end.nznucl[i_n1]
    n2  = cl2.end.nznucl[i_n2]


    nz1_dict = {}
    nz2_dict = {}
    n_alk1 = 0
    n_alk2 = 0
    for z in z_alk_ions:
        nz1_dict[z] = 0 
        nz2_dict[z] = 0 

    for i in alk1l:
        nz1_dict[ cl1.end.znucl[i] ] = cl1.end.nznucl[i]
    for i in alk2l:
        nz2_dict[ cl2.end.znucl[i] ] = cl2.end.nznucl[i]

    for z in z_alk_ions:
        mul = (nz1_dict[z] / n1 - nz2_dict[z] / n2)
        if abs(mul) > 0: #only change of concentration of one ion type is allowed; the first found is used
            printlog('Change of concentration detected for ', element_name_inv(z))
            if not energy_ref: #take energy ref from dict
                energy_ref = energy_ref_dict[ z ]
            break

    # print(energy_ref)
    # print(cl1.energy_sigma0, cl2.energy_sigma0, mul)
    
    e1 = cl1.energy_sigma0 
    e2 = cl2.energy_sigma0
    if temp != None:
        #temperature corrections
        e1 += cl1.F(temp)
        e2 += cl2.F(temp)
        # print(cl1.F(temp), cl2.F(temp))
        # print(e1, cl1.energy_sigma0)
        # print(e2, cl2.energy_sigma0)


    if abs(mul) > 0:
        redox = -(  ( e1 / n1 -  e2 / n2 ) / mul  -  energy_ref  )
    else:
        redox = 0

    # print(n1, n2)

    dV = cl1.end.vol / n1 - cl2.end.vol / n2 

    vol_red = dV / (cl1.end.vol/n1) * 100 # %

    # final_outstring = ("{:} | {:.2f} eV \n1".format(cl1.id[0]+'.'+cl1.id[1], redox  ))
    final_outstring = ("{:45} | {:30} | {:10.2f} V | {:10.1f} % | {:6.2f}| {:6.2f}| {:6.0f}| {:6.0f} | {:3.0f}".format(cl1.name,cl2.name, redox, vol_red, cl1.energy_sigma0, cl2.energy_sigma0, cl1.maxforce, cl2.maxforce, value ))
    
    if not silent:
        printlog( final_outstring, end = '\n', imp = 'y' )
    
    try:
        cl1.set.update()

        results_dic = {'is':cl1.id[0], 'redox_pot':redox, 'id_is':cl1.id, 'id_ds':cl2.id, 
        'kspacing':cl1.set.kspacing, 'time':cl1.time/3600.,
        'mdstep':cl1.mdstep, 'ecut':cl1.set.ecut, 'niter':cl1.iterat/cl1.mdstep,
        'set_is':cl1.id[1], 'vol_red':vol_red }
    except:
        results_dic = {'redox_pot':redox, 'vol_red':vol_red}


    return results_dic
Example #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.0
            print "\n\nPositions of boundaries gb1 and gb2", gbpos1, gbpos2
            print "Maximum possible distance between boundary and impurity", r1x / 4
        else:
            gbpos2 = 0
            gbpos1 = 0

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

        n_neighbours = 8  # number of atoms to calculate sums

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

        sumrlist = []  # list of sumr1+sumr2

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

        diffprec = 0.02

        # print xcart_pores

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                k += 1

        dlist.sort(key=itemgetter(0))

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

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

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

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

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

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

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

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

                if el1 == el2:
                    continue

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

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

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

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

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

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

        return dlist
Example #8
0
def plot_dos(cl1, cl2 = None, dostype = None, iatom = 0, orbitals = ('s'), up = None, neighbors = 6, show = 1, path = 'dos', xlim = (None, None), ylim = (None,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
    up - 'up2' allows to download the file once again


    iatom (int) - number of atom starting from 1 to plot DOS by default it is assumed that the last atom is used
    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

    xlim, ylim (tuple)- limits for plot

    #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.

    """
    iatom -= 1





    """1. Read dos"""
    printlog("------Start plot_dos()-----", imp = 'Y')
    dos = []
    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', update = up); 
        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

    


    

    """2. Plot dos for different cases"""
    if dostype == 'total':

        fit_and_plot(show = show, image_name = os.path.join(path, cl1.name+'.dosTotal'), xlabel = "Energy (eV)", ylabel = "DOS (states/eV)",
            xlim = xlim, ylim = ylim,
            Total = (dos[0].energy, smoother(dos[0].dos, 10), 'b-'))

    elif dostype == 'diff_total':

        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)",
                xlim = xlim, ylim = ylim,
                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 
       
        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)

        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)
            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] # first atom is impurity if exist
        printlog("Numbers of local atoms:", [n+1 for n in numbers] )
        printlog("List of distances", [round(d,2) for d in local_atoms[3]] )


        iX = numbers[0]

        for j in range(len(dos)):
            
            dos[j].p = [] #central and and surrounding
            dos[j].d = [] #central atom and surrounding atoms
            dos[j].d6 = 0 #sum by six atoms

            for i in numbers: #Now for surrounding atoms in numbers list:

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


                dlist = [dos[j].site_dos(i, l)  for l in (4,5,6,7,8) ] # For total d T96C
                dsum = [ sum(x) for x in zip(*dlist) ] 
                dos[j].d.append(  dsum   )
            

            dos[j].p6 = [ sum(pi) for pi in zip(*dos[j].p) ] #sum over neighbouring atoms
            dos[j].d6 = [ sum(di) for di in zip(*dos[j].d) ] #sum over neighbouring atoms

            # t2g = [dos[0].site_dos(iTi, l)  for l in 4,5,7] #  Now only for first Ti atom
            # dos[0].t2g =  [ sum(x) for x in zip(*t2g) ]  

            # eg = [dos[0].site_dos(iTi, l)  for l in 8, 6] #  Now only for first Ti atom
            # dos[0].eg =  [ sum(x) for x in zip(*eg) ] 
           


        """Plotting"""
        nsmooth = 15 # smooth of dos
        d1 = dos[0]
        energy1 = dos[0].energy
        args = {}
        i_orb = {'s':0, 'py':1, 'pz':2, 'px':3, 'dxy':4, 'dyz':5, 'dz2':6, 'dxz':7, 'dx2':8}
        color = {'s':'k-', 'p':'g-', 'd':'b-', 'py':'r-', 'pz':'b-', 'px':'c-', 'dxy':'m-', 'dyz':'c-', 'dz2':'m-', 'dxz':'r-', 'dx2':'g-'}

        for orb in orbitals:
            if orb == 'p':
                args[orb] = (d1.energy, smoother(d1.p[0], nsmooth), color[orb])
            elif orb == 'd':
                args[orb] = (d1.energy, smoother(d1.d[0], nsmooth), color[orb])
            else:
                args[orb] = (d1.energy, smoother(d1.site_dos(iX, i_orb[orb]), nsmooth), color[orb])

        image_name = os.path.join(path, cl1.name+'.'+''.join(orbitals)+'.'+el+str(iX))

        fit_and_plot(show = show, image_name = image_name, figsize = (4,6), xlabel = "Energy (eV)", ylabel = "DOS (states/eV)", 
        # title = cl1.name.split('.')[0]+'; V='+str(round(cl1.vol) )+' $\AA^3$; Impurity: '+el,
        xlim = xlim, ylim = ylim, legend = 2,
        **args
        )
        # printlog("Writing file", image_name, imp = 'Y')

        """Additional dos analysis; to be refined"""

        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}
Example #9
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],  #number, d1, d2, name,  sumr1, sumr2, dgb1, dgb2

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

                if el1 == el2: continue

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

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

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

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

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

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

        return dlist