Exemple #1
0
    def set_potential(self, znucl, arg=''):
        # print arg

        if not arg:
            arg = header.PATH2POTENTIALS + '/' + invert(znucl)
            printlog('Attention!, Default potentials is chosen from ',
                     header.PATH2POTENTIALS,
                     'for',
                     invert(znucl),
                     imp='Y')

        if type(arg) not in (str, ):
            # sys.exit("\nset_potential error\n")
            raise RuntimeError

        if znucl in self.potdir:
            if arg == self.potdir[znucl]:
                print_and_log(
                    "Warning! You already have the same potential for " +
                    str(znucl) + " element\n")
        # print type(self.potdir)
        self.potdir[znucl] = arg
        self.history += "Potential for " + str(
            znucl) + " was changed to " + arg + "\n"
        print_and_log("Potential for " + str(znucl) + " was changed to " +
                      arg + "\n")

        # self.update()
        return
Exemple #2
0
def form_en(sources, products, norm_el=None):
    """
    Calculate formation energy of reaction.

    sources, products - list of tuples (x, cl), where x is multiplier and cl is calculation
    norm_el  - which element to use for normalization

        'all' - normalize by total number of atoms
        'el' - normalize by this element
        int - divide by this number
    """

    El = []
    Nzl = []

    for ls in [sources, products]:
        E = 0
        Nz = {}
        for x, cl in ls:
            E += x * cl.e0
            for i, z in enumerate(cl.end.znucl):
                if z not in Nz:
                    Nz[z] = 0
                Nz[z] += x * cl.end.nznucl[i]
        El.append(E)
        Nzl.append(Nz)

    for z in Nzl[0]:
        if abs(Nzl[0][z] - Nzl[1][z]) > 1e-5:
            printlog('Error! Number of', invert(z),
                     'atoms in source and product are different!')

    # norm = 1
    if 'all' == norm_el:
        norm = sum(Nzl[0].values())
    elif type(norm_el) == str:
        norm = Nzl[0][invert(norm_el)]
    elif norm_el != None:
        norm = norm_el
    else:
        norm = 1

    print('Normalizing by ', norm_el, norm, 'atoms')

    dE = (El[1] - El[0]) / norm
    print('dE = {:4.2f} eV'.format(dE))

    return dE
Exemple #3
0
def exchange_with_external(st, zr, thickness, external = None):
    """
    external (dict) - {'Ni':['Li']} - atoms from external reservior which can replace existing elements, in this example Ni can replace Li
    """
    
    printlog('Starting exchange with external')

    zr_range = get_zr_range(st, thickness, zr)

    # get  external 
    # print(external.keys())
    el_ext = random.choice(list(external.keys()))

    # get element to change
    el_int = random.choice(external[el_ext])


    nn1 = st.get_specific_elements([invert(el_int)], zr_range = zr_range)

    nn2 = st.get_specific_elements([invert(el_ext)], zr_range = zr_range) # just to know good TM-O distance

    j = random.choice(nn2)

    av2 = st.nn(j, 6, only = [8], from_one = 0, silent = 1)['av(A-O,F)'] # in slab

    if len(nn1) == 0:
        printlog('All atoms were replaced, exiting ', imp = 'y')
        sys.exit()


    for k in range(10):
        i = random.choice(nn1)
        av1 = st.nn(i,          6, only = [8], from_one = 0, silent = 1)['av(A-O,F)']
        if av1 < av2+0.4:
            printlog('The chosen position is compared to the existing in slab for {:s}: {:.2f} {:.2f} A'.format(el_ext, av1, av2), imp = 'y')
            break
        else:
            printlog('Trying ', i)
    else:
        printlog('No more good options, trying all', imp = 'y')

    st_new = st.replace_atoms([i], el_ext)
    printlog('Atom', el_int, i, 'was replaced by ', el_ext, 'from external reservoir')

    return st_new 
