diff --git a/aiida_quantumespresso/calculations/matdyn.py b/aiida_quantumespresso/calculations/matdyn.py index 59072f249..9c308d6d7 100644 --- a/aiida_quantumespresso/calculations/matdyn.py +++ b/aiida_quantumespresso/calculations/matdyn.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- """`CalcJob` implementation for the matdyn.x code of Quantum ESPRESSO.""" from aiida import orm - from aiida_quantumespresso.calculations.namelists import NamelistsCalculation from aiida_quantumespresso.data.force_constants import ForceConstantsData @@ -12,16 +11,18 @@ class MatdynCalculation(NamelistsCalculation): _PHONON_FREQUENCIES_NAME = 'phonon_frequencies.dat' _PHONON_MODES_NAME = 'phonon_displacements.dat' _PHONON_DOS_NAME = 'phonon_dos.dat' + _PHONON_ELASTICITY_NAME = 'phonon_elasticity.yaml' _default_namelists = ['INPUT'] _blocked_keywords = [ ('INPUT', 'flfrq', _PHONON_FREQUENCIES_NAME), # output frequencies ('INPUT', 'flvec', _PHONON_MODES_NAME), # output displacements ('INPUT', 'fldos', _PHONON_DOS_NAME), # output density of states + ('INPUT', 'flelc', _PHONON_ELASTICITY_NAME), # output elastic properties ('INPUT', 'q_in_cryst_coord', True), # kpoints always in crystal coordinates ] - _internal_retrieve_list = [_PHONON_FREQUENCIES_NAME, _PHONON_DOS_NAME] + _internal_retrieve_list = [_PHONON_FREQUENCIES_NAME, _PHONON_DOS_NAME, _PHONON_ELASTICITY_NAME] _default_parser = 'quantumespresso.matdyn' @classmethod @@ -34,6 +35,7 @@ def define(cls, spec): spec.inputs.pop('parent_folder') spec.output('output_parameters', valid_type=orm.Dict) spec.output('output_phonon_bands', valid_type=orm.BandsData) + spec.output('output_elasticity', valid_type=orm.Dict) spec.default_output_node = 'output_parameters' spec.exit_code(310, 'ERROR_OUTPUT_STDOUT_READ', message='The stdout output file could not be read.') @@ -41,6 +43,8 @@ def define(cls, spec): message='The stdout output file was incomplete probably because the calculation got interrupted.') spec.exit_code(330, 'ERROR_OUTPUT_FREQUENCIES', message='The output frequencies file could not be read from the retrieved folder.') + spec.exit_code(340, 'ERROR_OUTPUT_ELASTICITY', + message='The output elasticity file could not be read from the retrieved folder.') spec.exit_code(410, 'ERROR_OUTPUT_KPOINTS_MISSING', message='Number of kpoints not found in the output data') spec.exit_code(411, 'ERROR_OUTPUT_KPOINTS_INCOMMENSURATE', @@ -56,7 +60,7 @@ def _get_following_text(self): kpoints_string = [f'{len(kpoints)}'] for kpoint in kpoints: - kpoints_string.append('{:18.10f} {:18.10f} {:18.10f}'.format(*kpoint)) # pylint: disable=consider-using-f-string + kpoints_string.append('{:18.10f} {:18.10f} {:18.10f}'.format(*kpoint)) return '\n'.join(kpoints_string) + '\n' @@ -71,7 +75,9 @@ def prepare_for_submission(self, folder): :return: :py:`~aiida.common.datastructures.CalcInfo` instance. """ force_constants = self.inputs.force_constants - self._blocked_keywords.append(('INPUT', 'flfrc', force_constants.filename)) + flfrc_tuple = ('INPUT', 'flfrc', force_constants.filename) + if flfrc_tuple not in self._blocked_keywords: + self._blocked_keywords.append(flfrc_tuple) calcinfo = super().prepare_for_submission(folder) calcinfo.local_copy_list.append((force_constants.uuid, force_constants.filename, force_constants.filename)) diff --git a/aiida_quantumespresso/parsers/matdyn.py b/aiida_quantumespresso/parsers/matdyn.py index 44a31045d..7bf75e9b4 100644 --- a/aiida_quantumespresso/parsers/matdyn.py +++ b/aiida_quantumespresso/parsers/matdyn.py @@ -3,7 +3,6 @@ from qe_tools import CONSTANTS from aiida_quantumespresso.calculations.matdyn import MatdynCalculation - from .base import Parser @@ -15,6 +14,7 @@ def parse(self, **kwargs): retrieved = self.retrieved filename_stdout = self.node.get_option('output_filename') filename_frequencies = MatdynCalculation._PHONON_FREQUENCIES_NAME + filename_elasticity = MatdynCalculation._PHONON_ELASTICITY_NAME if filename_stdout not in retrieved.list_object_names(): return self.exit(self.exit_codes.ERROR_OUTPUT_STDOUT_READ) @@ -48,6 +48,12 @@ def parse(self, **kwargs): output_bands.set_kpointsdata(kpoints_for_bands) output_bands.set_bands(parsed_data.pop('phonon_bands'), units='THz') + if filename_elasticity in retrieved.list_object_names(): + output_elasticity = parse_elasticity_file(retrieved.get_object_content(filename_elasticity)) + self.out('output_elasticity', orm.Dict(dict=output_elasticity)) + else: + return self.exit(self.exit_codes.ERROR_OUTPUT_ELASTICITY) + for message in parsed_data['warnings']: self.logger.error(message) @@ -67,9 +73,8 @@ def parse_raw_matdyn_phonon_file(phonon_frequencies): * num_kpoints: number of kpoints read from the file * phonon_bands: BandsData object with the bands for each kpoint """ - import re - import numpy + import re parsed_data = {} parsed_data['warnings'] = [] @@ -99,7 +104,7 @@ def parse_raw_matdyn_phonon_file(phonon_frequencies): # 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 != ''] + 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: @@ -123,3 +128,19 @@ def parse_raw_matdyn_phonon_file(phonon_frequencies): parsed_data['phonon_bands'] = freq_matrix return parsed_data + + +def parse_elasticity_file(elasticity_file): + """Parses the elastic properties file. + + :param elasticity_file: elasticity file from the matdyn calculation + + :return dict parsed_data: + A dictionary of elastic properties, see example output yaml file + of elasticity about the supported keys. + """ + import yaml + + parsed_data = yaml.full_load(elasticity_file) + + return parsed_data \ No newline at end of file