Source code for pyprocar.io.lobster

import re
import os

import numpy as np
import xml.etree.ElementTree as ET

from pyprocar.core import DensityOfStates, Structure, ElectronicBandStructure, KPath
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 ---------- dirname : str, optional The directory name for the calculation, by default "" code : str, optional The code name, by default 'qe' lobsterin : str, optional The lobster in put filename, by default 'lobsterin' lobsterout : str, optional The lobster output filename, by default 'lobsterout' scfIn_filename : str, optional The scf.in file for QE calculations, by default "scf.in" outcar : str, optional The outcar for vasp calculations, by default 'OUTCAR' poscar : str, optional The poscar for vasp calculations, by default 'POSCAR' procar : 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, dirname = "", code = 'qe', lobsterin = 'lobsterin', lobsterout = 'lobsterout', scfIn_filename = "scf.in", outcar = 'OUTCAR', poscar = 'POSCAR', procar = 'PROCAR', dos_interpolation_factor = None ): if dirname != "": dirname = dirname + os.sep else: dirname = "" self.dirname = dirname self.code = code rf = open(f"{self.dirname}{lobsterin}", "r") self.lobsterin = rf.read() rf.close() rf = open(f"{self.dirname}{lobsterout}", "r") self.lobsterout = rf.read() rf.close() # self.orbitals = [ # {"l": 0, "m": 1}, # {"l": 1, "m": 3}, # {"l": 1, "m": 1}, # {"l": 1, "m": 2}, # {"l": 2, "m": 5}, # {"l": 2, "m": 3}, # {"l": 2, "m": 1}, # {"l": 2, "m": 2}, # {"l": 2, "m": 4}, # ] self.orbitals = [ "s", "p_y", "p_z", "p_x", "d_xy", "d_yz", "d_z^2", "d_xz", "d_x^2-y^2", # "f_y^3-x^2", # "f_xyz", # "f_yz^2", # "f_z^3", # "f_xz^2", # "f_zx^2", # "f_x^3", # "_tot", ] self.dos_interpolation_factor = dos_interpolation_factor self.scfIn_filename = scfIn_filename self.parse_structure( outcar=outcar, poscar=poscar, procar=procar, 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, ) if os.path.exists(f"{self.dirname}DOSCAR.lobster"): self.data = self._parse_doscar(f"{self.dirname}DOSCAR.lobster")
@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 The filename of the DOSCAR Returns ------- dict Returns a dict with the total, projected, and labels Raises ------ ValueError DOSCAR seems truncated """ rf = open(filename) data = rf.readlines() rf.close() 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.file_names = [] 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: fileName = f"{self.dirname}{os.sep}FATBAND_" + proj[0] + "_" + orbital + ".lobster" self.file_names.append(fileName) return None def _readFatBands(self): """Helpermethod to parse the fatbands Returns ------- None None """ rf = open(self.file_names[0], "r") projFile = rf.read() rf.close() ########################################################################################## # 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.file_names)): rf = open(self.file_names[file], "r") projFile = rf.read() rf.close() 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:str=None, poscar:str=None, procar: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 : str, optional The OUTCAR filename, by default None poscar : str, optional The POSCAR filename, by default None procar : 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 is not None: outcar = vasp.Outcar(outcar) 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": rf = open(f"{self.dirname}{self.scfIn_filename}", "r") self.scfIn = rf.read() rf.close() if self.dirname is None: self.dirname = "bands" parser = qe.QEParser(scfIn_filename = "scf.in", dirname = self.dirname, 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