Source code for matador.scrapers.qe_scrapers

# coding: utf-8
# Distributed under the terms of the MIT License.

""" This file implements some scraper functions for
Quantum Espresso-related inputs and outputs.

"""


from collections import defaultdict
from os import stat
from math import gcd
from matador.utils.cell_utils import cart2abc, cart2volume
from matador.utils.chem_utils import RY_TO_EV, KBAR_TO_GPA
from matador.scrapers.utils import scraper_function, get_flines_extension_agnostic


[docs]@scraper_function def pwout2dict(fname, **kwargs): """ Extract available information from pw.x .out file. Parameters: fname (str/list): filename or list of filenames to scrape as a QuantumEspresso pw.x output. """ flines, fname = get_flines_extension_agnostic(fname, ["out", "in"]) pwout = {} pwout['source'] = [fname] try: # grab file owner username from pwd import getpwuid pwout['user'] = getpwuid(stat(fname).st_uid).pw_name except Exception: pwout['user'] = 'xxx' if 'CollCode' in fname: pwout['icsd'] = fname.split('CollCode')[-1] for ind, line in enumerate(reversed(flines)): ind = len(flines) - 1 - ind if 'cell_parameters' in line.lower() and 'angstrom' in line.lower() and 'lattice_cart' not in pwout: pwout['lattice_cart'] = [] for j in range(3): line = flines[ind+j+1].strip().split() pwout['lattice_cart'].append(list(map(float, line))) pwout['cell_volume'] = cart2volume(pwout['lattice_cart']) elif 'atomic_positions' in line.lower() and 'positions_frac' not in pwout: pwout['positions_frac'] = [] pwout['atom_types'] = [] j = 1 while True: if 'End final coordinates' in flines[j+ind]: break else: try: line = flines[j+ind].strip().split() pwout['atom_types'].append(line[0]) pwout['positions_frac'].append(list(map(float, line[1:5]))) j += 1 except Exception: break pwout['num_atoms'] = len(pwout['atom_types']) elif 'final enthalpy' in line.lower() and 'enthalpy' not in pwout: pwout['enthalpy'] = RY_TO_EV * float(line.lower().split()[-2]) elif 'total stress' in line.lower() and 'pressure' not in pwout: pwout['pressure'] = KBAR_TO_GPA * float(line.lower().split()[-1]) elif all(key in pwout for key in ['enthalpy', 'pressure', 'lattice_cart', 'positions_frac']): break # get abc lattice pwout['lattice_abc'] = cart2abc(pwout['lattice_cart']) # calculate stoichiometry pwout['stoichiometry'] = defaultdict(float) for atom in pwout['atom_types']: if atom not in pwout['stoichiometry']: pwout['stoichiometry'][atom] = 0 pwout['stoichiometry'][atom] += 1 gcd_val = 0 for atom in pwout['atom_types']: if gcd_val == 0: gcd_val = pwout['stoichiometry'][atom] else: gcd_val = gcd(pwout['stoichiometry'][atom], gcd_val) # convert stoichiometry to tuple for fryan temp_stoich = [] for key, value in pwout['stoichiometry'].items(): if float(value)/gcd_val % 1 != 0: temp_stoich.append([key, float(value)/gcd_val]) else: temp_stoich.append([key, value/gcd_val]) pwout['stoichiometry'] = temp_stoich atoms_per_fu = 0 for elem in pwout['stoichiometry']: atoms_per_fu += elem[1] pwout['num_fu'] = len(pwout['atom_types']) / atoms_per_fu return pwout, True