Source code for pyprocar.procarselect.procarselect

import logging
import re
import sys

import matplotlib.pyplot as plt
import numpy as np

from ..utilsprocar import UtilsProcar


[docs]class ProcarSelect: """ Reduces the dimensionality of the data making it uselful to plot bands. The main data to manipulate is the projected electronic structure. Its shape original is: spd[kpoint][band][ispin][atom][orbital]. The selection of components should be done in order, says, first "ispin", then "atom", and at last "orbital". Note: once any selection has been performed, the data itself changes. Say, if you want compare atom [0] and [1,2], you need two instances of this class. Example to compare the bandstructure of two set of atoms >>> """ def __init__( self, ProcarData=None, deepCopy=True, loglevel=logging.WARNING, mode=None ): self.spd = None self.bands = None self.kpoints = None # self.cspd=None self.mode = mode # We want a logging to tell us what is happening self.log = logging.getLogger("ProcarSelect") self.log.setLevel(loglevel) self.ch = logging.StreamHandler() self.ch.setFormatter( logging.Formatter("%(name)s::%(levelname)s:" " %(message)s") ) self.ch.setLevel(logging.DEBUG) self.log.addHandler(self.ch) # At last, one message to the logger. self.log.debug("ProcarSelect: instanciated") if ProcarData is not None: self.setData(ProcarData, deepCopy) return
[docs] def setData(self, ProcarData, deepCopy=True): """ The data from ProcarData is deepCopy-ed by default (ie: their elements are not modified by this class. Args: -ProcarData: is a ProcarParser instance (or anything with similar functionality, duck typing) -deepCopy=True: If false a shallow copy will be made (saves memory). """ self.log.debug("setData: ...") if deepCopy is True: self.spd = ProcarData.spd.copy() self.bands = ProcarData.bands.copy() self.kpoints = ProcarData.kpoints.copy() # self.cspd = ProcarData.cspd.copy() else: self.spd = ProcarData.spd self.bands = ProcarData.bands self.kpoints = ProcarData.kpoints # self.cspd = ProcarData.cspd self.numspin = self.spd.shape[2] # Number of spins self.log.debug("setData: ... Done") print( "spd shape : %s [kpoints, bands, spins, atoms+1, orbitals+2]" % str(self.spd.shape) ) return
[docs] def selectIspin(self, value=None, separate=False): """ value is a list with the values of Ispin to select. UPDATE: if separate == true, then spin = 0 corresponds to spin up and spin = 1 corresponds to spin down. If not, they give spin density and spin magnetization, respectively. Example: >>> foo = ProcarParser() >>> foo.readFile("PROCAR") >>> bar = ProcarSelect(foo) >>> bar.selectIspin([0]) #just the density """ # all kpoint, all bands, VALUE spin, all the rest self.log.debug("selectIspin: ...") self.log.debug("old spd shape =" + str(self.spd.shape)) # first, testing if the domensionaluty is rigth: dimen = len(self.spd.shape) if dimen != 5: self.log.error( "The array is " + str(dimen) + " dimensional, expecting a" " 5 dimensional array." ) self.log.error( "You should call selectIspin->selecAtom->selectOrbitals, " "in this order." ) raise RuntimeError("Wrong dimensionality of the array") self.log.debug("ispin value = " + str(value)) numofbands = int(self.spd.shape[1] / 2) if separate == False: # spin density or magnetization self.spd = self.spd[:, :, value] self.spd = self.spd.sum(axis=2) self.log.info("new spd shape =" + str(self.spd.shape)) self.log.debug("selectIspin: ...Done") if self.mode == "parametric": if self.numspin > 1: if value == [0]: print("Plotting spin density...") elif value == [1]: print("Plotting spin magnetization...") else: # spin up (spin = 0) and spin down (spin = 1) separately. if value == [0]: # select spin up block self.spd = self.spd[:, :numofbands, 0] elif value == [1]: # select spin down block self.spd = self.spd[:, numofbands:, 0] return
[docs] def selectAtoms(self, value=None, fortran=False): """ value is a list with the values of Atoms to select. The optional `fortran` argument indicates whether a c-like 0-based indexing (`=False`, default) or a fortran-like 1-based (`=True`) is provided in `value`. Example: >>> foo = ProcarParser() >>> foo.readFile("PROCAR") >>> bar = ProcarSelect(foo) >>> bar.selectIspin([...]) >>> bar.selectAtoms([0,1,2]) #atom0+atom1+atom2 Note: this method should be called after select.Ispin """ self.log.debug("selectAtoms: ...") # taking care about stupid fortran indexing if fortran is True: value = [x - 1 for x in value] # all kpoint, all bands, VALUE atoms, all the rest self.log.debug("old shape =" + str(self.spd.shape)) # testing if the dimensionaluty is rigth: dimen = len(self.spd.shape) if dimen != 4: self.log.error( "The array is " + str(dimen) + " dimensional, expecting a" " 4 dimensional array." ) self.log.error( "You should call selectIspin->selecAtom->selectOrbitals, " "in this order." ) raise RuntimeError("Wrong dimensionality of the array") self.spd = self.spd[:, :, value] self.spd = self.spd.sum(axis=2) # self.cspd = self.cspd[:,:,value] # self.cspd = self.cspd.sum(axis=2) self.log.info("new shape =" + str(self.spd.shape)) self.log.debug("selectAtoms: ...Done") return
[docs] def selectOrbital(self, value): """ value is a list with the values of orbital to select. Example: >>> foo = ProcarParser() >>> foo.readFile("PROCAR") >>> bar = ProcarSelect(foo) >>> bar.selectIspin([...]) >>> bar.selectAtoms([...]) >>> bar.selectOrbital([-1]) #the last (`tot`) field to select "p" orbitals just change the argument in the last line to [2,3,4] or as needed Note: this method should be called after `select.Ispin` and `select.Atoms` """ self.log.debug("selectOrbital: ...") self.log.debug("Changing the orbital `values` to have a 0-based indexes") # Mind: the first orbital field is the atoms number, which is not # an orbital, therefore the orbital index is an affective 1-based # therefore all `value` indexes += 1 (well, negative values do not # change ) for i in range(len(value)): if value[i] >= 0: value[i] += 1 self.log.debug("New values (indexes to select) :" + str(value)) # all kpoint, all bands, VALUE orbitals, nothing else? self.spd = self.spd[:, :, value] # self.cspd = self.cspd[:,:,value] self.log.debug("old shape =" + str(self.spd.shape)) # testing if the dimensionaluty is rigth: dimen = len(self.spd.shape) if dimen != 3: self.log.error( "The array is " + str(dimen) + " dimensional, expecting a" " 3 dimensional array." ) self.log.error( "You should call selectIspin->selecAtom->selectOrbitals, " "in this order." ) raise RuntimeError("Wrong dimensionality of the array") self.spd = self.spd.sum(axis=2) # self.cspd=self.cspd.sum(axis=2) self.log.info("new shape =" + str(self.spd.shape)) self.log.debug("selectOrbital: ...Done") return