Source code for aiida_quantumespresso.parsers.matdyn
# -*- coding: utf-8 -*-
from aiida import orm
from qe_tools import CONSTANTS
from aiida_quantumespresso.calculations.matdyn import MatdynCalculation
from aiida_quantumespresso.utils.mapping import get_logging_container
from .base import BaseParser
[docs]class MatdynParser(BaseParser):
"""``Parser`` implementation for the ``MatDynCalculation`` calculation job class."""
[docs] def parse(self, **kwargs):
"""Parse the retrieved files from a ``MatdynCalculation`` into output nodes."""
logs = get_logging_container()
_, parsed_data, logs = self.parse_stdout_from_retrieved(logs)
base_exit_code = self.check_base_errors(logs)
if base_exit_code:
return self.exit(base_exit_code, logs)
self.out('output_parameters', orm.Dict(parsed_data))
if 'ERROR_OUTPUT_STDOUT_INCOMPLETE'in logs.error:
return self.exit(self.exit_codes.ERROR_OUTPUT_STDOUT_INCOMPLETE, logs)
filename_frequencies = MatdynCalculation._PHONON_FREQUENCIES_NAME
# Extract the kpoints from the input data and create the `KpointsData` for the `BandsData`
try:
kpoints = self.node.inputs.kpoints.get_kpoints()
kpoints_for_bands = self.node.inputs.kpoints.clone()
except AttributeError:
kpoints = self.node.inputs.kpoints.get_kpoints_mesh(print_list=True)
kpoints_for_bands = orm.KpointsData()
kpoints_for_bands.set_kpoints(kpoints)
parsed_data = parse_raw_matdyn_phonon_file(self.retrieved.base.repository.get_object_content(filename_frequencies))
try:
num_kpoints = parsed_data.pop('num_kpoints')
except KeyError:
return self.exit(self.exit_codes.ERROR_OUTPUT_KPOINTS_MISSING, logs)
if num_kpoints != kpoints.shape[0]:
return self.exit(self.exit_codes.ERROR_OUTPUT_KPOINTS_INCOMMENSURATE, logs)
output_bands = orm.BandsData()
output_bands.set_kpointsdata(kpoints_for_bands)
output_bands.set_bands(parsed_data.pop('phonon_bands'), units='THz')
for message in parsed_data['warnings']:
self.logger.error(message)
self.out('output_phonon_bands', output_bands)
return self.exit(logs=logs)
[docs]def parse_raw_matdyn_phonon_file(phonon_frequencies):
"""Parses the phonon frequencies file.
:param phonon_frequencies: phonon frequencies file from the matdyn calculation
:return dict parsed_data: keys:
* warnings: parser warnings raised
* num_kpoints: number of kpoints read from the file
* phonon_bands: BandsData object with the bands for each kpoint
"""
import re
import numpy
parsed_data = {}
parsed_data['warnings'] = []
# extract numbere of bands and kpoints
try:
num_bands = int(phonon_frequencies.split('=')[1].split(',')[0])
num_kpoints = int(phonon_frequencies.split('=')[2].split('/')[0])
parsed_data['num_kpoints'] = num_kpoints
except (ValueError, IndexError):
parsed_data['warnings'].append('Number of bands or kpoints unreadable in phonon frequencies file')
return parsed_data
# initialize array of frequencies
freq_matrix = numpy.zeros((num_kpoints, num_bands))
split_data = phonon_frequencies.split()
# discard the header of the file
raw_data = split_data[split_data.index('/') + 1:]
# try to improve matdyn deficiencies
corrected_data = []
for b in raw_data:
try:
corrected_data.append(float(b))
except ValueError:
# case in which there are two frequencies attached like -1204.1234-1020.536
if '-' in b:
c = re.split('(-)', b)
d = [i for i in c if i != '']
for i in range(0, len(d), 2): # d should have an even number of elements
corrected_data.append(float(d[i] + d[i + 1]))
else:
# I don't know what to do
parsed_data['warnings'].append('Bad formatting of frequencies')
return parsed_data
counter = 3
for i in range(num_kpoints):
for j in range(num_bands):
try:
freq_matrix[i, j] = corrected_data[counter] * CONSTANTS.invcm_to_THz # from cm-1 to THz
except ValueError:
parsed_data['warnings'].append('Error while parsing the frequencies')
except IndexError:
parsed_data['warnings'].append('Error while parsing the frequencies, dimension exceeded')
return parsed_data
counter += 1
counter += 3 # move past the kpoint coordinates
parsed_data['phonon_bands'] = freq_matrix
return parsed_data