-
Notifications
You must be signed in to change notification settings - Fork 75
/
matdyn.py
128 lines (100 loc) · 4.79 KB
/
matdyn.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# -*- coding: utf-8 -*-
from aiida import orm
from aiida.common import exceptions
from qe_tools import CONSTANTS
from aiida_quantumespresso.calculations.matdyn import MatdynCalculation
from .base import Parser
class MatdynParser(Parser):
"""Parser implementation for the MatdynCalculation."""
def parse(self, **kwargs):
"""Parse the retrieved files from a `MatdynCalculation`."""
try:
output_folder = self.retrieved
except exceptions.NotExistent:
return self.exit(self.exit_codes.ERROR_NO_RETRIEVED_FOLDER)
filename_stdout = self.node.get_option('output_filename')
filename_frequencies = MatdynCalculation._PHONON_FREQUENCIES_NAME
if filename_stdout not in output_folder.list_object_names():
return self.exit(self.exit_codes.ERROR_OUTPUT_STDOUT_READ)
if 'JOB DONE' not in output_folder.get_object_content(filename_stdout):
return self.exit(self.exit_codes.ERROR_OUTPUT_STDOUT_INCOMPLETE)
if filename_frequencies not in output_folder.list_object_names():
return self.exit(self.exit_codes.ERROR_OUTPUT_STDOUT_READ)
# 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(output_folder.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)
if num_kpoints != kpoints.shape[0]:
return self.exit(self.exit_codes.ERROR_OUTPUT_KPOINTS_INCOMMENSURATE)
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_parameters', orm.Dict(dict=parsed_data))
self.out('output_phonon_bands', output_bands)
return
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 numpy
import re
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 is not '']
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