Source code for pylada.vasp.extract.base

""" Subpackage containing extraction methods for VASP. """
__docformat__  = 'restructuredtext en'
__all__ = ['ExtractBase']
from quantities import g, cm, eV
from ...tools import make_cached
from ...tools.extract import search_factory
from ...error import GrepError

OutcarSearchMixin = search_factory('OutcarSearchMixin', 'OUTCAR', __name__)

[docs]class ExtractBase(object): """ Implementation class for extracting data from VASP output """ def __init__(self): """ Initializes the extraction class. """ super(ExtractBase, self).__init__() @property @make_cached
[docs] def ialgo(self): """ Returns the kind of algorithms. """ result = self._find_first_OUTCAR(r"""^\s*IALGO\s*=\s*(\d+)\s*""") return int(result.group(1))
@property @make_cached
[docs] def algo(self): """ Returns the kind of algorithms. """ return { 68: 'Fast', 38: 'Normal', 48: 'Very Fast', 58: 'Conjugate', 53: 'Damped', 4: 'Subrot', 90: 'Exact', 2: 'Nothing'}[self.ialgo]
@property
[docs] def is_dft(self): """ True if this is a DFT calculation, as opposed to GW. """ try: return self.algo not in ['gw', 'gw0', 'chi', 'scgw', 'scgw0'] except: return False
@property
[docs] def is_gw(self): """ True if this is a GW calculation, as opposed to DFT. """ try: return self.algo in ['gw', 'gw0', 'chi', 'scgw', 'scgw0'] except: return False
@property
[docs] def encut(self): """ Energy cutoff. """ return float(self._find_first_OUTCAR(r"ENCUT\s*=\s*(\S+)").group(1)) * eV
@property @make_cached
[docs] def functional(self): """ Returns vasp functional used for calculation. Requires the functional to be pasted at the end of the calculations. """ from re import compile from .. import exec_input regex = compile('#+ FUNCTIONAL #+\n((.|\n)*)\n#+ END FUNCTIONAL #+') with self.__outcar__() as file: result = regex.search(file.read()) if result is None: return None return exec_input(result.group(1)).vasp
@property
[docs] def success(self): """ Checks that VASP run has completed. At this point, checks for the existence of OUTCAR. Then checks that timing stuff is present at end of OUTCAR. """ regex = r"""General\s+timing\s+and\s+accounting\s+informations\s+for\s+this\s+job""" try: return self._find_last_OUTCAR(regex) is not None except: return False
@property @make_cached
[docs] def datetime(self): """ Greps execution date and time. """ from datetime import datetime regex = r"""executed on .*\n""" result = self._find_first_OUTCAR(regex) if result is None: return result = result.group(0) result = result[result.find('date')+4:].rstrip().lstrip() return datetime.strptime(result, '%Y.%m.%d %H:%M:%S')
@property
[docs] def initial_structure(self): """ Structure at start of calculations. """ from re import compile, M from numpy import array, dot from numpy.linalg import inv from ...crystal import Structure from .. import exec_input try: regex = compile('#+ INITIAL STRUCTURE #+\n((.|\n)*)\n#+ END INITIAL STRUCTURE #+') with self.__outcar__() as file: result = regex.search(file.read(), M) if result is not None: return exec_input(result.group(1)).structure except: pass result = Structure() with self.__outcar__() as file: atom_index, cell_index = None, None cell_re = compile(r"""^\s*direct\s+lattice\s+vectors\s+""") atom_re = compile(r"""^\s*position\s+of\s+ions\s+in\s+fractional\s+coordinates""") for line in file: if cell_re.search(line) is not None: break data = [] for i in range(3): data.append(file.next().split()) try: for i in range(3): result.cell[:,i] = array(data[i][:3], dtype='float64') except: for i in range(3): result.cell[i, :] = array(data[i][-3:], dtype='float64') result.cell = inv(result.cell) for line in file: if atom_re.search(line) is not None: break for specie, n in zip(self.species,self.stoichiometry): for i, line in zip(range(n), file): data = line.split() result.add_atom(pos=dot(result.cell, array(data, dtype='float64')), type=specie) return result
@property def _catted_contcar(self): """ Returns contcar found at end of OUTCAR. """ from re import compile from StringIO import StringIO from ...crystal import read with self.__outcar__() as file: lines = file.readlines() begin_contcar_re = compile(r"""#+\s+CONTCAR\s+#+""") end_contcar_re = compile(r"""#+\s+END\s+CONTCAR\s+#+""") start, end = None, None for i, line in enumerate(lines[::-1]): if begin_contcar_re.match(line) is not None: start = -i; break; if end_contcar_re.match(line) is not None: end = -i if start is None or end is None: raise IOError("Could not find catted contcar.") stringio = StringIO("".join(lines[start:end if end != 0 else -1])) return read.poscar(stringio, self.species) @property @make_cached def _grep_structure(self): """ Greps cell and positions from OUTCAR. """ from re import compile from ...crystal import Structure from numpy.linalg import inv from numpy import array with self.__outcar__() as file: lines = file.readlines() atom_index, cell_index = None, None atom_re = compile(r"""^\s*POSITION\s+""") cell_re = compile(r"""^\s*direct\s+lattice\s+vectors\s+""") for index, line in enumerate(lines[::-1]): if atom_re.search(line) is not None: atom_index = index - 1 if cell_re.search(line) is not None: cell_index = index; break if atom_index is None or cell_index is None: raise GrepError("Could not find structure description in OUTCAR.") result = Structure() try: for i in range(3): result.cell[:,i] = array(lines[-cell_index+i].split()[:3], dtype="float64") except: for i in range(3): result.cell[i,:] = array(lines[-cell_index+i].split()[-3:], dtype="float64") result.cell = inv(result.cell) species = [type for type, n in zip(self.species, self.stoichiometry) for i in xrange(n)] while atom_index > 0 and len(lines[-atom_index].split()) == 6: result.add_atom( pos=array(lines[-atom_index].split()[:3], dtype="float64"), type=species.pop(-1) ) atom_index -= 1 return result @property @make_cached
[docs] def structure(self): """ Greps structure and total energy from OUTCAR. """ if self.nsw == 0 or self.ibrion == -1: return self.initial_structure try: result = self._catted_contcar; except: result = self._contcar_structure try: result = self._contcar_structure except: result = self._grep_structure # tries to find adequate name for structure. try: name = self.system except GrepError: name = '' if len(name) == 0 or name == 'POSCAR created by SUPERPOSCAR': try: title = self.system except GrepError: title = '' if len(title) != 0: result.name = title else: result.name = name if self.is_dft: result.energy = self.total_energy try: initial = self.initial_structure except: pass else: for key, value in initial.__dict__.iteritems(): if not hasattr(result, key): setattr(result, key, value) for a, b in zip(result, initial): for key, value in b.__dict__.iteritems(): if not hasattr(a, key): setattr(a, key, value) # adds magnetization. try: magnetization = self.magnetization except: pass else: if magnetization is not None: for atom, mag in zip(result, magnetization): atom.magmom = sum(mag) # adds stress. try: result.stress = self.stress except: pass # adds forces. try: forces = self.forces except: pass else: for force, atom in zip(forces, result): atom.force = force return result
@property @make_cached
[docs] def LDAUType(self): """ Type of LDA+U performed. """ type = self._find_first_OUTCAR(r"""LDAUTYPE\s*=\s*(\d+)""") if type == None: return None type = int(type.group(1)) if type == 1: return "liechtenstein" elif type == 2: return "dudarev" return type
@property @make_cached
[docs] def HubbardU_NLEP(self): """ Hubbard U/NLEP parameters. """ from ..specie import U as ldaU, nlep from re import M type = self._find_first_OUTCAR(r"""LDAUTYPE\s*=\s*(\d+)""") if type == None: return {} type = int(type.group(1)) species = tuple([ u.group(1) for u in self._search_OUTCAR(r"""VRHFIN\s*=\s*(\S+)\s*:""") ]) # first look for standard VASP parameters. groups = r"""\s*((?:(?:\+|-)?\d+(?:\.\d+)?\s*)+)\s*\n""" regex = r"""\s*angular\s+momentum\s+for\s+each\s+species\s+LDAUL\s+=""" + groups \ + r"""\s*U\s+\(eV\)\s+for\s+each\s+species\s+LDAUU\s+=""" + groups \ + r"""\s*J\s+\(eV\)\s+for\s+each\s+species\s+LDAUJ\s+=""" + groups result = {} for k in species: result[k] = [] for found in self._search_OUTCAR(regex, M): moment = found.group(1).split() LDAU = found.group(2).split() LDAJ = found.group(3).split() for specie, m, U, J in zip(species, moment, LDAU, LDAJ): if int(m) != -1: result[specie].append(ldaU(type, int(m), float(U), float(J))) for key in result.keys(): if len(result[key]) == 0: del result[key] if len(result) != 0: return result # then look for nlep parameters. regex = r"""\s*angular\s+momentum\s+for\s+each\s+species,\s+LDAU#\s*(?:\d+)\s*:\s*L\s*=""" + groups \ + r"""\s*U\s+\(eV\)\s+for\s+each\s+species,\s+LDAU\#\s*(?:\d+)\s*:\s*U\s*=""" + groups \ + r"""\s*J\s+\(eV\)\s+for\s+each\s+species,\s+LDAU\#\s*(?:\d+)\s*:\s*J\s*=""" + groups \ + r"""\s*nlep\s+for\s+each\s+species,\s+LDAU\#\s*(?:\d+)\s*:\s*O\s*=""" + groups result = {} for k in species: result[k] = [] for found in self._search_OUTCAR(regex, M): moment = found.group(1).split() LDAU = found.group(2).split() LDAJ = found.group(3).split() funcs = found.group(4).split() for specie, m, U, J, func in zip(species, moment, LDAU, LDAJ, funcs): if int(m) == -1: continue if int(func) == 1: result[specie].append(ldaU(type, int(m), float(U), float(J))) else: result[specie].append(nlep(type, int(m), float(U), float(J))) for key in result.keys(): if len(result[key]) == 0: del result[key] return result
@property @make_cached
[docs] def pseudopotential(self): """ Title of the first POTCAR. """ return self._find_first_OUTCAR(r"""POTCAR:.*""").group(0).split()[1]
@property @make_cached
[docs] def volume(self): """ Unit-cell volume. """ from numpy import abs from numpy.linalg import det from quantities import angstrom return abs(det(self.structure.scale * self.structure.cell)) * angstrom**3
@property @make_cached
[docs] def reciprocal_volume(self): """ Reciprocal space volume (including 2pi). """ from numpy import abs, pi from numpy.linalg import det, inv from quantities import angstrom return abs(det(inv(self.structure.scale * self.structure.cell))) * (2e0*pi/angstrom)**3
@property @make_cached
[docs] def density(self): """ Computes density of the material. """ from quantities import atomic_mass_unit as amu from ... import periodic_table as pt result = 0e0 * amu; for atom, n in zip(self.species, self.stoichiometry): if atom not in pt.__dict__: return None; result += pt.__dict__[atom].atomic_weight * float(n) * amu return (result / self.volume).rescale(g/cm**3)
@property @make_cached def _contcar_structure(self): """ Greps structure from CONTCAR. """ from ...crystal import read from quantities import eV result = read.poscar(self.__contcar__(), self.species) result.energy = float(self.total_energy.rescale(eV)) if self.is_dft else 0e0 return result @property @make_cached
[docs] def stoichiometry(self): """ Stoichiometry of the compound. """ result = self._find_first_OUTCAR(r"""\s*ions\s+per\s+type\s*=.*$""") if result is None: return None return [int(u) for u in result.group(0).split()[4:]]
@property
[docs] def ions_per_specie(self): """ Alias for stoichiometry. """ return self.stoichiometry
@property @make_cached
[docs] def species(self): """ Greps species from OUTCAR. """ return [ u.group(1) for u in self._search_OUTCAR(r"""VRHFIN\s*=\s*(\S+)\s*:""") ]
@property @make_cached
[docs] def isif(self): """ Greps ISIF from OUTCAR. """ result = self._find_first_OUTCAR(r"""\s*ISIF\s*=\s*(-?\d+)\s+""") if result is None: return None return int(result.group(1))
@property @make_cached
[docs] def nsw(self): """ Greps NSW from OUTCAR. """ result = self._find_first_OUTCAR(r"""\s*NSW\s*=\s*(-?\d+)\s+""") if result is None: return None return int(result.group(1))
@property @make_cached
[docs] def ismear(self): """ Greps smearing function from OUTCAR. """ result = self._find_first_OUTCAR(r"""\s*ISMEAR\s*=\s*(\d+);""") if result is None: return None return int(result.group(1))
@property @make_cached
[docs] def sigma(self): """ Greps smearing function from OUTCAR. """ from numpy import array from quantities import eV result = self._find_first_OUTCAR(r"""\s*ISMEAR\s*=\s*(?:\d+)\s*;\s*SIGMA\s*=\s+(.*)\s+br""") if result is None: return None result = result.group(1).rstrip().lstrip().split() if len(result) == 1: return float(result[0]) * eV return array(result, dtype="float64") * eV
@property
[docs] def relaxation(self): """ Returns the kind of relaxation performed in this calculation. """ from ..keywords import Relaxation return Relaxation().__get__(self)
@property @make_cached
[docs] def ibrion(self): """ Greps IBRION from OUTCAR. """ result = self._find_first_OUTCAR(r"""\s*IBRION\s*=\s*(-?\d+)\s+""") if result is None: return None return int(result.group(1))
@property @make_cached
[docs] def potim(self): """ Greps POTIM from OUTCAR. """ result = self._find_first_OUTCAR(r"""\s*POTIM\s*=\s*(-?\S+)\s+""") if result is None: return None return float(result.group(1))
@property @make_cached
[docs] def lorbit(self): """ Greps LORBIT from OUTCAR. """ result = self._find_first_OUTCAR(r"""\s*LORBIT\s*=\s*(\d+)\s+""") if result is None: return None return int(result.group(1))
@property @make_cached
[docs] def isym(self): """ Greps ISYM from OUTCAR. """ result = self._find_first_OUTCAR(r"""\s*ISYM\s*=\s*(\d+)\s+""") if result is None: return None return int(result.group(1))
@property @make_cached
[docs] def nupdown(self): """ Greps NUPDOWN from OUTCAR. """ result = self._find_first_OUTCAR(r"""\s*NUPDOWN\s*=\s*(\S+)\s+""") if result is None: return None return float(result.group(1))
@property @make_cached
[docs] def lmaxmix(self): """ Greps LMAXMIX from OUTCAR. """ result = self._find_first_OUTCAR(r"""\s*LMAXMIX\s*=\s*(\d+)\s+""") if result is None: return None return int(result.group(1))
@property @make_cached
[docs] def istart(self): """ Greps ISTART from OUTCAR. """ result = self._find_first_OUTCAR(r"""\s*ISTART\s*=\s*(\d+)\s+""") if result is None: return None return int(result.group(1))
@property @make_cached
[docs] def icharg(self): """ Greps ICHARG from OUTCAR. """ result = self._find_first_OUTCAR(r"""\s*ICHARG\s*=\s*(\d+)\s+""") if result is None: return None return int(result.group(1))
@property @make_cached
[docs] def precision(self): """ Greps PREC from OUTCAR. """ result = self._find_first_OUTCAR(r"""\s*PREC\s*=\s*(\S*)\s+""") if result is None: return None if result.group(1) == "accura": return "accurate" return result.group(1)
@property @make_cached
[docs] def ediff(self): """ Greps EDIFF from OUTCAR. """ result = self._find_first_OUTCAR(r"""\s*EDIFF\s*=\s*(\S+)\s+""") if result is None: return None return float(result.group(1))
@property @make_cached
[docs] def ediffg(self): """ Greps EDIFFG from OUTCAR. """ result = self._find_first_OUTCAR(r"""\s*EDIFFG\s*=\s*(\S+)\s+""") if result is None: return None return float(result.group(1))
@property @make_cached
[docs] def lsorbit(self): """ Greps LSORBIT from OUTCAR. """ result = self._find_first_OUTCAR(r"""\s*LSORBIT\s*=\s*(T|F)\s+""") if result is None: return None return result.group(1) == 'T'
@property @make_cached
[docs] def lasph(self): """ Greps LASPH from OUTCAR. """ result = self._find_first_OUTCAR(r"""\s*LASPH\s*=\s*(T|F)\s+""") if result is None: return None return result.group(1) == 'T'
@property @make_cached
[docs] def metagga(self): """ Greps METAGGA from OUTCAR. """ result = self._find_first_OUTCAR(r"""\s*METAGGA\s*=\s*(T|F)\s+""") if result is None: return None return result.group(1) == 'T'
@property @make_cached
[docs] def lreal(self): """ Greps LREAL from OUTCAR. """ result = self._find_first_OUTCAR(r"""\s*LREAL\s*=\s*(T|F)\s+""") if result is None: return None return result.group(1) == 'T'
@property @make_cached
[docs] def lcompat(self): """ Greps LCOMPAT from OUTCAR. """ result = self._find_first_OUTCAR(r"""\s*LCOMPAT\s*=\s*(T|F)\s+""") if result is None: return None return result.group(1) == 'T'
@property @make_cached
[docs] def lreal_compat(self): """ Greps LREAL_COMPAT from OUTCAR. """ result = self._find_first_OUTCAR(r"""\s*LREAL_COMPAT\s*=\s*(T|F)\s+""") if result is None: return None return result.group(1) == 'T'
@property @make_cached
[docs] def lgga_compat(self): """ Greps LGGA_COMPAT from OUTCAR. """ result = self._find_first_OUTCAR(r"""\s*LGGA_COMPAT\s*=\s*(T|F)\s+""") if result is None: return None return result.group(1) == 'T'
@property @make_cached
[docs] def lcorr(self): """ Greps LCORR from OUTCAR. """ result = self._find_first_OUTCAR(r"""\s*LCORR\s*=\s*(T|F)\s+""") if result is None: return None return result.group(1) == 'T'
@property @make_cached
[docs] def ldiag(self): """ Greps LDIAG from OUTCAR. """ result = self._find_first_OUTCAR(r"""\s*LDIAG\s*=\s*(T|F)\s+""") if result is None: return None return result.group(1) == 'T'
@property @make_cached
[docs] def kpoints(self): """ Greps k-points from OUTCAR. Numpy array where each row is a k-vector in cartesian units. """ from re import compile from numpy import array result = [] found_generated = compile(r"""Found\s+(\d+)\s+irreducible\s+k-points""") found_read = compile(r"""k-points in units of 2pi/SCALE and weight""") with self.__outcar__() as file: found = 0 for line in file: if found_generated.search(line) is not None: found = 1; break elif found_read.search(line) is not None: found = 2; break if found == 1: found = compile(r"""Following\s+cartesian\s+coordinates:""") for line in file: if found.search(line) is not None: break file.next() for line in file: data = line.split() if len(data) != 4: break; result.append( data[:3] ) return array(result, dtype="float64") if found == 2: for line in file: data = line.split() if len(data) == 0: break result.append(data[:3]) return array(result, dtype="float64")
@property @make_cached
[docs] def multiplicity(self): """ Greps multiplicity of each k-point from OUTCAR. """ from re import compile from numpy import array result = [] # case where kpoints where generated by vasp. found_generated = compile(r"""Found\s+(\d+)\s+irreducible\s+k-points""") # case where kpoints where given by hand. found_read = compile(r"""k-points in units of 2pi/SCALE and weight""") with self.__outcar__() as file: found = 0 for line in file: if found_generated.search(line) is not None: found = 1; break elif found_read.search(line) is not None: found = 2; break if found == 1: found = compile(r"""Following\s+cartesian\s+coordinates:""") for line in file: if found.search(line) is not None: break file.next() for line in file: data = line.split() if len(data) != 4: break; result.append( data[-1] ) return array(result, dtype="float64") elif found == 2: for line in file: data = line.split() if len(data) == 0: break result.append(float(data[3])) return array([round(r*float(len(result))) for r in result], dtype="float64")
@property @make_cached
[docs] def ispin(self): """ Greps ISPIN from OUTCAR. """ result = self._find_first_OUTCAR(r"""^\s*ISPIN\s*=\s*(1|2)\s+""") if result is None: raise GrepError("Could not extract ISPIN from OUTCAR.") return int(result.group(1))
@property @make_cached
[docs] def name(self): """ Greps POSCAR title from OUTCAR. """ result = self._find_first_OUTCAR(r"""^\s*POSCAR\s*=.*$""") if result is None: raise GrepError("Could not extract POSCAR title from OUTCAR.") result = result.group(0) result = result[result.index('=')+1:] return result.rstrip().lstrip()
@property @make_cached
[docs] def system(self): """ Greps system title from OUTCAR. """ result = self._find_first_OUTCAR(r"""^\s*SYSTEM\s*=.*$""") if result is None: raise GrepError("Could not extract SYSTEM title from OUTCAR.") result = result.group(0) result = result[result.index('=')+1:].rstrip().lstrip() if result[0] == '"': result = result[1:] if result[-1] == '"': result = result[:-1] return result
def _unpolarized_values(self, which): """ Returns spin-unpolarized eigenvalues and occupations. """ from re import compile, finditer import re with self.__outcar__() as file: lines = file.readlines() # Finds last first kpoint. spin_comp1_re = compile(r"\s*k-point\s+1\s*:\s*(\S+)\s+(\S+)\s+(\S+)\s*") found = None for i, line in enumerate(lines[::-1]): found = spin_comp1_re.match(line) if found is not None: break if found is None: raise GrepError("Could not extract eigenvalues/occupation from OUTCAR.") # now greps actual results. if self.is_dft: kp_re = r"\s*k-point\s+(?:(?:\d|\*)+)\s*:\s*(?:\S+)\s*(?:\S+)\s*(?:\S+)\n"\ r"\s*band\s+No\.\s+band\s+energies\s+occupation\s*\n"\ r"(\s*(?:\d+)\s+(?:\S+)\s+(?:\S+)\s*\n)+" skip, cols = 2, 3 else: kp_re = r"\s*k-point\s+(?:(?:\d|\*)+)\s*:\s*(?:\S+)\s*(?:\S+)\s*(?:\S+)\n"\ r"\s*band\s+No\.\s+.*\n\n"\ r"(\s*(?:\d+)\s+(?:\S+)\s+(?:\S+)\s+(?:\S+)\s+(?:\S+)"\ r"\s+(?:\S+)\s+(?:\S+)\s+(?:\S+)\s*\n)+" skip, cols = 3, 8 results = [] for kp in finditer(kp_re, "".join(lines[-i-1:]), re.M): dummy = [u.split() for u in kp.group(0).split('\n')[skip:]] results.append([float(u[which]) for u in dummy if len(u) == cols]) return results def _spin_polarized_values(self, which): """ Returns spin-polarized eigenvalues and occupations. """ from re import compile, finditer import re with self.__outcar__() as file: lines = file.readlines() # Finds last spin components. spin_comp1_re = compile(r"""\s*spin\s+component\s+(1|2)\s*$""") spins = [None,None] for i, line in enumerate(lines[::-1]): found = spin_comp1_re.match(line) if found is None: continue if found.group(1) == '1': if spins[1] is None: raise GrepError("Could not find two spin components in OUTCAR.") spins[0] = i break else: spins[1] = i if spins[0] is None or spins[1] is None: raise GrepError("Could not extract eigenvalues/occupation from OUTCAR.") # now greps actual results. if self.is_dft: kp_re = r"\s*k-point\s+(?:(?:\d|\*)+)\s*:\s*(?:\S+)\s*(?:\S+)\s*(?:\S+)\n"\ r"\s*band\s+No\.\s+band\s+energies\s+occupation\s*\n"\ r"(\s*(?:\d+)\s+(?:\S+)\s+(?:\S+)\s*\n)+" skip, cols = 2, 3 else: kp_re = r"\s*k-point\s+(?:(?:\d|\*)+)\s*:\s*(?:\S+)\s*(?:\S+)\s*(?:\S+)\n"\ r"\s*band\s+No\.\s+.*\n\n"\ r"(\s*(?:\d+)\s+(?:\S+)\s+(?:\S+)\s+(?:\S+)\s+(?:\S+)"\ r"\s+(?:\S+)\s+(?:\S+)\s+(?:\S+)\s*\n)+" skip, cols = 3, 8 results = [ [], [] ] for kp in finditer(kp_re, "".join(lines[-spins[0]:-spins[1]]), re.M): dummy = [u.split() for u in kp.group(0).split('\n')[skip:]] results[0].append([float(u[which]) for u in dummy if len(u) == cols]) for kp in finditer(kp_re, "".join(lines[-spins[1]:]), re.M): dummy = [u.split() for u in kp.group(0).split('\n')[skip:]] results[1].append([u[which] for u in dummy if len(u) == cols]) return results @property @make_cached
[docs] def ionic_charges(self): """ Greps ionic_charges from OUTCAR.""" regex = """^\s*ZVAL\s*=\s*(.*)$""" result = self._find_last_OUTCAR(regex) if result is None: raise GrepError("Could not find ionic_charges in OUTCAR") return [float(u) for u in result.group(1).split()]
@property @make_cached
[docs] def valence(self): """ Greps number of valence bands from OUTCAR.""" ionic = self.ionic_charges species = self.species atoms = [u.type for u in self.structure] result = 0 for c, s in zip(ionic, species): result += c * atoms.count(s) return result
@property @make_cached
[docs] def nelect(self): """ Greps nelect from OUTCAR.""" regex = """^\s*NELECT\s*=\s*(\S+)\s+total\s+number\s+of\s+electrons\s*$""" result = self._find_last_OUTCAR(regex) if result is None: raise GrepError("Could not find energy in OUTCAR") return float(result.group(1))
@property
[docs] def extraelectron(self): """ Returns charge state of the system. """ return self.nelect - self.valence
@property
[docs] def nonscf(self): """ True if non-selfconsistent calculation. """ return self.icharg >= 10
@property
[docs] def lwave(self): """ Greps LWAVE from OUTCAR. """ result = self._find_first_OUTCAR(r"""^\s*LWAVE\s*=\s*(\S)""") if result is None: return None return result.group(1) == 'T'
@property
[docs] def lcharg(self): """ Greps LWAVE from OUTCAR. """ result = self._find_first_OUTCAR(r"""^\s*LCHARG\s*=\s*(\S)""") if result is None: return None return result.group(1) == 'T'
@property
[docs] def lnoncollinear(self): """ Greps LNONCOLLINEAR from OUTCAR. """ result = self._find_first_OUTCAR(r"""^\s*LNONCOLLINEAR\s*=\s*(\S)""") if result is None: return None return result.group(1) == 'T'
@property
[docs] def lsecvar(self): """ Greps LSECVAR from OUTCAR. """ result = self._find_first_OUTCAR(r"""^\s*LSECVAR\s*=\s*(\S)""") if result is None: return None return result.group(1) == 'T'
@property
[docs] def lelf(self): """ Greps LELF from OUTCAR. """ result = self._find_first_OUTCAR(r"""^\s*LELF\s*=\s*(\S)""") if result is None: return None return result.group(1) == 'T'
@property
[docs] def ldipol(self): """ Greps LDIPOL from OUTCAR. """ result = self._find_first_OUTCAR(r"""^\s*LDIPOL\s*=\s*(\S)""") if result is None: return None return result.group(1) == 'T'
@property
[docs] def lvtot(self): """ Greps LVTOT from OUTCAR. """ result = self._find_first_OUTCAR(r"""^\s*LVTOT\s*=\s*(\S)""") if result is None: return None return result.group(1) == 'T'
@property
[docs] def nelm(self): """ Greps NELM from OUTCAR. """ result = self._find_first_OUTCAR(r"""^\s*NELM\s*=\s*(\d+)""") if result is None: return None return int(result.group(1))
@property
[docs] def nelmdl(self): """ Greps NELMDL from OUTCAR. """ regex = r"""^\s*NELM\s*=\s*\d+\s*;"""\ """\s*NELMIN\s*=\s*\d+\s*;"""\ """\s*NELMDL\s*=\s*(-?\d+)""" result = self._find_first_OUTCAR(regex) if result is None: return None return int(result.group(1))
@property
[docs] def nelmin(self): """ Greps NELMIN from OUTCAR. """ regex = r"""^\s*NELM\s*=\s*\d+\s*;\s*NELMIN\s*=\s*(\d+)""" result = self._find_first_OUTCAR(regex) if result is None: return None return int(result.group(1))
@property @make_cached
[docs] def nbands(self): """ Number of bands in calculation. """ result = self._find_first_OUTCAR("""NBANDS\s*=\s*(\d+)""") if result is None: raise GrepError("Could not find NBANDS in OUTCAR.") return int(result.group(1))
@property @make_cached
[docs] def nbprocs(self): """ Number of bands in calculation. """ result = self._find_first_OUTCAR("""running\s+on\s+(\d+)\s+nodes""") if result is None: raise GrepError("Could not find number of processes in OUTCAR.") return int(result.group(1))
[docs] def iterfiles(self, **kwargs): """ iterates over input/output files. :param bool stout: Include standard output files :param bool errors: Include stderr files. :param bool input: Include INCAR file :param bool wavefunctions: Include WAVECAR file :param bool dos: Include DOSCAR file :param bool charge: Include CHGCAR file :param bool structure: Include POSCAR file :param bool contcar: Include CONTCAR file :param bool procar: Include PROCAR file """ from os.path import exists, join from glob import iglob from itertools import chain files = [self.OUTCAR] if kwargs.get('stdout', False): files.append('stdout') if kwargs.get('errors', False): files.append('stderr') if kwargs.get('input', False): files.append('INCAR') if kwargs.get('wavefunctions', False): files.append('WAVECAR') if kwargs.get('dos', False): files.append('DOSCAR') if kwargs.get('charge', False): files.append('CHGCAR') if kwargs.get('structure', False): files.append('POSCAR') if kwargs.get('contcar', False): files.append('CONTCAR') if kwargs.get('procar', False): files.append('PROCAR') for file in files: file = join(self.directory, file) if exists(file): yield file # Add RelaxCellShape directories. for dir in chain( iglob(join(self.directory, "relax_cellshape/[0-9]/")), iglob(join(self.directory, "relax_cellshape/[0-9][0-9]/")), iglob(join(self.directory, "relax_ions/[0-9]/")), iglob(join(self.directory, "relax_ions/[0-9][0-9]/")) ): a = self.__class__(dir) for file in a.iterfiles(**kwargs): yield file
@property @make_cached
[docs] def energy_sigma0(self): """ Greps total energy extrapolated to $\sigma=0$ from OUTCAR. """ if not self.is_dft: raise AttributeError('not a DFT calculation.') from quantities import eV regex = """energy\s+without\s+entropy\s*=\s*(\S+)\s+energy\(sigma->0\)\s+=\s+(\S+)""" result = self._find_last_OUTCAR(regex) if result is None: raise GrepError("Could not find sigma0 energy in OUTCAR") return float(result.group(2)) * eV
@property @make_cached
[docs] def energies_sigma0(self): """ Greps total energy extrapolated to $\sigma=0$ from OUTCAR. """ if not self.is_dft: raise AttributeError('not a DFT calculation.') from numpy import array from quantities import eV regex = """energy\s+without\s+entropy\s*=\s*(\S+)\s+energy\(sigma->0\)\s+=\s+(\S+)""" try: result = [float(u.group(2)) for u in self._search_OUTCAR(regex)] except TypeError: raise GrepError("Could not find energies in OUTCAR") if len(result) == 0: raise GrepError("Could not find energy in OUTCAR") return array(result) * eV
@property @make_cached
[docs] def all_total_energies(self): """ Greps total energies for all electronic steps from OUTCAR.""" if not self.is_dft: raise AttributeError('not a DFT calculation.') from numpy import array from quantities import eV regex = """energy\s+without\s+entropy =\s*(\S+)\s+energy\(sigma->0\)\s+=\s+(\S+)""" try: result = [float(u.group(1)) for u in self._search_OUTCAR(regex)] except TypeError: raise GrepError("Could not find energies in OUTCAR") if len(result) == 0: raise GrepError("Could not find energy in OUTCAR") return array(result) * eV
@property
[docs] def fermi0K(self): """ Fermi energy at zero kelvin. This procedure recomputes the fermi energy using a step-function. It avoids negative occupation numbers. As such, it may be different from the fermi energy given by vasp, depeneding on the smearing and the smearing function. """ if not self.is_dft: raise AttributeError('not a DFT calculation.') from operator import itemgetter from numpy import rollaxis, sum if self.ispin == 2: eigs = rollaxis(self.eigenvalues, 0, 2) else: eigs = self.eigenvalues array = [(e, m) for u, m in zip(eigs, self.multiplicity) for e in u.flat] array = sorted(array, key=itemgetter(0)) occ = 0e0 factor = (2.0 if self.ispin == 1 else 1.0)/float(sum(self.multiplicity)) for i, (e, w) in enumerate(array): occ += w*factor if occ >= self.valence - 1e-8: return e * self.eigenvalues.units return None
@property
[docs] def halfmetallic(self): """ True if the material is half-metallic. """ if not self.is_dft: raise AttributeError('not a DFT calculation.') from numpy import max, abs if self.ispin == 1: return False if self.cbm - self.vbm > 0.01 * self.cbm.units: return False fermi = self.fermi0K vbm0 = max(self.eigenvalues[0][self.eigenvalues[0]<=float(fermi)+1e-8]) vbm1 = max(self.eigenvalues[1][self.eigenvalues[1]<=float(fermi)+1e-8]) return abs(float(vbm0-vbm1)) > 2e0 * min(float(fermi - vbm0), float(fermi - vbm1))
@property
[docs] def cbm(self): """ Returns Condunction Band Minimum. """ if not self.is_dft: raise AttributeError('not a DFT calculation.') from numpy import min return min(self.eigenvalues[self.eigenvalues>self.fermi0K+1e-8*self.fermi0K.units])
@property
[docs] def vbm(self): """ Returns Valence Band Maximum. """ if not self.is_dft: raise AttributeError('not a DFT calculation.') from numpy import max return max(self.eigenvalues[self.eigenvalues<=self.fermi0K+1e-8*self.fermi0K.units])
@property @make_cached
[docs] def total_energies(self): """ Greps total energies for all ionic steps from OUTCAR.""" if not self.is_dft: raise AttributeError('not a DFT calculation.') from numpy import array from quantities import eV regex = """energy\s+without\s+entropy=\s*(\S+)\s+energy\(sigma->0\)\s+=\s+(\S+)""" try: result = [float(u.group(1)) for u in self._search_OUTCAR(regex)] except TypeError: raise GrepError("Could not find energies in OUTCAR") if len(result) == 0: raise GrepError("Could not find energy in OUTCAR") return array(result) * eV
@property @make_cached
[docs] def total_energy(self): """ Greps total energy from OUTCAR.""" if not self.is_dft: raise AttributeError('not a DFT calculation.') from quantities import eV regex = """energy\s+without\s+entropy=\s*(\S+)\s+energy\(sigma->0\)\s+=\s+(\S+)""" result = self._find_last_OUTCAR(regex) if result is None: raise GrepError("Could not find energy in OUTCAR") return float(result.group(1)) * eV
energy = total_energy """ Alias for total_energy. """ @property @make_cached
[docs] def fermi_energy(self): """ Greps fermi energy from OUTCAR. """ if not self.is_dft: raise AttributeError('not a DFT calculation.') from quantities import eV regex = r"""E-fermi\s*:\s*(\S+)""" result = self._find_last_OUTCAR(regex) if result is None: raise GrepError("Could not find fermi energy in OUTCAR") return float(result.group(1)) * eV
@property @make_cached
[docs] def moment(self): """ Returns magnetic moment from OUTCAR. """ if not self.is_dft: raise AttributeError('not a DFT calculation.') regex = r"""^\s*number\s+of\s+electron\s+(\S+)\s+magnetization\s+(\S+)\s*$""" result = self._find_last_OUTCAR(regex) if result is None: raise GrepError("Could not find magnetic moment in OUTCAR") return float(result.group(2))
@property @make_cached
[docs] def pressures(self): """ Greps all pressures from OUTCAR """ if not self.is_dft: raise AttributeError('not a DFT calculation.') from quantities import kbar as kB regex = r"""external\s+pressure\s*=\s*(\S+)\s*kB\s+Pullay\s+stress\s*=\s*(\S+)\s*kB""" try: result = [float(u.group(1)) for u in self._search_OUTCAR(regex)] except TypeError: raise GrepError("Could not find pressures in OUTCAR") if len(result) == 0: raise GrepError("Could not find pressures in OUTCAR") return result * kB
@property @make_cached
[docs] def pressure(self): """ Greps last pressure from OUTCAR """ if not self.is_dft: raise AttributeError('not a DFT calculation.') from quantities import kbar as kB regex = r"""external\s+pressure\s*=\s*(\S+)\s*kB\s+Pullay\s+stress\s*=\s*(\S+)\s*kB""" result = self._find_last_OUTCAR(regex) if result is None: raise GrepError("Could not find pressure in OUTCAR") return float(result.group(1)) * kB
@property @make_cached
[docs] def alphabet(self): """ Greps alpha+bet from OUTCAR """ if not self.is_dft: raise AttributeError('not a DFT calculation.') regex = r"""^\s*E-fermi\s*:\s*(\S+)\s+XC\(G=0\)\s*:\s*(\S+)\s+alpha\+bet\s*:(\S+)\s*$""" result = self._find_last_OUTCAR(regex) if result is None: raise GrepError("Could not find alpha+bet in OUTCAR") return float(result.group(3))
@property @make_cached
[docs] def xc_g0(self): """ Greps XC(G=0) from OUTCAR """ if not self.is_dft: raise AttributeError('not a DFT calculation.') regex = r"""^\s*E-fermi\s*:\s*(\S+)\s+XC\(G=0\)\s*:\s*(\S+)\s+alpha\+bet\s*:(\S+)\s*$""" result = self._find_last_OUTCAR(regex) if result is None: raise GrepError("Could not find xc(G=0) in OUTCAR") return float(result.group(2))
@property @make_cached
[docs] def pulay_pressure(self): """ Greps pressure from OUTCAR """ if not self.is_dft: raise AttributeError('not a DFT calculation.') from quantities import kbar as kB regex = r"external\s+pressure\s*=\s*(\S+)\s*kB\s+" \ r"Pullay\s+stress\s*=\s*(\S+)\s*kB" result = self._find_last_OUTCAR(regex) if result is None: raise GrepError("Could not find pulay pressure in OUTCAR") return float(result.group(2)) * kB
@property @make_cached
[docs] def fft(self): """ Greps recommended or actual fft setting from OUTCAR. """ if not self.is_dft: raise AttributeError('not a DFT calculation.') from re import search, M as re_M from numpy import array regex = r"(?!I would recommend the setting:\s*\n)" \ "\s*dimension x,y,z NGX =\s+(\d+)\s+NGY =\s+(\d+)\s+NGZ =\s+(\d+)" with self.__outcar__() as file: result = search(regex, file.read(), re_M) if result is None: raise GrepError("Could not FFT grid in OUTCAR.""") return array([ int(result.group(1)), int(result.group(2)), int(result.group(3)) ])
@property @make_cached
[docs] def recommended_fft(self): """ Greps recommended or actual fft setting from OUTCAR. """ if not self.is_dft: raise AttributeError('not a DFT calculation.') from re import search, M as re_M from numpy import array regex = r"I would recommend the setting:\s*\n" \ "\s*dimension x,y,z NGX =\s+(\d+)\s+NGY =\s+(\d+)\s+NGZ =\s+(\d+)" with self.__outcar__() as file: result = search(regex, file.read(), re_M) if result is None: raise GrepError("Could not recommended FFT grid in OUTCAR.""") return array([int(result.group(1)), int(result.group(2)), int(result.group(3))])
def _partial_charges_impl(self, grep): """ Greps partial charges from OUTCAR. This is a numpy array where the first dimension is the ion (eg one row per ion), and the second the partial charges for each angular momentum. The total is not included. Implementation also used for magnetization. """ import re from numpy import array result = [] with self.__outcar__() as file: lines = file.readlines() found = re.compile(grep) for index in xrange(1, len(lines)+1): if found.search(lines[-index]) is not None: break if index == len(lines): return None index -= 4 line_re = re.compile(r"""^\s*\d+\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*$""") for i in xrange(0, index): match = line_re.match(lines[-index+i]) if match is None: break result.append([float(match.group(j)) for j in range(1, 5)]) return array(result, dtype="float64") @property @make_cached
[docs] def partial_charges(self): """ Greps partial charges from OUTCAR. This is a numpy array where the first dimension is the ion (eg one row per ion), and the second the partial charges for each angular momentum. The total is not included. """ if not self.is_dft: raise AttributeError('not a DFT calculation.') return self._partial_charges_impl(r"""\s*total\s+charge\s*$""")
@property @make_cached
[docs] def magnetization(self): """ Greps partial charges from OUTCAR. This is a numpy array where the first dimension is the ion (eg one row per ion), and the second the partial charges for each angular momentum. The total is not included. """ if not self.is_dft: raise AttributeError('not a DFT calculation.') return self._partial_charges_impl(r"""^\s*magnetization\s*\(x\)\s*$""")
@property @make_cached
[docs] def eigenvalues(self): """ Greps eigenvalues from OUTCAR. In spin-polarized cases, the leading dimension of the numpy array are spins, followed by kpoints, and finally with bands. In spin-unpolarized cases, the leading dimension are the kpoints, followed by the bands. """ if not (self.is_dft or self.is_gw): raise AttributeError('Neither a DFT not a GW calculation.') from numpy import array from quantities import eV if self.ispin == 2: return array(self._spin_polarized_values(1), dtype="float64") * eV return array(self._unpolarized_values(1), dtype="float64") * eV
@property @make_cached
[docs] def occupations(self): """ Greps occupations from OUTCAR. In spin-polarized cases, the leading dimension of the numpy array are spins, followed by kpoints, and finally with bands. In spin-unpolarized cases, the leading dimension are the kpoints, followed by the bands. """ if not (self.is_dft or self.is_gw): raise AttributeError('Neither a DFT not a GW calculation.') from numpy import array if self.ispin == 2: return array(self._spin_polarized_values(2), dtype="float64") return array(self._unpolarized_values(2), dtype="float64")
@property @make_cached
[docs] def qp_eigenvalues(self): """ Greps quasi-particle eigenvalues from OUTCAR. In spin-polarized cases, the leading dimension of the numpy array are spins, followed by kpoints, and finally with bands. In spin-unpolarized cases, the leading dimension are the kpoints, followed by the bands. """ if not self.is_gw: raise AttributeError('not a GW calculation.') from numpy import array if self.ispin == 2: return array(self._spin_polarized_values(1), dtype="float64") * eV return array(self._unpolarized_values(2), dtype="float64") * eV
@property @make_cached
[docs] def self_energies(self): """ Greps self-energies of each eigenvalue from OUTCAR. In spin-polarized cases, the leading dimension of the numpy array are spins, followed by kpoints, and finally with bands. In spin-unpolarized cases, the leading dimension are the kpoints, followed by the bands. """ if not self.is_gw: raise AttributeError('not a GW calculation.') from numpy import array if self.ispin == 2: return array(self._spin_polarized_values(1), dtype="float64") * eV return array(self._unpolarized_values(3), dtype="float64") * eV
@property @make_cached
[docs] def electropot(self): """ Greps average atomic electrostatic potentials from OUTCAR. """ if not self.is_dft: raise AttributeError('not a DFT calculation.') from re import compile, X as reX from numpy import array from quantities import eV with self.__outcar__() as file: lines = file.readlines() regex = compile( r"average\s+\(electrostatic\)\s+potential\s+at\s+core", \ reX ) for i, line in enumerate(lines[::-1]): if regex.search(line) is not None: break if -i + 2 >= len(lines): raise GrepError("Could not find average atomic potential in file.") regex = compile(r"""(?:\s|\d){8}\s*(-?\d+\.\d+)""") result = [] for line in lines[-i+2:]: data = line.split() if len(data) == 0: break result.extend([m.group(1) for m in regex.finditer(line)]) return array(result, dtype="float64") * eV
@property @make_cached
[docs] def electronic_dielectric_constant(self): """ Electronic contribution to the dielectric constant. """ if not self.is_dft: raise AttributeError('not a DFT calculation.') from re import M as multline from numpy import array regex = r"\s*MACROSCOPIC\s+STATIC\s+DIELECTRIC\s" \ r"+TENSOR\s*\(including local field effects in DFT\)\s*\n" \ r"\s*-+\s*\n" \ r"\s*(\S+)\s+(\S+)\s+(\S+)\s*\n" \ r"\s*(\S+)\s+(\S+)\s+(\S+)\s*\n" \ r"\s*(\S+)\s+(\S+)\s+(\S+)\s*\n" \ r"\s*-+\s*\n" result = self._find_last_OUTCAR(regex, multline) if result is None: raise GrepError('Could not find dielectric tensor in output.') return array( [result.group(i) for i in range(1,10)], \ dtype='float64').reshape((3,3) )
@property @make_cached
[docs] def ionic_dielectric_constant(self): """ Ionic contribution to the dielectric constant. """ if not self.is_dft: raise AttributeError('not a DFT calculation.') from re import M as multline from numpy import array regex = r"\s*MACROSCOPIC\s+STATIC\s+DIELECTRIC" \ r"\s+TENSOR\s+IONIC\s+CONTRIBUTION\s*\n" \ r"\s*-+\s*\n" \ r"\s*(\S+)\s+(\S+)\s+(\S+)\s*\n" \ r"\s*(\S+)\s+(\S+)\s+(\S+)\s*\n" \ r"\s*(\S+)\s+(\S+)\s+(\S+)\s*\n" \ r"\s*-+\s*\n" result = self._find_last_OUTCAR(regex, multline) if result is None: raise GrepError('Could not find dielectric tensor in output.') return array( [result.group(i) for i in range(1,10)], \ dtype='float64').reshape((3,3) )
@property
[docs] def dielectric_constant(self): """ Dielectric constant of the material. """ if not self.is_dft: raise AttributeError('not a DFT calculation.') return self.electronic_dielectric_constant \ + self.ionic_dielectric_constant
@property @make_cached
[docs] def stresses(self): """ Returns total stress at each relaxation step. """ if not self.is_dft: raise AttributeError('not a DFT calculation.') from numpy import zeros, abs, array from numpy.linalg import det from quantities import eV, J, kbar from re import finditer, M if self.isif < 1: return None pattern \ = """\s*Total\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*\n""" \ """\s*in kB\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*\n""" result = [] with self.__outcar__() as file: for regex in finditer(pattern, file.read(), M): stress = zeros((3,3), dtype="float64"), zeros((3,3), dtype="float64") for i in xrange(2): for j in xrange(3): stress[i][j, j] += float(regex.group(i*6+1+j)) stress[i][0,1] += float(regex.group(i*6+4)) stress[i][1,0] += float(regex.group(i*6+4)) stress[i][1,2] += float(regex.group(i*6+4)) stress[i][2,1] += float(regex.group(i*6+4)) stress[i][0,2] += float(regex.group(i*6+4)) stress[i][2,0] += float(regex.group(i*6+4)) if sum(abs(stress[0].flatten())) > sum(abs(stress[1].flatten())): result.append( stress[0] * float(eV.rescale(J) * 1e22 \ / abs(det(self.structure.cell*self.structure.scale))) \ * kbar) else: result.append(stress[1]) return array(result)*kbar
@property
[docs] def stress(self): """ Returns final total stress. """ if not self.is_dft: raise AttributeError('not a DFT calculation.') return self.stresses[-1]
@property @make_cached
[docs] def forces(self): """ Forces on each atom. """ if not self.is_dft: raise AttributeError('not a DFT calculation.') from numpy import array from quantities import angstrom, eV from re import finditer, M pattern = """ *POSITION\s*TOTAL-FORCE\s*\(eV\/Angst\)\s*\n""" \ """\s*-+\s*\n""" \ """(?:\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s*\n)+""" \ """\s*-+\s*\n""" \ """\s*total drift""" with self.__outcar__() as file: for regex in finditer(pattern, file.read(), M): pass return array( [u.split()[3:] for u in regex.group(0).split('\n')[2:-2]], \ dtype="float64" ) * eV / angstrom
@property @make_cached
[docs] def errors(self): """ List of errors. Errors that are encountered more than once are not repeated. """ errors = [] with self.__outcar__() as file: for line in file: if 'ERROR'.lower() in line.lower() and line[-1] not in errors: errors.append(line[:-1]) return errors
@property @make_cached
[docs] def warnings(self): """ List of warnings. Warnings that are encountered more than once are not repeated. """ warnings = [] with self.__outcar__() as file: for line in file: if 'WARNING' in line and line[-1] not in warnings: warnings.append(line[:-1]) return warnings
def __dir__(self): """ Attributes and members of this class. Removes dft and gw attributes if this is not a dft or gw calculation. """ result = set([u for u in dir(self.__class__) if u[0] != '_']) \ | set([u for u in self.__dict__.iterkeys() if u[0] != '_' ]) if not self.is_gw: result -= set(['qp_eigenvalues', 'self_energies']) if not self.is_dft: result -= set( [ 'energy_sigma0', 'energies_sigma0', 'all_total_energies', 'fermi0K', 'halfmetallic', 'cbm', 'vbm', 'total_energies', 'total_energy', 'fermi_energy', 'moment', 'pressures', 'pressure', 'forces', 'stresses', 'stress', 'alphabet', 'xc_g0', 'pulay_pressure', 'fft', 'recommended_fft', 'partial_charges', 'magnetization', 'electropot', 'electronic_dielectric_constant', 'ionic_dielectric_constant', 'dielectric_constant' ] ) return list(result)