Skip to content

Commit

Permalink
Migrated parsers for aiida core v2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
atztogo committed Jun 1, 2021
1 parent ccb6e86 commit 1ea9b1d
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 96 deletions.
7 changes: 3 additions & 4 deletions aiida_phonopy/calcs/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def prepare_for_submission(self, folder):
if (not self.inputs.fc_only and
'nac_params' in self.inputs and
'primitive' in self.inputs and
'symmetry_tolerance' in self.inputs):
'symmetry_tolerance' in self.inputs): # noqa: E129
born_txt = get_BORN_txt(
self.inputs.nac_params,
self.inputs.primitive,
Expand All @@ -88,10 +88,9 @@ def prepare_for_submission(self, folder):
for i, (default_params, additional_params) in enumerate(zip(
self._calculation_cmd, self._additional_cmd_params)):
codeinfo = CodeInfo()
codeinfo.cmdline_params = default_params + additional_params
cmdline_params = default_params + additional_params
codeinfo.cmdline_params = cmdline_params
codeinfo.code_uuid = self.inputs.code.uuid
codeinfo.stdout_name = "%s%d" % (
self.options.output_filename, i + 1)
codeinfo.withmpi = False
calcinfo.codes_info.append(codeinfo)

Expand Down
43 changes: 24 additions & 19 deletions aiida_phonopy/calcs/phonopy.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""CalcJob to run phonopy at a remote host."""

from aiida.plugins import DataFactory
from aiida_phonopy.calcs.base import BasePhonopyCalculation
from aiida.orm import Str
from aiida.common import InputValidationError
from aiida_phonopy.common.file_generators import (
get_FORCE_SETS_txt, get_phonopy_options, get_phonopy_yaml_txt)
Expand All @@ -10,18 +11,17 @@
ArrayData = DataFactory('array')
XyData = DataFactory('array.xy')
Dict = DataFactory('dict')
Str = DataFactory('str')


class PhonopyCalculation(BasePhonopyCalculation):
"""
A basic plugin for calculating phonon properties using Phonopy.
"""
"""Phonopy calculation."""

_OUTPUT_PROJECTED_DOS = 'projected_dos.dat'
_OUTPUT_TOTAL_DOS = 'total_dos.dat'
_OUTPUT_THERMAL_PROPERTIES = 'thermal_properties.yaml'
_OUTPUT_BAND_STRUCTURE = 'band.yaml'
_INOUT_FORCE_CONSTANTS = 'FORCE_CONSTANTS'
_INOUT_FORCE_CONSTANTS = 'force_constants.hdf5'
_INPUT_CELL = 'phonopy_cells.yaml'
_INPUT_FORCE_SETS = 'FORCE_SETS'

Expand All @@ -42,7 +42,7 @@ def define(cls, spec):
default=lambda: Str(cls._INOUT_FORCE_CONSTANTS))
# parser_name has to be set to invoke parsing.
spec.inputs['metadata']['options']['parser_name'].default = 'phonopy'
spec.inputs['metadata']['options']['output_filename'].default = 'phonopy.out'
spec.inputs['metadata']['options']['output_filename'].default = 'phonopy.yaml'

spec.output('force_constants', valid_type=ArrayData, required=False,
help='Calculated force constants')
Expand All @@ -54,6 +54,8 @@ def define(cls, spec):
help='Calculated thermal properties')
spec.output('band_structure', valid_type=BandsData, required=False,
help='Calculated phonon band structure')
spec.output('version', valid_type=Str, required=False,
help='Version number')

def prepare_for_submission(self, folder):
"""Prepare calcinfo."""
Expand All @@ -67,25 +69,28 @@ def _create_additional_files(self, folder):
mesh_opts, fc_opts = get_phonopy_options(
self.inputs.settings['postprocess_parameters'])

self._internal_retrieve_list = [self._INOUT_FORCE_CONSTANTS, ]
self._additional_cmd_params = [['--writefc', ] + fc_opts, ]
self._calculation_cmd = [['-c', self._INPUT_CELL], ]
self._internal_retrieve_list = [
self._INOUT_FORCE_CONSTANTS,
self.inputs.metadata.options.output_filename]
self._additional_cmd_params = [
['--writefc', '--writefc-format=hdf5'] + fc_opts,
['--readfc', '--readfc-format=hdf5'],
['--readfc', '--readfc-format=hdf5']]

# First run with --writefc, and with --readfc for remaining runs
if not self.inputs.fc_only:

if self.inputs.fc_only:
self._calculation_cmd = [['-c', self._INPUT_CELL], ]
else:
self._calculation_cmd = [
['-c', self._INPUT_CELL, '--pdos=auto'] + mesh_opts,
['-c', self._INPUT_CELL, '-t', '--dos'] + mesh_opts,
['-c', self._INPUT_CELL, '--band=auto', '--band-points=101',
'--band-const-interval']
]
N = len(self._calculation_cmd) - 1
self._additional_cmd_params += [['--readfc', ] for i in range(N)]
self._internal_retrieve_list += [self._OUTPUT_TOTAL_DOS,
self._OUTPUT_PROJECTED_DOS,
self._OUTPUT_THERMAL_PROPERTIES,
self._OUTPUT_BAND_STRUCTURE]
'--band-const-interval']]
self._internal_retrieve_list += [
self._OUTPUT_TOTAL_DOS,
self._OUTPUT_PROJECTED_DOS,
self._OUTPUT_THERMAL_PROPERTIES,
self._OUTPUT_BAND_STRUCTURE]

def _create_phonopy_yaml(self, folder):
phpy_yaml_txt = get_phonopy_yaml_txt(
Expand Down
78 changes: 40 additions & 38 deletions aiida_phonopy/common/raw_parsers.py
Original file line number Diff line number Diff line change
@@ -1,73 +1,77 @@
import numpy as np
"""File parsers."""

import h5py
import yaml
try:
from yaml import CLoader as Loader
except ImportError:
from yaml import Loader
import numpy as np
from aiida.plugins import DataFactory
from aiida_phonopy.common.utils import (
get_total_dos, get_projected_dos, get_thermal_properties, get_bands)
from phonopy.file_IO import parse_FORCE_CONSTANTS as parse_FC


ArrayData = DataFactory('array')
XyData = DataFactory('array.xy')
BandsData = DataFactory('array.bands')


# Parse files to generate AIIDA OBJECTS
def parse_phonopy_yaml(f):
"""phonopy.yaml parser."""
data = yaml.load(f, Loader=Loader)
return data


def parse_FORCE_CONSTANTS(filename):
force_constants = parse_FC(filename=filename)
def parse_FORCE_CONSTANTS(f):
"""force_constants.hdf5 parser."""
with h5py.File(f, 'r') as f5:
force_constants = f5['force_constants'][:]
fc_array = ArrayData()
fc_array.set_array('force_constants', force_constants)
fc_array.label = 'force_constants'
return fc_array


def parse_total_dos(filename):
data = np.loadtxt(filename)
def parse_total_dos(f):
"""total_dos.dat parser."""
data = np.loadtxt(f)
total_dos = {'frequency_points': data[:, 0],
'total_dos': data[:, 1]}
dos = get_total_dos(total_dos)
return dos


def parse_projected_dos(filename):
data = np.loadtxt(filename)
def parse_projected_dos(f):
"""projected_dos.dat parser."""
data = np.loadtxt(f)
projected_dos = {'frequency_points': data[:, 0],
'projected_dos': data[:, 1:].T}
pdos = get_projected_dos(projected_dos)
return pdos


def parse_thermal_properties(filename):
def parse_thermal_properties(f):
"""thermal_properties.yaml parser."""
thermal_properties = {'temperatures': [],
'free_energy': [],
'entropy': [],
'heat_capacity': []}

with open(filename, 'r') as stream:
try:
data = yaml.load(stream, Loader=yaml.FullLoader)
except AttributeError:
data = yaml.load(stream)
for tp in data['thermal_properties']:
thermal_properties['temperatures'].append(tp['temperature'])
thermal_properties['entropy'].append(tp['entropy'])
thermal_properties['free_energy'].append(tp['free_energy'])
thermal_properties['heat_capacity'].append(tp['heat_capacity'])
for key in thermal_properties:
thermal_properties[key] = np.array(thermal_properties[key])
data = yaml.load(f, Loader=Loader)
for tp in data['thermal_properties']:
thermal_properties['temperatures'].append(tp['temperature'])
thermal_properties['entropy'].append(tp['entropy'])
thermal_properties['free_energy'].append(tp['free_energy'])
thermal_properties['heat_capacity'].append(tp['heat_capacity'])
for key in thermal_properties:
thermal_properties[key] = np.array(thermal_properties[key])

tprops = get_thermal_properties(thermal_properties)

return tprops


def parse_band_structure(filename, label=None):
with open(filename, 'r') as stream:
try:
bands = yaml.load(stream, Loader=yaml.FullLoader)
except AttributeError:
bands = yaml.load(stream)

def parse_band_structure(f, label=None):
"""band.yaml parser."""
bands = yaml.load(f, Loader=Loader)
frequencies_flat = []
qpoints_flat = []
for k in bands['phonon']:
Expand All @@ -83,7 +87,7 @@ def parse_band_structure(filename, label=None):
label_pairs = []
for pair in bands['labels']:
label_pairs.append(
[x.replace('$', '').replace('\\', '').replace('mathrm{', '').replace('}', '').upper()
[x.replace('$', '').replace('\\', '').replace('mathrm{', '').replace('}', '').upper() # noqa E501
for x in pair])

labels = [label_pairs[0][0], label_pairs[0][1]]
Expand All @@ -102,12 +106,10 @@ def parse_band_structure(filename, label=None):
return bs


def parse_kappa(filename):
import h5py

def parse_kappa(f):
"""kappa.hdf5 parser."""
kappa = ArrayData()

f = h5py.File(filename, 'r')
f = h5py.File(f, 'r')
for item in f:
array = np.array(f[item])
kappa.set_array(item, array)
Expand Down
57 changes: 25 additions & 32 deletions aiida_phonopy/parsers/phonopy.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
"""Parsers of phonopy output files."""

from aiida.engine import ExitCode
from aiida.common.exceptions import NotExistent
from aiida.parsers.parser import Parser
from aiida_phonopy.common.raw_parsers import (
parse_thermal_properties, parse_FORCE_CONSTANTS, parse_projected_dos,
parse_total_dos, parse_band_structure)
parse_total_dos, parse_band_structure, parse_phonopy_yaml)
from aiida.plugins import DataFactory


Str = DataFactory('str')


class PhonopyParser(Parser):
"""
Parser the DATA files from phonopy.
"""
"""Parser the DATA files from phonopy."""

def __init__(self, calc):
"""
Initialize the instance of PhonopyParser
"""
super(PhonopyParser, self).__init__(calc)
"""Call Parser.__init__."""
super().__init__(calc)

def parse(self, **kwargs):
"""
Parses the datafolder, stores results.
"""
self.logger.info("Parsing start.")
"""Parse retrieved files."""
self.logger.info("parse retrieved files")

# select the folder object
# Check that the retrieved folder is there
Expand All @@ -33,37 +33,25 @@ def parse(self, **kwargs):
# check what is inside the folder
list_of_files = output_folder.list_object_names()

# OUTPUT file should exist
# if not self._calc._OUTPUT_FILE_NAME in list_of_files:
# successful = False
# self.logger.error("Output file not found")
# return successful, ()

# Get files and do the parsing

fc_filename = self.node.inputs.force_constants_filename.value
if fc_filename in list_of_files:
with output_folder.open(fc_filename) as f:
fname = f.name
self.out('force_constants', parse_FORCE_CONSTANTS(fname))
with output_folder.open(fc_filename, 'rb') as f:
self.out('force_constants', parse_FORCE_CONSTANTS(f))

projected_dos_filename = self.node.inputs.projected_dos_filename.value
if projected_dos_filename in list_of_files:
with output_folder.open(projected_dos_filename) as f:
fname = f.name
self.out('pdos', parse_projected_dos(fname))
self.out('pdos', parse_projected_dos(f))

total_dos_filename = self.node.inputs.projected_dos_filename.value
if total_dos_filename in list_of_files:
with output_folder.open(total_dos_filename) as f:
fname = f.name
self.out('dos', parse_total_dos(fname))
self.out('dos', parse_total_dos(f))

tp_filename = self.node.inputs.thermal_properties_filename.value
if tp_filename in list_of_files:
with output_folder.open(tp_filename) as f:
fname = f.name
self.out('thermal_properties', parse_thermal_properties(fname))
self.out('thermal_properties', parse_thermal_properties(f))

band_filename = self.node.inputs.band_structure_filename.value
if band_filename in list_of_files:
Expand All @@ -74,9 +62,14 @@ def parse(self, **kwargs):
else:
label = None
with output_folder.open(band_filename) as f:
fname = f.name
self.out('band_structure',
parse_band_structure(fname, label=label))
self.out('band_structure', parse_band_structure(f, label=label))

options = self.node.get_options()
phpy_yaml_filename = options['output_filename']
if phpy_yaml_filename in list_of_files:
with output_folder.open(phpy_yaml_filename) as f:
yaml_dict = parse_phonopy_yaml(f)
self.out('version', Str(yaml_dict['phonopy']['version']))

self.logger.info("Parsing done.")
return ExitCode(0)
6 changes: 3 additions & 3 deletions setup.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@
"classifiers": [
"Intended Audience :: Science/Research",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Topic :: Scientific/Engineering :: Physics",
"Topic :: Scientific/Engineering :: Chemistry",
"Development Status :: 5 - Production/Stable",
"Framework :: AiiDA"
],
"license": "MIT license",
"install_requires": [
"phonopy>=2.8.1",
"phonopy>=2.9.3",
"numpy",
"seekpath",
"aiida-core>=1.2.1,<2.0.0",
"aiida-core>=1.6.3,<2.0.0",
"aiida-vasp>=2.0.0"
],
"setup_requires": [
Expand Down

0 comments on commit 1ea9b1d

Please sign in to comment.