Source code for casm.vasp.io.vasprun

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
from builtins import *

import xml.etree.cElementTree as etree
import os, gzip
import numpy as np


[docs]class VasprunError(Exception): def __init__(self, msg): self.msg = msg def __str__(self): return self.msg
[docs]class Vasprun: """ An object containing values read from vasprun.xml The Vasprun class contains: self.total_energy: final total energy ('e_wo_entrp') self.forces: final forces on atoms (2d list of double) self.atom_type: list of atom types (list of str) self.atoms_per_type: list of number of atoms for each atom type (list of int) self.lattice: final lattice (2d list of double) self.rec_lat: final reciprocal lattice (2d list of double) self.basis: final basis (2d list of double) self.coordinate_mode: coordinate mode for basis (always 'direct') self.is_complete: did the VASP calculation run to completion? (bool) self.dos: Basic DOS output (3d list of double or bool) self.dos_efermi: Fermi level for DOS use (double) self.dos_lm: l or lm-projected DOS output (4d list of double or bool) self.eigenvalues: eigenvalues and energies for doing band structure plots (list of 2d list of double) self.all_e_0: energy (e_0_energy) for each electronic step of each ionic step self.nelm: NELM (max. number of electronic steps) """
[docs] def __init__(self, filename, DOS=False, Band=False): """ Create a Vasprun object from a vasprun.xml file with name 'filename' """ #### Filename ######################### self.filename = filename #### set default values ############### # final energy ('e_wo_entrp') self.total_energy = None # final forces on atoms (2d list) self.forces = [] # list of atom types self.atom_type = [] # list of number of atoms for each atom type self.atoms_per_type = [] # final lattice (2d list) self.lattice = None # final rec lattice (2d list) self.rec_lat = None # final basis (2d list) self.basis = None # coordinate mode for basis self.coordinate_mode = 'direct' # did the VASP calculation run to completion? self.is_complete = False # Is DOS present? self.DOS = DOS # Whether to even read DOS; grabbed from init args self.dos = None # What about band structure? self.Band = Band if self.Band: self.DOS = True # Need to read DOS to do some band things # What is the fermi level? self.efermi = None # is l or lm-projected DOS present? self.dos_lm = None # Energy (e_0_energy) for each electronic step for each ionic step self.all_e_0 = [] ##### read from vasprun.xml file ######## self.iter_read()
def is_complete(self): """ Return True if VASP calculation ran to completion """ return self.is_complete def iter_read(self): """ Create a Vasprun object from a vasprun.xml file with name 'filename' """ if os.path.isfile(self.filename): if self.filename.split(".")[-1].lower() == "gz": f = gzip.open(self.filename) else: f = open(self.filename) elif os.path.isfile(self.filename + ".gz"): f = gzip.open(self.filename + ".gz") else: raise VasprunError("file not found: " + self.filename) for event, elem in etree.iterparse(f): if elem.tag == 'parameters': self.nelm = int(elem.find(".//i[@name='NELM']").text) if elem.tag == 'calculation': #finding the energy of the relaxation self.total_energy = None energy = elem.findall('energy') for child in energy[-1]: if child.attrib['name'] == 'e_wo_entrp': self.total_energy = float(child.text) break child.clear() #finding the forces on the atoms varray = elem.findall('varray') forces = None for v in varray: if v.attrib['name'] == 'forces': forces = v self.forces = [] for child in forces: self.forces.append( [float(i) for i in child.text.strip().split()]) child.clear() v.clear() # find energy (e_0_energy) for each electronic step in this ionic step self.all_e_0.append([]) for i in elem.findall("./scstep/energy/i[@name='e_0_energy']"): self.all_e_0[-1].append(float(i.text)) if self.DOS: # gather the DOS, if calculated and warranted self.dos = None self.dos_lm = None self.efermi = None is_dos = elem.find('dos') if is_dos != None: for child in is_dos: if child.attrib['name'] == 'efermi': self.efermi = float(child.text) child.clear() break else: child.clear() total = is_dos.find('total').find('array') spins = len(total.find('set').findall('set')) points = len( total.find('set').findall('set')[0].findall('r')) fields = len(total.findall('field')) total_array = np.zeros([spins, points, fields]) for s in range(spins): my_set = total.find('set').findall( 'set')[s].findall('r') for r in range(points): total_array[s, r] = map(float, my_set[r].text.split()) self.dos = total_array partial = is_dos.find('partial') if partial != None: partial = partial.find('array') else: partial = None if partial: ions = len(partial.find('set').findall('set')) spins = len( partial.find('set').findall('set')[0].findall( 'set')) points = len( partial.find('set').findall('set')[0].findall( 'set')[0].findall('r')) fields = len(partial.findall('field')) partial_array = np.zeros( [ions, spins, points, fields]) for i in range(ions): i_set = partial.find('set').findall( 'set')[i].findall('set') for s in range(spins): my_set = i_set[s].findall('r') for r in range(points): partial_array[i, s, r] = map( float, my_set[r].text.split()) self.dos_lm = partial_array if self.Band: eig_parse_vals = elem.find('eigenvalues').find( 'array').find('set') num_kpoints = len( eig_parse_vals.find('set').findall('set')) num_bands = len( eig_parse_vals.find('set').find('set').findall('r')) self.eigenvalues = [ np.empty([num_kpoints, num_bands]), np.empty([num_kpoints, num_bands]) ] for spin_ctr, spin in enumerate(eig_parse_vals): for kpoint_ctr, kpoint in enumerate(spin): for band_ctr, band in enumerate(kpoint): self.eigenvalues[spin_ctr][ kpoint_ctr, band_ctr] = band.text.strip().split()[0] eig_parse_vals.clear() elif elem.tag == 'kpoints': if self.Band: self.num_divisions = elem.find('generation').find('i') if self.num_divisions != None: self.num_divisions = int( self.num_divisions.text.strip()) kp_parse_vals = elem.find('varray') if elem.find( 'varray').attrib['name'] == 'kpointlist' else None if kp_parse_vals != None: num_paths = len(kp_parse_vals.findall( 'v')) / self.num_divisions kpoint_list = np.zeros( [self.num_divisions * num_paths, 3]) for i, row in enumerate(kp_parse_vals): kpoint_list[i, :] = [ float(val) for val in row.text.strip().split() ] self.kpoint_divisions = np.empty( [2 * num_paths, 3]) for i in range(num_paths): self.kpoint_divisions[2 * i] = kpoint_list[ i * self.num_divisions, :] self.kpoint_divisions[2 * i + 1] = kpoint_list[ (i + 1) * self.num_divisions - 1, :] kp_parse_vals.clear() else: self.kpoint_divisions = False elif elem.tag == 'atominfo': #finding the atom_type and atoms_per_type temp_node = elem.findall('array') for child in temp_node: if child.attrib['name'] == 'atomtypes': child_node = child break t_atom_info = child_node.findall('set')[0].findall('rc') self.atom_type = [] self.atoms_per_type = [] for child in t_atom_info: self.atom_type.append(child[1].text) self.atoms_per_type.append(int(child[0].text)) elif elem.tag == 'structure': self.is_complete = False if 'name' in elem.attrib: if elem.attrib['name'] == 'finalpos': #finding the final structure finalpos = elem self.is_complete = True # collect the final lattice self.lattice = [] for i in range(3): self.lattice.append([ float(x) for x in finalpos[0][0] [i].text.strip().split() ]) # Collect the reciprocal lattice self.rec_lat = [] for i in range(3): self.rec_lat.append([ float(x) for x in finalpos[0][2] [i].text.strip().split() ]) # collect the final basis self.basis = [] for i, basis_atom in enumerate(finalpos[1]): self.basis.append([ float(x) for x in basis_atom.text.strip().split() ]) finalpos.clear() else: pass elem.clear() f.close()