import re
import xml.etree.ElementTree as ET
from pathlib import Path
from typing import Union
import numpy as np
from pyprocar.core import DensityOfStates, ElectronicBandStructure, KPath, Structure
from . import qe, vasp
# Physics Contstnats
HARTREE_TO_EV = 27.211386245988 # eV/Hartree
def str2bool(v):
return v.lower() in ("true")
[docs]
class LobsterParser:
"""The class helps parse the information from a lobster calculation
Parameters
----------
dirpath : str or Path, optional
The directory name for the calculation, by default ""
code : str, optional
The code name, by default 'qe'
lobsterin_filepath : str, optional
The lobster in put filename, by default 'lobsterin'
lobsterout_filepath : str, optional
The lobster output filename, by default 'lobsterout'
scfin_filepath : str, optional
The scf.in file for QE calculations, by default "scf.in"
outcar_filepath : str, optional
The outcar for vasp calculations, by default 'OUTCAR'
poscar_filepath : str, optional
The poscar for vasp calculations, by default 'POSCAR'
procar_filepath : str, optional
The procar for vasp calculations, by default 'PROCAR'
dos_interpolation_factor : _type_, optional
The interpolation factor on the density of states, by default None
"""
[docs]
def __init__(
self,
dirpath: Union[str, Path] = "",
code: str = "qe",
lobsterin_filepath: Union[str, Path] = Path("lobsterin"),
lobsterout_filepath: Union[str, Path] = Path("lobsterout"),
scfin_filepath: Union[str, Path] = Path("scf.in"),
outcar_filepath: Union[str, Path] = Path("OUTCAR"),
poscar_filepath: Union[str, Path] = Path("POSCAR"),
procar_filepath: Union[str, Path] = Path("PROCAR"),
dos_interpolation_factor: int = None,
):
# Convert dirpath to Path object
self.dirpath = Path(dirpath)
self.code = code
# Use Path for file operations
lobsterin_filepath = self.dirpath / lobsterin_filepath.name
with open(lobsterin_filepath, "r") as rf:
self.lobsterin = rf.read()
lobsterout_filepath = self.dirpath / lobsterout_filepath.name
with open(lobsterout_filepath, "r") as rf:
self.lobsterout = rf.read()
self.orbitals = [
"s",
"p_y",
"p_z",
"p_x",
"d_xy",
"d_yz",
"d_z^2",
"d_xz",
"d_x^2-y^2",
]
self.dos_interpolation_factor = dos_interpolation_factor
self.scfin_filepath = scfin_filepath
self.parse_structure(
outcar_filepath=outcar_filepath,
poscar_filepath=poscar_filepath,
procar_filepath=procar_filepath,
interpolation_factor=1,
fermi=None,
)
self._getSpecialKpoints()
# For band structures
if len(self.kticks) != 0:
self._readFileNames()
self._readFatBands()
self._createKPath()
self.ebs = ElectronicBandStructure(
kpoints=self.kpoints,
bands=self.bands + self.efermi,
projected=self._spd2projected(self.spd),
efermi=self.efermi,
kpath=self.kpath,
projected_phase=None,
labels=self.orbitals[:-1],
reciprocal_lattice=self.reciprocal_lattice,
interpolation_factor=dos_interpolation_factor,
# shifted_to_efermi=True,
# shifted_to_efermi=False,
)
doscar_path = self.dirpath / "DOSCAR.lobster"
if doscar_path.exists():
self.data = self._parse_doscar(doscar_path)
@property
def species(self):
"""Returns the species of the calculation
Returns
-------
List
Returns a list of string or atomic numbers[int]
"""
return self.initial_structure.species
@property
def structures(self):
"""Returns a list of pyprocar.core.Structure
Returns
-------
List
Returns a list of pyprocar.core.Structure
"""
# symbols = [x.strip() for x in self.data['ions']]
symbols = [x.strip() for x in self.ions]
structures = []
st = Structure(
atoms=symbols,
lattice=self.direct_lattice,
fractional_coordinates=self.atomic_positions,
)
structures.append(st)
return structures
@property
def structure(self):
"""Returns a the last element of a list of pyprocar.core.Structure
Returns
-------
pyprocar.core.Structure
Returns a the last element of a list of pyprocar.core.Structure
"""
return self.structures[-1]
@property
def initial_structure(self):
"""Returns a the first element of a list of pyprocar.core.Structure
Returns
-------
pyprocar.core.Structure
Returns a the first element of a list of pyprocar.core.Structure
"""
return self.structures[0]
@property
def final_structure(self):
"""Returns a the last element of a list of pyprocar.core.Structure
Returns
-------
pyprocar.core.Structure
Returns a the last element of a list of pyprocar.core.Structure
"""
return self.structures[-1]
@property
def dos(self):
"""Initializes the pyprocar.core.DensityOfStates
Returns
-------
pyprocar.core.DensityOfStates
Retruns the pyprocar.core.DensityOfStates object
"""
energies = self.dos_total["energies"]
total = []
for ispin in self.dos_total:
if ispin == "energies":
continue
total.append(self.dos_total[ispin])
# total = np.array(total).T
return DensityOfStates(
energies=energies,
total=total,
projected=self.dos_projected,
interpolation_factor=self.dos_interpolation_factor,
)
"""
Returns the complete density (total,projected) of states as a python dictionary
"""
@property
def dos_to_dict(self):
"""Returns the complete density (total,projected) of states as a python dictionary
Returns
-------
dict
Returns a dictionary with the projected and total denisity of states
"""
return {"total": self._get_dos_total(), "projected": self._get_dos_projected()}
@property
def dos_total(self):
"""Returns the density of states total as a dict.
The keys are energies,Spin-up, Spin-down
Returns
-------
dict
Returns the density of states total as a dict
"""
dos_total, labels = self._get_dos_total()
# dos_total['energies'] -= self.fermi
return dos_total
@property
def dos_projected(self):
"""Returns the projected DOS as a multi-dimentional array,
to be used in the pyprocar.core.DensityOfStates object
Returns
-------
list
A list of projections per atom
"""
ret = []
dos_projected, info = self._get_dos_projected()
if dos_projected is None:
return None
norbitals = len(info) - 1
info[0] = info[0].capitalize()
labels = []
labels.append(info[0])
ret = []
for iatom in dos_projected:
temp_atom = []
for iorbital in range(norbitals):
temp_spin = []
for key in dos_projected[iatom]:
if key == "energies":
continue
temp_spin.append(dos_projected[iatom][key][:, iorbital])
temp_atom.append(temp_spin)
ret.append([temp_atom])
return ret
def _get_dos_total(self):
"""Helper method to get the total density of state
Returns
-------
dict, list
Returns the total_dos dict and label names
"""
energies = self.data["total"][:, 0]
dos_total = {"energies": energies}
if self.nspin != 1:
dos_total["Spin-up"] = self.data["total"][:, 1]
dos_total["Spin-down"] = self.data["total"][:, 2]
# dos_total['integrated_dos_up'] = self.data['total'][:, 3]
# dos_total['integrated_dos_down'] = self.data['total'][:, 4]
else:
dos_total["Spin-up"] = self.data["total"][:, 1]
# dos_total['integrated_dos'] = self.data['total'][:, 2]
return dos_total, list(dos_total.keys())
def _get_dos_projected(self, atoms=[]):
"""
Helper method to get the total density of state
Parameters
-------
atoms: list, optional
Atoms to to iterate through
Returns
-------
list, list
Returns the porjected dos istt and label names
"""
if len(atoms) == 0:
atoms = np.arange(self.initial_structure.natoms)
if "projected" in list(self.data.keys()):
dos_projected = {}
ion_list = [
"ion %s" % str(x + 1) for x in atoms
] # using this name as vasrun.xml uses ion #
for i in range(len(ion_list)):
iatom = ion_list[i]
name = self.initial_structure.atoms[atoms[i]]
energies = self.data["projected"][i][:, 0, 0]
dos_projected[name] = {"energies": energies}
if self.nspin != 1:
dos_projected[name]["Spin-up"] = self.data["projected"][i][:, 1:, 0]
dos_projected[name]["Spin-down"] = self.data["projected"][i][
:, 1:, 1
]
else:
dos_projected[name]["Spin-up"] = self.data["projected"][i][:, 1:, 0]
return dos_projected, self.data["projected_labels_info"]
else:
print("This calculation does not include partial density of states")
return None, None
[docs]
def dos_parametric(self, atoms=None, orbitals=None, spin=None, title=None):
"""This function sums over the list of atoms and orbitals given
for example dos_paramateric(atoms=[0,1,2],orbitals=[1,2,3],spin=[0,1])
will sum all the projections of atoms 0,1,2 and all the orbitals of 1,2,3 (px,py,pz)
and return separatly for the 2 spins as a DensityOfStates object from pychemia.visual.DensityofStates
Parameters
----------
atoms : list[int], optional
list of atom index needed to be sumed over., by default None
orbitals : list[int], optional
list of orbitals needed to be sumed over
| s || py || pz || px || dxy || dyz || dz2 || dxz ||x2-y2||
| 0 || 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 ||, by default None
spin : list[int], optional
which spins to be included, by default None
title : str, optional
Title, by default None
Returns
-------
pyprocar.core.DensityOfStates
Returns the dos object
"""
projected = self.dos_projected
dos_projected, labelsInfo = self._get_dos_projected()
self.availiableOrbitals = list(labelsInfo.keys())
self.availiableOrbitals.pop(0)
if atoms == None:
atoms = np.arange(self.nions, dtype=int)
if spin == None:
spin = [0, 1]
if orbitals == None:
orbitals = np.arange((len(projected[0].labels) - 1) // 2, dtype=int)
if title == None:
title = "Sum"
orbitals = np.array(orbitals)
if len(spin) == 2:
labels = ["Energy", "Spin-Up", "Spin-Down"]
new_orbitals = []
for ispin in spin:
new_orbitals.append(
list(orbitals + ispin * (len(projected[0].labels) - 1) // 2)
)
orbitals = new_orbitals
else:
for x in orbitals:
if x + 1 > (len(projected[0].labels) - 1) // 2:
print("listed wrong amount of orbitals")
print(
"Only use one or more of the following "
+ str(np.arange((len(projected[0].labels) - 1) // 2, dtype=int))
)
print(
"Only use one or more of the following "
+ str(np.arange((len(projected[0].labels) - 1) // 2, dtype=int))
)
print(
"They correspond to the following orbitals : "
+ str(self.availiableOrbitals)
)
print("Again do not trust the plot that was just produced")
if spin[0] == 0:
labels = ["Energy", "Spin-Up"]
elif spin[0] == 1:
labels = ["Energy", "Spin-Down"]
ret = np.zeros(shape=(len(projected[0].energies), len(spin) + 1))
ret[:, 0] = projected[0].energies
for iatom in atoms:
if len(spin) == 2:
ret[:, 1:] += self.dos_projected[iatom].values[:, orbitals].sum(axis=2)
elif len(spin) == 1:
ret[:, 1] += self.dos_projected[iatom].values[:, orbitals].sum(axis=1)
return DensityOfStates(table=ret, title=title, labels=labels)
def _parse_doscar(self, filename):
"""Helper method to parse the DOSCAR
Parameters
----------
filename : str or Path
The filename of the DOSCAR
Returns
-------
dict
Returns a dict with the total, projected, and labels
Raises
------
ValueError
DOSCAR seems truncated
"""
with open(filename, "r") as rf:
data = rf.readlines()
if len(data) < 5:
raise ValueError("DOSCAR seems truncated")
# Skipping the first lines of header
iline = 5
header = [float(x) for x in data[iline].strip().split()]
ndos = int(header[2])
iline += 1
total_dos = [[float(x) for x in y.split()] for y in data[iline : iline + ndos]]
total_dos = np.array(total_dos)
iline += ndos
ndos, total_ncols = total_dos.shape
is_spin_polarized = False
if total_ncols == 5:
is_spin_polarized = True
spins = ["dos_up", "dos_down"]
# In case there are more lines of data, they are the projected DOS
if len(data) > iline:
projected_dos = []
proj_orbitals = []
ion_index = 0
while iline < len(data):
header = [float(x) for x in data[iline].split(";")[0].split()]
# print(header)
ionsList = re.findall(
"calculating FatBand for Element: (.*) Orbital.*", self.lobsterout
)
proj_ions = re.findall(
"calculating FatBand for Element: (.*) Orbital\(s\):\s*.*",
self.lobsterout,
)
proj_orbitals.append((proj_ions[ion_index], data[iline].split(";")[2]))
# print(proj_orbitals)
ion_index += 1
ndos = int(header[2])
iline += 1
tmp_dos = [
[float(x) for x in y.split()] for y in data[iline : iline + ndos]
]
tmp_dos = np.array(tmp_dos)
projected_dos.append(tmp_dos)
iline += ndos
final_projected = []
for i_ion in range(len(projected_dos)):
tmp_dos = np.zeros(shape=[len(projected_dos[i_ion][:, 0]), 10, 2])
for ilabel, label in enumerate(proj_orbitals[i_ion][1].split(), 1):
if is_spin_polarized == False:
tmp_dos[:, 0, 0] = projected_dos[i_ion][:, 0]
if label.find("s") == True:
tmp_dos[:, 1, 0] += projected_dos[i_ion][:, ilabel]
elif label.find("p_y") == True:
tmp_dos[:, 2, 0] += projected_dos[i_ion][:, ilabel]
elif label.find("p_z") == True:
tmp_dos[:, 3, 0] += projected_dos[i_ion][:, ilabel]
elif label.find("p_x") == True:
tmp_dos[:, 4, 0] += projected_dos[i_ion][:, ilabel]
elif label.find("d_xy") == True:
tmp_dos[:, 5, 0] += projected_dos[i_ion][:, ilabel]
elif label.find("d_yz") == True:
tmp_dos[:, 6, 0] += projected_dos[i_ion][:, ilabel]
elif label.find("d_z^2") == True:
tmp_dos[:, 7, 0] += projected_dos[i_ion][:, ilabel]
elif label.find("d_xz") == True:
tmp_dos[:, 8, 0] += projected_dos[i_ion][:, ilabel]
elif label.find("d_x^2-y^2") == True:
tmp_dos[:, 9, 0] += projected_dos[i_ion][:, ilabel]
else:
tmp_dos[:, 0, 0] = projected_dos[i_ion][:, 0]
tmp_dos[:, 0, 1] = projected_dos[i_ion][:, 0]
if label.find("s") == True:
tmp_dos[:, 1, 0] += projected_dos[i_ion][:, 2 * ilabel - 1]
tmp_dos[:, 1, 1] += projected_dos[i_ion][:, 2 * ilabel]
elif label.find("p_y") == True:
tmp_dos[:, 2, 0] += projected_dos[i_ion][:, 2 * ilabel - 1]
tmp_dos[:, 2, 1] += projected_dos[i_ion][:, 2 * ilabel]
elif label.find("p_z") == True:
tmp_dos[:, 3, 0] += projected_dos[i_ion][:, 2 * ilabel - 1]
tmp_dos[:, 3, 1] += projected_dos[i_ion][:, 2 * ilabel]
elif label.find("p_x") == True:
tmp_dos[:, 4, 0] += projected_dos[i_ion][:, 2 * ilabel - 1]
tmp_dos[:, 4, 1] += projected_dos[i_ion][:, 2 * ilabel]
elif label.find("d_xy") == True:
tmp_dos[:, 5, 0] += projected_dos[i_ion][:, 2 * ilabel - 1]
tmp_dos[:, 5, 1] += projected_dos[i_ion][:, 2 * ilabel]
elif label.find("d_yz") == True:
tmp_dos[:, 6, 0] += projected_dos[i_ion][:, 2 * ilabel - 1]
tmp_dos[:, 6, 1] += projected_dos[i_ion][:, 2 * ilabel]
elif label.find("d_z^2") == True:
tmp_dos[:, 7, 0] += projected_dos[i_ion][:, 2 * ilabel - 1]
tmp_dos[:, 7, 1] += projected_dos[i_ion][:, 2 * ilabel]
elif label.find("d_xz") == True:
tmp_dos[:, 8, 0] += projected_dos[i_ion][:, 2 * ilabel - 1]
tmp_dos[:, 8, 1] += projected_dos[i_ion][:, 2 * ilabel]
elif label.find("d_x^2-y^2") == True:
tmp_dos[:, 9, 0] += projected_dos[i_ion][:, 2 * ilabel - 1]
tmp_dos[:, 9, 1] += projected_dos[i_ion][:, 2 * ilabel]
final_projected.append(tmp_dos)
final_labels_index = {
"energies": None,
"s": 0,
"p_y": 1,
"p_z": 2,
"p_x": 3,
"d_xy": 4,
"d_yz": 5,
"d_z^2": 6,
"d_xz": 7,
"d_x^2-y^2": 8,
}
final_labels = list(final_labels_index.keys())
return {
"total": total_dos,
"projected": final_projected,
"projected_labels_info": final_labels,
"ions": ionsList,
}
else:
return {"total": total_dos}
def _readFileNames(self):
"""Helper method to parse filenames form the lobster outfile
Returns
-------
None
None
"""
self.filepaths = []
self.ionsList = re.findall(
"calculating FatBand for Element: (.*) Orbital.*", self.lobsterout
)
proj_orbitals = re.findall(
"calculating FatBand for Element: (.*) Orbital\(s\):\s*(.*)",
self.lobsterout,
)
for proj in proj_orbitals:
orbitals = proj[1].split()
for orbital in orbitals:
filepath = self.dirpath / f"FATBAND_{proj[0]}_{orbital}.lobster"
self.filepaths.append(filepath)
return None
def _readFatBands(self):
"""Helpermethod to parse the fatbands
Returns
-------
None
None
"""
with open(self.filepaths[0], "r") as rf:
projFile = rf.read()
##########################################################################################
# kpoints
##########################################################################################
raw_kpoints = re.findall(
"# K-Point \d+ :\s*([-\.\\d]*)\s*([-\.\\d]*)\s*([-\.\\d]*)", projFile
)
self.kpointsCount = len(raw_kpoints)
self.kpoints = np.zeros(shape=(self.kpointsCount, 3))
for ik in range(len(raw_kpoints)):
for coord in range(3):
self.kpoints[ik][coord] = raw_kpoints[ik][coord]
self.bandsCount = int(re.findall("NBANDS (\d*)", projFile)[0])
self.orbitalCount = 10
self.spd = np.zeros(
shape=(
self.kpointsCount,
self.bandsCount,
self.nspin,
self.ionsCount + 1,
len(self.orbitals) + 2,
)
)
self.bands = np.zeros(shape=(self.kpointsCount, self.bandsCount, self.nspin))
for file in range(len(self.filepaths)):
with open(self.filepaths[file], "r") as rf:
projFile = rf.read()
fatbands_info = re.findall("#\sFATBAND\sfor(.*)", projFile)[0].split()
current_ion = fatbands_info[0]
current_orbital = fatbands_info[1][1:]
iion = 0
iorbital = 0
for i in range(len(self.ionsList)):
if self.ionsList[i] == current_ion:
iion = i
for i in range(len(self.orbitals)):
if self.orbitals[i] == current_orbital:
iorbital = i + 1
fatbands = re.split("# K-Point", projFile)[1:]
for ik, fatband in enumerate(fatbands[:]):
for iband, band in enumerate(fatband.split("\n")[1:-1]):
if self.nspin == 2:
if iband < self.bandsCount:
self.bands[ik, iband, 0] = float(band.split()[1])
self.bands[ik, iband, 1] = float(
fatband.split("\n")[1:][
iband + self.bandsCount
].split()[1]
)
self.spd[ik, iband, 0, iion, iorbital] = float(
band.split()[2]
)
self.spd[ik, iband, 1, iion, iorbital] = float(
fatband.split("\n")[1:-1][
iband + self.bandsCount
].split()[2]
)
else:
self.bands[ik, iband, 0] = float(band.split()[1])
self.spd[ik, iband, 0, iion, iorbital] = float(band.split()[2])
self.spd[:, :, :, :, -1] = np.sum(self.spd[:, :, :, :, 1:-1], axis=4)
self.spd[:, :, :, -1, :] = np.sum(self.spd[:, :, :, 0:-1, :], axis=3)
self.spd[:, :, :, -1, 0] = 0
return None
def _spd2projected(self, spd, nprinciples=1):
"""A helper method to conver spd format to projected format
to be inputed in to pyprocar.core.ElectronicBandStructure
Parameters
----------
spd : np.ndarray
The spd array
nprinciples : int, optional
The principle quantum number, by default 1
Returns
-------
np.ndarray
The projected array
"""
# This function is for VASP
# non-pol and colinear
# spd is formed as (nkpoints,nbands, nspin, natom+1, norbital+2)
# natom+1 > last column is total
# norbital+2 > 1st column is the number of atom last is total
# non-colinear
# spd is formed as (nkpoints,nbands, nspin +1 , natom+1, norbital+2)
# natom+1 > last column is total
# norbital+2 > 1st column is the number of atom last is total
# nspin +1 > last column is total
if spd is None:
return None
natoms = spd.shape[3] - 1
nkpoints = spd.shape[0]
nbands = spd.shape[1]
nspins = spd.shape[2]
norbitals = spd.shape[4] - 2
# if spd.shape[2] == 4:
# nspins = 3
# else:
# nspins = spd.shape[2]
# if nspins == 2:
# nbands = int(spd.shape[1] / 2)
# else:
# nbands = spd.shape[1]
projected = np.zeros(
shape=(nkpoints, nbands, natoms, nprinciples, norbitals, nspins),
dtype=spd.dtype,
)
temp_spd = spd.copy()
# (nkpoints,nbands, nspin, natom, norbital)
temp_spd = np.swapaxes(temp_spd, 2, 4)
# (nkpoints,nbands, norbital , natom , nspin)
temp_spd = np.swapaxes(temp_spd, 2, 3)
# (nkpoints,nbands, natom, norbital, nspin)
# projected[ikpoint][iband][iatom][iprincipal][iorbital][ispin]
# if nspins == 3:
# projected[:, :, :, 0, :, :] = temp_spd[:, :, :-1, 1:-1, :-1]
# elif nspins == 2:
# projected[:, :, :, 0, :, 0] = temp_spd[:, :nbands, :-1, 1:-1, 0]
# projected[:, :, :, 0, :, 1] = temp_spd[:, nbands:, :-1, 1:-1, 0]
# else:
projected[:, :, :, 0, :, :] = temp_spd[:, :, :-1, 1:-1, :]
return projected
def _createKPath(self):
"""Helper method to format thwe kpath information into
the pyprocar.core.KPath
Returns
-------
None
None
"""
self.special_kpoints = np.zeros(shape=(len(self.kticks) - 1, 2, 3))
self.modified_knames = []
for itick in range(len(self.kticks)):
if itick != len(self.kticks) - 1:
self.special_kpoints[itick, 0, :] = self.kpoints[self.kticks[itick]]
self.special_kpoints[itick, 1, :] = self.kpoints[self.kticks[itick + 1]]
self.modified_knames.append(
[self.knames[itick], self.knames[itick + 1]]
)
has_time_reversal = True
self.kpath = KPath(
knames=self.modified_knames,
special_kpoints=self.special_kpoints,
kticks=self.kticks,
ngrids=self.ngrids,
has_time_reversal=has_time_reversal,
)
return None
def _getSpecialKpoints(self):
"""Helper method to get the special kpoints for a given code
Returns
-------
None
None
"""
if self.code == "qe":
numK = int(re.findall("K_POINTS.*\n([0-9]*)", self.scfIn)[0])
raw_kpoints = re.findall(
"K_POINTS.*\n\s*[0-9]*.*\n" + numK * "(.*)\n",
self.scfIn,
)[0]
raw_high_symmetry = []
self.knames = []
self.kticks = []
tickCountIndex = 0
for x in raw_kpoints:
if len(x.split()) == 5:
raw_high_symmetry.append(
(float(x.split()[0]), float(x.split()[1]), float(x.split()[2]))
)
self.knames.append("%s" % x.split()[4].replace("!", ""))
self.kticks.append(tickCountIndex)
if float(x.split()[3]) == 0:
tickCountIndex += 1
self.high_symmetry_points = np.array(raw_high_symmetry)
self.nhigh_sym = len(self.knames)
self.ngrids = []
tick_Count = 1
for ihs in range(self.nhigh_sym):
# self.kticks.append(tick_Count - 1)
self.ngrids.append(int(float(raw_kpoints[ihs].split()[3])))
tick_Count += int(float(raw_kpoints[ihs].split()[3]))
else:
self.knames = []
self.kticks = []
self.high_symmetry_points = []
self.nhigh_sym = []
self.ngrids = []
return None
[docs]
def parse_structure(
self,
outcar_filepath: str = None,
poscar_filepath: str = None,
procar_filepath: str = None,
reciprocal_lattice: np.ndarray = None,
kpoints: str = None,
interpolation_factor: int = 1,
fermi: float = None,
):
"""A method to parse the electronic sturcutue information
Parameters
----------
outcar_filepath : str, optional
The OUTCAR filename, by default None
poscar_filepath : str, optional
The POSCAR filename, by default None
procar_filepath : str, optional
The POSCAR filename, by default None
reciprocal_lattice : np.ndarray, optional
The reciprocal lattice matrix, by default None
kpoints : str, optional
The KPOINTS file name, by default None
interpolation_factor : int, optional
The interpolation factor, by default 1
fermi : float, optional
The fermi energy, by default None
Returns
-------
None
None
"""
if self.code == "vasp":
if outcar_filepath is not None:
outcar = vasp.Outcar(outcar_filepath)
if fermi is None:
fermi = outcar.efermi
reciprocal_lattice = outcar.reciprocal_lattice
if poscar is not None:
poscar = vasp.Poscar(poscar)
structure = poscar.structure
if reciprocal_lattice is None:
reciprocal_lattice = poscar.structure.reciprocal_lattice
if kpoints is not None:
kpoints = vasp.Kpoints(kpoints)
kpath = kpoints.kpath
procar = vasp.Procar(
procar,
structure,
reciprocal_lattice,
kpath,
fermi,
interpolation_factor=interpolation_factor,
)
ebs = procar.ebs
elif self.code == "qe":
scfin_filepath = self.dirpath / self.scfin_filepath.name
with open(scfin_filepath, "r") as rf:
self.scfIn = rf.read()
if self.dirpath is None:
self.dirpath = Path("bands")
parser = qe.QEParser(
scfIn_filename="scf.in",
dirpath=str(
self.dirpath
), # Convert to string for QEParser compatibility
dos_interpolation_factor=None,
)
self.prefix = parser.prefix
self.non_colinear = parser.non_colinear
self.spinCalc = parser.spinCalc
self.spin_orbit = parser.spin_orbit
self.nspin = parser.nspin
self.bandsCount = parser.bandsCount
self.atomic_positions = parser.atomic_positions
self.direct_lattice = parser.direct_lattice
self.species_list = parser.nspecies
self.species_list = parser.species_list
self.ionsCount = parser.ionsCount
self.ions = parser.ions
self.alat = parser.alat
self.composition = parser.composition
self.efermi = parser.efermi
self.reciprocal_lattice = parser.reciprocal_lattice
return None