Exemple #4
0
def chgsum(cll, el, site, silent=1):
    """
    calculate sum of Bader charges for particular atoms
    """

    for cl in cll:
        # print(cl.id, end = '  ')

        try:
            cl.chgsum[(el, site)] = 0
        except:
            pass
        if not hasattr(cl, 'charges') or len(cl.charges) == 0:
            cl.get_bader_ACF()
        # determine_symmetry_positions(cl.end, el, silent = 0)

    # print('')
    try:
        pos = determine_symmetry_positions(cll[0].end, el, silent=1)
    except:
        printlog('chgsum() Warning!', cll[0].id, 'is broken!')
        return 0

    for p in pos[site]:
        ''
        for cl in cll:
            if not hasattr(cl, 'chgsum'):
                cl.chgsum = {}
                cl.chgsum[(el, site)] = 0

            cl.chgsum[(el, site)] += cl.charges[p]

            # print('{:5.3f}'.format(cl.charges[p]), end = '  ')
        # print('')
    if not silent:
        print('Sum of charges for ', el + str(site + 1), ':')

    el_ind = cl.init.znucl.index(
        invert(el))  # index of element in znucl and zval and nznucl
    zval = cl.init.zval[el_ind]  # number of electrons in chosen potential

    for cl in cll:
        cl.chgsum[(el, site)] /= len(pos[site])

        chgsum = zval - cl.chgsum[(el, site)]

        if cl == cll[0]:
            chgsum_ref = chgsum
        if not silent:

            print('{:5.2f}({:4.2f})'.format(chgsum, chgsum_ref - chgsum), )
    if not silent:
        print('\n')

    # print(cl.charges)
    return chgsum
Exemple #5
0
def find_polaron(st, i_alk_ion, out_prec=1):
    """
    #using magmom, find the transition atoms that have different magnetic moments
    #i_alk_ion - number of ion from 0 to calculate distances to transition metals
    out_prec (int) - precision of magmom output


    # maglist = cli.end.get_maglist()
    # magm = np.array(cli.end.magmom)

    # n_tm = len(magm[maglist])
    # # print(len(maglist))
    # numb, dist, chosen_ion = around_alkali(cli.end, n_tm, atom_num)
    # # print(magm[numb][1:]) 
    # mtm = magm[numb][1:] # the first is alkali

    # m_av = sum(mtm)/len(mtm)
    # print(mtm-m_av)
    """
    def zscore(s):
        # print(np.std(s))
        return (s - np.mean(s)) / np.std(s)

    magmom = np.array(st.magmom)
    if len(magmom) == 0:
        printlog('Warning! magmom is empty')

    _, mag_numbers = st.get_maglist()

    pol = {}
    # for z in mag_numbers:
    #     pos = determine_symmetry_positions(st, invert(z))

    # sys.exit()
    magmom_tm = None
    for key in mag_numbers:
        printlog('Looking at polarons on transition atoms: ', invert(key))
        numbs = np.array(mag_numbers[key])
        # print(numbs)
        # print(magmom)
        magmom_tm = magmom[numbs]
        dev = np.absolute(zscore(magmom_tm))
        # print(magmom_tm)
        # print(list(zip(magmom_tm, dev.round(1))))
        # p = np.where(dev>2)[0] # 2 standard deviations
        # print(dev>2)
        # print (type(numbs))
        nstd = 1.5
        # nstd = 4
        i_pols = numbs[dev > nstd]

        if len(i_pols) > 0:
            x1 = st.xcart[i_alk_ion]
            d_to_pols = []
            for j in i_pols:
                x2 = st.xcart[j]
                d, _ = st.image_distance(x1, x2, st.rprimd)
                d_to_pols.append(d)
            print(
                'polarons are detected on atoms', [i + 1 for i in i_pols],
                'with magnetic moments:', magmom[i_pols],
                'and distances: ' + ', '.join('{:2.2f}'.format(d)
                                              for d in d_to_pols), 'A')
            print('mag moments on trans. atoms:', magmom_tm.round(out_prec))

            pol[key] = i_pols
        else:
            print('no polarons is detected with nstd', nstd)
            print('mag moments on trans. atoms:', magmom_tm.round(out_prec))
            # print(' deviations                :', dev.round(1))
            pol[key] = None
    return pol, magmom_tm
Exemple #6
0
def create_segregation_cases(it,
                             ise,
                             verlist,
                             dist_gb,
                             gbpos=None,
                             ise_new=None,
                             option=None,
                             precip_folder=None,
                             use_init=False,
                             precision=None):
    """
    Written for Ti-Fe project.
    Allows to create segregation by substituting atoms;
    dist_gb - distance from gb inside which the atoms are included
    

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


    !Warning PBC are not used in determination of seg positions 

    """

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

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

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

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

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

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

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

    cl_list = []
    sumr_list = []

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

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

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

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

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

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

            if option == 'precip':
                it_new_path = precip_folder

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

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

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

    for d in des_list:
        print(d)

    for d in add_list:
        print(d)

    return
