Source code for pyprocar.io.bxsf

__author__ = "Logan Lang"
__maintainer__ = "Logan Lang"
__email__ = "lllang@mix.wvu.edu"
__date__ = "March 31, 2020"

import re
from pathlib import Path
from typing import List, Union

import numpy as np

from pyprocar.core import ElectronicBandStructure


[docs] class BxsfParser: """ The class is used to parse the information inside bxsf files Parameters ---------- filepaths : list, optional This is a list of .bxsf filenames to parse through. It is a list because in some codes there can be multiple .bsxf files representing spin-up and spin-sown bands ,by default ["in.bxsf"] """
[docs] def __init__(self, filepaths: Union[list[Path], Path] = Path("in.bxsf")): self.reciprocal_lattice = None self.origin = None self.nkfs_dim = None self.nkfs = None self.nk_dim = None self.nk = None self.kpoints = None self.band_labels = None self.n_bands = None self.bands = None self.parse_bxsf(filepaths=filepaths) self.ebs = ElectronicBandStructure( kpoints=self.kpoints, bands=self.bands, projected=None, efermi=self.e_fermi, kpath=None, projected_phase=None, labels=None, reciprocal_lattice=self.reciprocal_lattice, interpolation_factor=None, ) return None
[docs] def parse_bxsf(self, filepaths: Union[list[Path], Path]): """A Helper method to parse bxsf files Parameters ---------- infiles : List This is a list of .bxsf filenames to parse through. """ band_labels = [] # If 2 bxsf files search for total number of bands in both files for ispin, filepath in enumerate(filepaths): with open(filepath, "r") as f: data = f.read() band_labels_spin = re.findall("BAND\:\s*(.*)", data) band_labels_spin = [int(band_label) for band_label in band_labels_spin] raw_nkfs = re.findall("BEGIN\_BLOCK\_BANDGRID\_3D\n.*\n.*\n.*\n(.*)", data)[ 0 ] self.nkfs_dim = np.array([int(x) for x in raw_nkfs.split()]) self.nkfs = np.product(self.nkfs_dim) band_labels.extend(band_labels_spin) self.n_bands = max(band_labels) self.bands = np.zeros( shape=[ self.nkfs_dim[0] * self.nkfs_dim[1] * self.nkfs_dim[2], self.n_bands, 2, ] ) # populates bands array and kpoints for ispin, filepath in enumerate(filepaths): with open(filepath, "r") as f: data = f.read() self.e_fermi = float(re.findall("Fermi\sEnergy:\s*([\d.]*)", data)[0]) self.origin = re.findall( "BEGIN\_BLOCK\_BANDGRID\_3D\n.*\n.*\n.*\n.*\n(.*)", data )[0].split() self.origin = np.array([float(x) for x in self.origin]) self.reciprocal_lattice = re.findall( "BEGIN\_BLOCK\_BANDGRID\_3D\n.*\n.*\n.*\n.*\n.*\n" + 3 * "\s*(.*)\s*\n", data, )[0] self.reciprocal_lattice = np.array( [[float(y) for y in x.split()] for x in self.reciprocal_lattice] ) # Bxsf format adds extra redundant +1 dimension-size nkfs is including this dimension raw_nkfs = re.findall("BEGIN\_BLOCK\_BANDGRID\_3D\n.*\n.*\n.*\n(.*)", data)[ 0 ] self.nkfs_dim = np.array([int(x) for x in raw_nkfs.split()]) self.nkfs = np.product(self.nkfs_dim) # Bxsf format adds extra redundant +1 dimension-size, nk is excluding this dimension self.nk_dim = np.array([int(x) - 1 for x in raw_nkfs.split()]) self.nk = np.product(self.nk_dim) self.band_labels = re.findall("BAND\:\s*(.*)", data) # Number of bands self.n_bands = int( re.findall("BEGIN\_BLOCK\_BANDGRID\_3D\n.*\n.*\n\s*(\d*)", data)[0] ) band_labels = re.findall("BAND\:\s*(.*)", data) band_labels = [int(band_label) for band_label in band_labels_spin] if ispin == 0: self.kpoints = np.zeros( shape=[self.nkfs_dim[0] * self.nkfs_dim[1] * self.nkfs_dim[2], 3] ) # 2 for spin band_blocks = re.findall("(?<=BAND:).*\n([\s\S]*?)(?=[A-Za-z])", data) for i, (band_label, band_block) in enumerate(zip(band_labels, band_blocks)): band_energies = band_block.split() band_energies = [float(energy) for energy in band_energies] i_kpoint = 0 iband = band_label - 1 extra_band_energy_indices = [] for i in range(self.nkfs_dim[0]): for j in range(self.nkfs_dim[1]): for k in range(self.nkfs_dim[2]): self.bands[i_kpoint, iband, ispin] = band_energies[i_kpoint] self.kpoints[i_kpoint, :] = np.array( [ (i) / (self.nkfs_dim[0] - 1), (j) / (self.nkfs_dim[1] - 1), (k) / (self.nkfs_dim[2] - 1), ] ) if ( i == self.nkfs_dim[0] - 1 or j == self.nkfs_dim[1] - 1 or k == self.nkfs_dim[2] - 1 ): extra_band_energy_indices.append(i_kpoint) i_kpoint += 1 # Deletes extra kpoints self.kpoints = np.delete(self.kpoints, extra_band_energy_indices, axis=0) # self.kpoints = np.around(self.kpoints.dot(np.linalg.inv(self.reciprocal_lattice)),decimals=8) # Deletes extra band energies self.bands = np.delete(self.bands, extra_band_energy_indices, axis=0) return None