def core_energy(core_atom, bulk_nn, orbital='1s', ox_states=None, nn_method=CrystalNN(), outcar='OUTCAR', structure='POSCAR'): """ Parses the structure and OUTCAR files for the core level energy. Check the validity of nearest neighbour method on the bulk structure before using it on slabs. Args: core_atom (`str`, optional): The symbol of atom the core state energy level should be parsed from. bulk_nn (`list`, optional): The symbols of the nearest neighbours of the `core_atom`. orbital (`str`, optional): The orbital of core state. Defaults to 1s. ox_states (``None``, `list` or `dict`, optional): Add oxidation states to the structure. Different types of oxidation states specified will result in different pymatgen functions used. The options are: * if supplied as ``list``: The oxidation states are added by site e.g. ``[3, 2, 2, 1, -2, -2, -2, -2]`` * if supplied as ``dict``: The oxidation states are added by element e.g. ``{'Fe': 3, 'O':-2}`` * if ``None``: The oxidation states are added by guess. Defaults to ``None``. nn_method (`class` instance, optional): The coordination number algorithm used. Because the ``nn_method`` is a class, the class needs to be imported from pymatgen.analysis.local_env before it can be instantiated here. Defaults to ``CrystalNN()``. outcar (`str`, optional): Path to the OUTCAR file. Defaults to ``./OUTCAR``. structure (`str`, optional): Path to the structure file in any format supported by pymatgen. Defaults to ``./POSCAR``. Can also accept a pymaten.core.Structure object directly. Returns: Core state energy """ struc = _instantiate_structure(structure) struc = oxidation_states(struc, ox_states) bonded_struc = nn_method.get_bonded_structure(struc) bulk_nn.sort() bulk_nn_str = ' '.join(bulk_nn) # Get the nearest neighbours info, the c-coordinate and index number # for each atom list_of_dicts = [] for n, pos in enumerate(struc): if pos.specie.symbol == core_atom: nn_info = bonded_struc.get_connected_sites(n) slab_nn_list = [] for d in nn_info: nn = d.site.specie.symbol slab_nn_list.append(nn) slab_nn_list.sort() slab_nn = ' '.join(slab_nn_list) list_of_dicts.append({'atom': n, 'nn': slab_nn, 'c_coord': pos.c}) # Make pandas Dataframe, query the interquartile range of fractional # coordinates of atoms whose nearest neighbour environment is same as the # bulk nearest neighbours provided, get the atom that is the nearest to the # median of the interquartile range df = pd.DataFrame(list_of_dicts) low, high = df['c_coord'].quantile([0.25, 0.75]) df = df.query('@low<c_coord<@high and nn==@bulk_nn_str') atom = df['atom'].quantile(interpolation='nearest') # Check if the df from query isn't empty - if it is it returns # a nan as core energy, otherwise it attempts to extract from OUTCAR if type(atom) is np.float64: core_energy = np.nan else: # Read OUTCAR, get the core state energy otc = Outcar(outcar) core_energy_dict = otc.read_core_state_eigen() try: core_energy = core_energy_dict[atom][orbital][-1] except IndexError: core_energy = np.nan return core_energy
import matplotlib.pyplot as plt ao = "1s" zvals = [0.0, 0.2, 0.4, 0.5, 0.6, 0.8, 1.0] foutcars = ["CL_%3.1f/OUTCAR" % z for z in zvals] print(foutcars) clz = list() clz_e = list() lines = "# Clz eps_i(1s) for all atoms\n" for zval, foutcar in zip(zvals, foutcars): # print("OUTCAR = ", foutcar) out = Outcar(foutcar) cl = out.read_core_state_eigen() clz.append(cl[0][ao][-1]) clz_e.append(cl[0][ao][-1] + out.efermi) line = "%5f" % zval for cl_at in cl: line += "%12.4f" % cl_at[ao][-1] print("%4.1f %10.4f %10.4f %10.4f" % (zval, out.efermi, cl[0][ao][-1], cl[0][ao][-1] + out.efermi)) lines += line + "\n" #print(line) #print(clz) with open("cl.dat", "w") as f: f.write(lines)