Exemple #7
0
def add_neb(starting_calc=None,
            st=None,
            st_end=None,
            it_new=None,
            ise_new=None,
            i_atom_to_move=None,
            up='up2',
            search_type='vacancy_creation',
            images=None,
            r_impurity=None,
            calc_method=['neb'],
            inherit_option=None,
            mag_config=None,
            i_void_start=None,
            i_void_final=None,
            atom_to_insert=None,
            atom_to_move=None,
            rep_moving_atom=None,
            end_pos_types_z=None,
            replicate=None,
            it_new_folder=None,
            it_folder=None,
            inherit_magmom=False,
            x_start=None,
            xr_start=None,
            x_final=None,
            xr_final=None,
            upload_vts=False,
            center_on_moving=True,
            run=False,
            add_loop_dic=None,
            old_behaviour=None,
            params=None):
    """
    Prepare needed files for NEB
    Provides several regimes controlled by *search_type* flag:
        - existing_voids - search for voids around atom and use them as a final position 
        - vacancy_creation - search for neighbors of the same type and make a vacancy as a start position
        - interstitial_insertion - search for two neighboring voids; use them as start and final positions
                                    by inserting atom *atom_to_insert*
        - None - just use st and st2 as initial and final

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

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

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

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

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

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

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

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

    ###RETURN:
        None

    ###DEPENDS:

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


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

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

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

    if not add_loop_dic:
        add_loop_dic = {}

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

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

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

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

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

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

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

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

    # print(corenum)
    # sys.exit()

    # print(atom_to_insert)
    # sys.exit()

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

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

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

    name_suffix = ''
    st_pores = []

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

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

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

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

        st1 = st
        st2 = st_end

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

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

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

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

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

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

        else:

            atoms_to_move = []
            atoms_to_move_types = []

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

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

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

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

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

                type_atom_to_move = atom_to_move  #atoms_to_move[0][1]

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

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

                    numbers = determine_symmetry_positions(st, atom_to_move)

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

                else:
                    i_m = numbers[0][0]

                x_m = st.xcart[i_m]

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

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

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

            else:

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

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

                insert_positions = determine_unique_voids(st_pores, sums, avds)

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

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

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

                name_suffix += 'i' + str(i_void_start)

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

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

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

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

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

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

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

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

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

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

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

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

            if i_void_final == None:
                sys.exit()

            x_final = sur[0][i_void_final]  #

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

            x_del = x_final  #please compare with vacancy creation mode

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

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

            st1 = st

            st2 = st.mov_atoms(i_m, x_final)

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

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

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

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

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

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

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

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

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

            # print(x_m)
            # print(sur)

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

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

            # sys.exit()

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

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

            # sys.exit()

            header.temp_chosen_dist = chosen_dist

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

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

                # print(name_suffix)
                # sys.exit()

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

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

            # print st.magmom
            # print st1.magmom

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

                st1 = st1.del_atom(i_del)

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

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

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

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

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

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

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

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

        cl_test.actualize_set()  #find magmom for current structure

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

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

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

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

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

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

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

        if mag_config != None:

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

            name_suffix += 'm' + str(mag_config)

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

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

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

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

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

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

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

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

        if not it_new_folder and not it_folder:

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

    if rep_moving_atom:
        it_new += 'r' + rep_moving_atom

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

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

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

    cl = CalculationVasp()

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

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

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

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

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

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

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

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

    #write final position

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

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

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

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

    if center_on_moving and search_type is not None:

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

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

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

    #prepare calculations
    # sys.exit()

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

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

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

    inherit_ngkpt(it_new, it, varset[ise_new])

    if run:
        add_loop_dic['run'] = run

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

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

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

    printlog('add_neb finished')
    return it_new
Exemple #8
0
def find_polaron(st, i_alk_ion, out_prec=1, nstd=1.5):
    """
    Find TM atoms with outlying magnetic moments, which 
    is a good indication of being a small polaron

    Can be problems with charged-ordered materials

    INPUT:
        i_alk_ion - number of ion from 0 to calculate distances to detected polarons
        out_prec (int) - precision of magmom output

        nstd - number of standart deviations to detect polaron

    RETURN:
        pol (dict of int) - numbers of atoms, where polarons are detected for each TM element 
        magmom_tm (list of float) - just magmom for TM


    TODO:
        1. Add analysis of bond lengths to distinguish small polarons
            Janh-Teller
        2. Add treatment of charged-ordered


    """
    def zscore(s):
        # print(np.std(s))
        return (s - np.mean(s)) / np.std(s)

    magmom = np.array(st.magmom)
    if len(magmom) == 0:
        printlog('Warning! magmom is empty')

    _, mag_numbers = st.get_maglist()

    pol = {}
    # for z in mag_numbers:
    #     pos = determine_symmetry_positions(st, invert(z))

    # sys.exit()
    magmom_tm = None
    for z in mag_numbers:
        printlog('Looking at polarons on transition atoms: ', invert(z))
        numbs = np.array(mag_numbers[z])
        # print(numbs)
        # print(magmom)
        magmom_tm = magmom[numbs]
        dev = np.absolute(zscore(magmom_tm))
        # print(magmom_tm)
        # print(list(zip(magmom_tm, dev.round(1))))
        # p = np.where(dev>2)[0] # 2 standard deviations
        # print(dev>2)
        # print (type(numbs))
        # nstd = 1.5
        # nstd = 4
        i_pols = numbs[dev > nstd]

        if len(i_pols) > 0:
            x1 = st.xcart[i_alk_ion]
            d_to_pols = []
            for j in i_pols:
                x2 = st.xcart[j]
                d, _ = st.image_distance(x1, x2, st.rprimd)
                d_to_pols.append(d)
            print(
                'polarons are detected on atoms', [i for i in i_pols],
                'with magnetic moments:', magmom[i_pols],
                'and distances: ' + ', '.join('{:2.2f}'.format(d)
                                              for d in d_to_pols), 'A')
            print('mag moments on trans. atoms:', magmom_tm.round(out_prec))

            pol[z] = i_pols
        else:
            print('no polarons is detected with nstd', nstd)
            print('mag moments on trans. atoms:', magmom_tm.round(out_prec))
            # print(' deviations                :', dev.round(1))
            pol[z] = None
    return pol, magmom_tm
Exemple #9
0
def suf_en(cl1,
           cl2,
           silent=0,
           chem_pot=None,
           return_diff_energy=False,
           ev_a=0,
           normal=2,
           normalize_by=None):
    """Calculate surface energy
    cl1 - supercell with surface
    cl2 - comensurate bulk supercell
    the area is determined from r[0] and r[1];- i.e they lie in surface
    chem_pot (dic) - dictionary of chemical potentials for nonstoichiometric slabs

    normal - normal to the surface 0 - along a, 1 - along b, 2 - along c
    normalize_by - name of element to normalize number of atoms in bulk and slab, if None, transition elements are used

    return_diff_energy (bool) - in addtion to gamma return difference of energies 
    """

    if chem_pot is None:
        chem_pot = {}

    st1 = cl1.end
    st2 = cl2.end
    # pm = st1.convert2pymatgen(oxidation = {'Y':'Y3+', 'Ba':'Ba2+', 'Co':'Co2.25+', 'O':'O2-'})
    natom1 = st1.get_natom()
    natom2 = st2.get_natom()

    if natom1 % natom2:
        printlog('Warning! Non-stoichiometric slab, atom1/natom2 is',
                 natom1 / natom2)

    if normal == 0:
        A = np.linalg.norm(np.cross(st1.rprimd[1], st1.rprimd[2]))

    if normal == 1:
        A = np.linalg.norm(np.cross(st1.rprimd[0], st1.rprimd[2]))

    if normal == 2:
        A = np.linalg.norm(np.cross(st1.rprimd[0], st1.rprimd[1]))

    if not silent:
        print('Surface area is {:.2f} A^2, please check'.format(A))
    # get_reduced_formula
    # print(natom1, natom2)

    if normalize_by:
        ''
        z = invert(normalize_by)
        tra1 = st1.get_specific_elements([z])
        tra2 = st2.get_specific_elements([z])

    else:
        tra1 = st1.get_transition_elements()
        tra2 = st2.get_transition_elements()

    ntra1 = len(tra1)

    # if ntra1 == 0:

    if ntra1 == 0:
        ntra1 = natom1
    ntra2 = len(tra2)
    if ntra2 == 0:
        ntra2 = natom2
    rat1 = natom1 / ntra1
    rat2 = natom2 / ntra2
    mul = ntra1 / ntra2

    # print(rat1, rat2, natom1, ntra1, natom2, ntra2,)
    if not silent:
        print('Number of bulk cells in slab is {:n}'.format(mul))

    if rat1 != rat2:
        printlog('Non-stoichiometric slab, ratios are ',
                 rat1,
                 rat2,
                 'provide chemical potentials',
                 imp='y')

        #get number of TM atoms in slab
        if len(set(tra1)) > 1:
            printlog('More than one type of TM is not supported yet')
            return

        els1 = st1.get_elements()
        els2 = st2.get_elements()
        uniqe_elements = list(set(els1))
        el_dif = {
        }  # difference of elements between slab and normalized by transition metals bulk phase
        for el in uniqe_elements:
            dif = els1.count(el) - mul * els2.count(el)
            if not float(dif).is_integer():
                printlog(
                    'Error! difference of atom numbers is not integer for element ',
                    el, 'something is wrong')
            if abs(dif) > 0:
                el_dif[el] = int(dif)

        print('The following elements are off-stoicheometry in the slab',
              el_dif, 'please provide corresponding chemical potentials')

        E_nonst = 0
        for key in el_dif:
            if key not in chem_pot:
                printlog('Warning! no chemical potential for ', key,
                         'in chem_pot, return')
                return

            E_nonst += el_dif[key] * chem_pot[key]

    else:
        E_nonst = 0

    diff = cl1.e0 - (cl2.e0 * mul + E_nonst)
    gamma = diff / 2 / A * header.eV_A_to_J_m
    gamma_ev = diff / 2 / A
    # print(A)

    if not silent:
        print('Surface energy = {:3.2f} J/m2   | {:} | {:} '.format(
            gamma, cl1.id, cl2.id))
        if ev_a:
            print('Surface energy = {:3.2f} eV/A2   | {:} | {:} '.format(
                gamma_ev, cl1.id, cl2.id))

    if return_diff_energy:
        return gamma, diff
    else:
        return gamma
Exemple #10
0
def add_to_archive_database(cl, subgroup):
    """
    cl is Calculation which should be added to database
    subgroup (str) - subgroup folder

    """

    from pymatgen.core.composition import Composition
    from pymatgen.io.cif import CifWriter
    from pymatgen.symmetry.analyzer import SpacegroupAnalyzer

    join = os.path.join
    basename = os.path.basename
    dirname = os.path.dirname

    save_format = 'azh'
    dbpath = header.PATH2DATABASE
    it = cl.id[0]

    # print(cl.path)
    sub_folder = cl.path['output'].split('/')[
        0]  # usually basic chemical formula
    # sub_folder = header.struct_des[it].sfolder.split('/')[0] # usually basic chemical formula

    print('Processing ', cl.id)
    cl.read_results()

    if '4' not in cl.state:
        return
    st = cl.end

    # print(cl.end.typat)
    # sys.exit()

    if 1:
        #determine x
        #universal method, supports several alkali elements
        #requires cl.base_formula in 'Na2FePO4F' format
        #requires pymatgen, would be nice to remove dependency
        cmb = Composition(cl.base_formula)
        cm = st.get_pm_composition()

        rc = cl.end.get_reduced_composition().as_dict(
        )  #reduced composition dict
        rcb = cmb.reduced_composition.as_dict()

        # print(rc, rcb)

        alk = list(set(st.get_specific_elements(
            header.ALKALI_ION_ELEMENTS)))  # list of unique alkali elements
        tra = list(set(st.get_specific_elements(header.TRANSITION_ELEMENTS)))
        # print(alk, tra)
        el_for_norm = tra[0]  #first element used for normalization

        nnb = rcb[el_for_norm]  #number of norm elements in base
        nn = rc[el_for_norm]  #number of norm elements in interesting structure
        # print(nb, n)
        mul = nn / nnb  # multiplier that garanties normalization

        # print(rcb)
        nab = sum([
            rcb[invert(z)] for z in header.ALKALI_ION_ELEMENTS
            if invert(z) in rcb
        ])

        na = sum([rc[el] for el in alk])
        x = na / mul / nab

        # determine formula
        # cm = st.get_pm_composition() #get pymatgen composition class
        # print( (cm/4).formula)

        # print('Material detected:', formula, 'sub_folder:', sub_folder)

        #obtain base without alk
        formula = (cm.reduced_composition / mul).formula
        # formula = formula.replace('1 ', '').replace(' ', '')
        # print(formula)
        cl.formula = formula
        # print(Composition('Na0.75'))
        print('Material detected:', formula, 'sub_folder:', sub_folder)

        # sys.exit()

    if 0:
        #Old method, not robust at all!
        #determine x for alkali ion from structure name
        parsed = re.findall(r'([A-Z][a-z]*)(\d*)', formula)
        parsed = [(el, x if x else '1') for (el, x) in parsed]
        print(parsed)
        print('detected element is ', parsed[0][0])

        if parsed[0][0] in [invert(z) for z in header.ALKALI_ION_ELEMENTS]:
            x = parsed[0][0]

            if hasattr(cl, 'max_alk_ion_content'):
                x = float(x) / cl.max_alk_ion_content
            else:
                x = '1'

        else:
            x = '0'

    sfolder = os.path.join(dbpath, sub_folder)

    name = []

    if 'azh' in save_format:
        #1. Single point calculation of total energy
        # print(sfolder)
        makedir(join(sfolder, 'dummy'))

        if x < 1:
            x = int(round(100 * x, 0))
        else:
            x = int(round(x, 0))

        print('Concentration x:', x)

        name.append('x' + str(x))
        # sys.exit()

        # if formula in ['LiCoO2', 'LiTiO2', 'LiFePO4', 'NaFePO4', 'LiMnPO4',
        # 'LiNiO2', 'LiTiS2', 'LiMn2O4', 'LiVP2O7', 'LiVPO4F',
        # 'NaMnAsO4', 'Na2FePO4F', 'Na2FeVF7', 'KFeSO4F', 'NaLiCoPO4F', 'KVPO4F' ]:
        sfolder = join(sfolder, subgroup)
        makedir(join(sfolder, 'dummy'))

        cl.set.update()

        # print(cl.potcar_lines)
        potcar1_m = cl.potcar_lines[0][0]

        if '_' in potcar1_m:
            (pot, _) = potcar1_m.split('_')
        else:
            pot = potcar1_m

        xc = cl.xc_inc
        if '-' in xc:
            xc = cl.xc_pot

        if xc == 'PE':
            func = 'PBE'
        elif xc == 'CA':
            func = 'LDA'
        elif xc == 'PS':
            func = 'PBEsol'
        else:
            print('uknown xc type:', xc)
            sys.exit()

        if cl.set.spin_polarized:
            func = 'U' + func  #unrestricted

        u_ramping_flag = False
        if hasattr(cl.set, 'u_ramping_nstep') and cl.set.u_ramping_nstep:
            func += '-UR'
            u_ramping_flag = True

        elif cl.set.dftu:
            func += '-U'
        else:
            func += '-'

        func += pot.lower()
        ecut = str(round(cl.set.ecut))

        func += ecut
        # print(func)
        name.append(func)

        name.extend([it.replace('.', '_')] + [cl.id[1]] + [str(cl.id[2])])

        name_str = '_'.join(name)
        # print('_'.join(name) )

        # sys.exit()

        outcar_name = name_str + '.out'

        shutil.copyfile(cl.path["output"], join(sfolder, outcar_name))

        if u_ramping_flag:
            print(cl.associated_outcars)
            for i, u_outcar in enumerate(
                    cl.associated_outcars[:-1]
            ):  # except the last one, which was copied above
                u = u_outcar.split('.')[1]
                # print(u)
                path_to_outcar = join(dirname(cl.path["output"]), u_outcar)

                cl.read_results(load='o', choose_outcar=i + 1, only_load=1)

                shutil.copyfile(path_to_outcar,
                                join(sfolder, name_str + '_' + u + '.out'))

            # sys.exit()

        cl.end.write_xyz(path=sfolder, filename=name_str)

        pickle_file = cl.serialize(os.path.join(sfolder, 'bin', name_str))
        # cl

        #write input, problem with fitted version 100, which does not have input geometry, since they are created on cluster
        # makedir(sfolder+'input/dummy')
        # shutil.copyfile(cl.path["input_geo"], sfolder+'input/'+name_str+'.geo')

        st_mp = cl.end.convert2pymatgen()
        sg_before = st_mp.get_space_group_info()
        # from pymatgen.symmetry.finder import SymmetryFinder
        # sf = SymmetryFinder(st_mp_prim)
        symprec = 0.1
        sf = SpacegroupAnalyzer(st_mp, symprec=symprec)

        st_mp_prim = sf.find_primitive()
        # st_mp_prim = sf.get_primitive_standard_structure()
        # st_mp_prim = sf.get_conventional_standard_structure()

        # st_mp_conv = sf.get_conventional_standard_structure()
        # print(st_mp_conv)
        # print(st_mp_conv.lattice.matrix)
        # print(st_mp_prim)
        # print(st_mp_prim.lattice)

        sg_after = st_mp_prim.get_space_group_info()

        if sg_before[0] != sg_after[0]:
            printlog(
                'Attention! the space group was changed after primitive cell searching',
                sg_before, sg_after)
            printlog('I will save supercell in cif and reduce symprec to 0.01')
            st_mp_prim = st_mp
            symprec = 0.01

        if st_mp_prim:
            cif = CifWriter(st_mp_prim, symprec=symprec)
            cif_name = name_str + '.cif'
            cif.write_file(join(sfolder, cif_name))
            printlog('Writing cif', cif_name)

        if 0:
            #get multiplication matrix which allows to obtain the supercell from primitive cell.
            #however this matrix is not integer which is not convinient.
            print(st_mp.lattice.matrix.round(2))
            print(st_mp_prim.lattice.matrix.round(2))

            mul_matrix = np.dot(st_mp.lattice.matrix,
                                np.linalg.inv(st_mp_prim.lattice.matrix))

            print(mul_matrix.round(1))

            rprimd = np.dot(mul_matrix, st_mp_prim.lattice.matrix)

            print(rprimd.round(2))

        #write chg
        if 1:
            path_to_chg = cl.get_chg_file('CHGCAR')
            if path_to_chg:
                makedir(join(sfolder, 'bin', 'dummy'))
                printlog('path to chgcar', path_to_chg)
                gz = '.gz'
                if gz not in path_to_chg:
                    gz = ''
                shutil.copyfile(path_to_chg,
                                join(sfolder, 'bin', name_str + '.chg' + gz))

        #write dos
        if subgroup in ['dos', 'DOS']:
            DOSCAR = cl.get_file('DOSCAR', nametype='asoutcar')
            if DOSCAR:
                printlog('path to DOSCAR', DOSCAR)
                gz = '.gz'
                if gz not in path_to_chg:
                    gz = ''
                shutil.copyfile(DOSCAR,
                                join(sfolder, 'bin', name_str + '.dos' + gz))

        if subgroup in ['BAD']:  #bader
            cl.get_bader_ACF()
            acf = cl.get_file(basename(cl.path['acf']))
            # print(acf)
            # sys.exit()
            if acf:
                shutil.copyfile(acf, join(sfolder, 'bin', name_str + '.acf'))

        if subgroup in ['ph', 'PH']:  #bader
            # cl.get_bader_ACF()
            xml = cl.get_file('vasprun.xml', nametype='asoutcar')
            # print(acf)
            # sys.exit()
            if xml:
                shutil.copyfile(xml, join(sfolder, 'bin', name_str + '.xml'))

        #make dat
        #incars
        makedir(join(sfolder, 'dat', 'dummy'))
        incars = glob.glob(join(cl.dir, '*INCAR*'))
        # print(incars)
        for inc in incars:

            dest = join(sfolder, 'dat')
            # inc_name =
            if not os.path.exists(join(dest, basename(inc))):
                shutil.copy(inc, dest)

        #kpoints
        if it in header.struct_des:
            with open(join(sfolder, 'dat', 'kpoints_for_kspacings.json'),
                      'w',
                      newline='') as fp:
                json.dump(
                    header.struct_des[it].ngkpt_dict_for_kspacings,
                    fp,
                )
        else:
            printlog('Warning!, it not in struct_des:', it)
        # print(cl.set.toJSON())

        #prepare for neb
        # makedir(sfolder+'neb_'+name_str+'/dummy')

    return