Skip to content

Commit

Permalink
Merged collection of updates for the latest aiida, aiida-vasp, and ph…
Browse files Browse the repository at this point in the history
…onopy
  • Loading branch information
atztogo committed Oct 22, 2019
2 parents d442353 + 97ecc0e commit e183329
Show file tree
Hide file tree
Showing 67 changed files with 1,770 additions and 21,427 deletions.
42 changes: 42 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
*.py[cod]
*~
MANIFEST

# C extensions
*.so

# Packages
*.egg
*.egg-info
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
lib
lib64

# Installer logs
pip-log.txt

# Unit test / coverage reports
.coverage
.tox
nosetests.xml

# Translations
*.mo

# Mr Developer
.mr.developer.cfg
.project
.pydevproject

# Doc
.buildinfo
.doctrees
_build
20 changes: 3 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,6 @@

AiiDA Phonopy plugin
====================

This a phonopy plugin for AiiDA. This plugin includes workflows to calculate
phonon band structure, DOS, thermal properties and mode Gruneisen parameters.
It provides interfaces for VASP, Quantum ESPRESSO and LAMMPS to calculate the
atomic forces and relax the crystal structure.


Examples
--------
Some test calculations are found in the folder **/examples**

- plugins: examples of basic functionality of phonopy remote plugin. These tests require
the previous calculation of forces or force constants that should be already stored in the database
- workchains: examples of the full phonon calculation / gruneisen parameters from scratch. These workflows
require the installation of plugins for VASP, LAMMPS or QuantumESPRESSO.
- tools: example scripts for visualize the results of phonon/gruneisen workchains. These scripts require
matplotlib.
This a phonopy plugin for AiiDA. This plugin includes workflows to
calculate phonons with supercell and finite displacement approaches.
Currently it provides interfaces only to VASP.
File renamed without changes.
120 changes: 120 additions & 0 deletions aiida_phonopy/calcs/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
from aiida.common import CalcInfo, CodeInfo
from aiida.plugins import DataFactory
from aiida_phonopy.common.raw_parsers import (get_BORN_txt,
get_phonopy_conf_file_txt,
get_poscar_txt)

Dict = DataFactory('dict')
StructureData = DataFactory('structure')
ArrayData = DataFactory('array')


class BasePhonopyCalculation(object):
"""
A basic plugin for calculating force constants using Phonopy.
Requirement: the node should be able to import phonopy if NAC is used
"""

_INPUT_CELL = 'POSCAR'
_INPUT_FORCE_SETS = 'FORCE_SETS'
_INPUT_NAC = 'BORN'

@classmethod
def _baseclass_use_methods(cls, spec):
spec.input('settings', valid_type=Dict, required=True,
help=('Use a node that specifies the phonopy '
'parameters for the namelists'))
spec.input('structure', valid_type=StructureData, required=True,
help=('Use a node for the structure'))
spec.input('force_sets', valid_type=ArrayData, required=False,
help=('Use a node that specifies the force_sets '
'array for the namelists'))
spec.input('nac_params', valid_type=ArrayData, required=False,
help=('Use a node for the Non-analitical '
'corrections parameters arrays'))
spec.input('primitive', valid_type=StructureData,
required=False, help=('Use a node for the structure'))
spec.input('metadata.options.withmpi', valid_type=bool, default=False)

def _create_additional_files(self, folder):
pass

def prepare_for_submission(self, folder):
"""Create the input files from the input nodes passed to this instance of the `CalcJob`.
:param folder: an `aiida.common.folders.Folder` to temporarily write files on disk
:return: `aiida.common.datastructures.CalcInfo` instance
"""

self.logger.info("prepare_for_submission")

self._internal_retrieve_list = []
self._additional_cmd_params = []
self._calculation_cmd = []

settings = self.inputs.settings
structure = self.inputs.structure
code = self.inputs.code

##############################
# END OF INITIAL INPUT CHECK #
##############################

# ================= prepare the python input files =================

self._create_additional_files(folder)

cell_txt = get_poscar_txt(structure)
input_txt = get_phonopy_conf_file_txt(settings)

input_filename = folder.get_abs_path(
self.inputs.metadata.options.input_filename)
with open(input_filename, 'w') as infile:
infile.write(input_txt)

cell_filename = folder.get_abs_path(self._INPUT_CELL)
with open(cell_filename, 'w') as infile:
infile.write(cell_txt)

if ('nac_params' in self.inputs and
'primitive' in self.inputs):
born_txt = get_BORN_txt(
self.inputs.nac_params,
self.inputs.primitive,
settings['symmetry_tolerance'])

nac_filename = folder.get_abs_path(self._INPUT_NAC)
with open(nac_filename, 'w') as infile:
infile.write(born_txt)
for params in self._additional_cmd_params:
params.append('--nac')

# ============================ calcinfo ===============================

local_copy_list = []
remote_copy_list = []

calcinfo = CalcInfo()

calcinfo.uuid = self.uuid

# Empty command line by default
calcinfo.local_copy_list = local_copy_list
calcinfo.remote_copy_list = remote_copy_list

# Retrieve files
calcinfo.retrieve_list = self._internal_retrieve_list

calcinfo.codes_info = []
for default_params, additional_params in zip(
self._calculation_cmd, self._additional_cmd_params):
codeinfo = CodeInfo()
codeinfo.cmdline_params = (
[self.inputs.metadata.options.input_filename, ]
+ default_params + additional_params)
codeinfo.code_uuid = code.uuid
codeinfo.stdout_name = self.inputs.metadata.options.output_filename
codeinfo.withmpi = False
calcinfo.codes_info.append(codeinfo)

return calcinfo
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from aiida.common.exceptions import InputValidationError
from aiida.orm.calculation.job import JobCalculation
from aiida.common import InputValidationError
from aiida.engine import CalcJob
from aiida.common.utils import classproperty
from aiida.orm import DataFactory
from aiida_phonopy.calculations.phonopy import BasePhonopyCalculation


from aiida_phonopy.common.raw_parsers import get_disp_fc3_txt, get_forces_txt, \
write_fc2_to_hdf5_file, write_fc3_to_hdf5_file, write_kappa_to_hdf5_file
from aiida.plugins import DataFactory
from aiida_phonopy.calcs.base import BasePhonopyCalculation
from aiida_phonopy.common.raw_parsers import (get_disp_fc3_txt, get_forces_txt,
write_fc2_to_hdf5_file,
write_fc3_to_hdf5_file,
write_kappa_to_hdf5_file)

BandStructureData = DataFactory('phonopy.band_structure')
KpointsData = DataFactory('array.kpoints')
Expand All @@ -28,7 +28,8 @@ def get_grid_data_files(grid_data):

return gp_data

class Phono3pyCalculation(BasePhonopyCalculation, JobCalculation):

class Phono3pyCalculation(BasePhonopyCalculation, CalcJob):
"""
A basic plugin for calculating phonon properties using Phonopy.
"""
Expand Down Expand Up @@ -64,14 +65,15 @@ def _use_methods(cls):
'valid_types': ArrayData,
'additional_parameter': None,
'linkname': 'grid_data',
'docstring': "Use the node to include grid points data in distributed calculation",
'docstring': ("Use the node to include grid points data in "
"distributed calculation"),
}

return retdict

def _create_additional_files(self, tempfolder, inputdict):

data_sets = inputdict.pop(self.get_linkname('data_sets'), None)
datasets = inputdict.pop(self.get_linkname('datasets'), None)
fc3 = inputdict.pop(self.get_linkname('force_constants_3'), None)
fc2 = inputdict.pop(self.get_linkname('force_constants'), None)

Expand All @@ -90,18 +92,21 @@ def _create_additional_files(self, tempfolder, inputdict):

self._additional_cmdline_params += ['--fc2', '--fc3']

elif data_sets is not None:
elif datasets is not None:
disp_fc3_filename = tempfolder.get_abs_path(self._INPUT_DISP_FC3)
disp_f3c_txt = get_disp_fc3_txt(structure, parameters_data, data_sets)
disp_f3c_txt = get_disp_fc3_txt(
structure, parameters_data, datasets)
with open(disp_fc3_filename, 'w') as infile:
infile.write(disp_f3c_txt)

forces_txt = get_forces_txt(data_sets)
forces_txt = get_forces_txt(datasets)
forces_filename = tempfolder.get_abs_path(self._INPUT_FORCES_FC3)
with open(forces_filename, 'w') as infile:
infile.write(forces_txt)
else:
raise InputValidationError("either force_sets or force_constants should be specified for this calculation")
msg = ("either force_sets or force_constants should be specified "
"for this calculation")
raise InputValidationError(msg)

grid_data = inputdict.pop(self.get_linkname('grid_data'), None)

Expand All @@ -111,21 +116,26 @@ def _create_additional_files(self, tempfolder, inputdict):
kappa_g_filename = self._OUTPUT_KAPPA + \
'm{}{}{}'.format(*parameters_data.dict.mesh) + \
'-g{}.hdf5'.format(gp)
write_kappa_to_hdf5_file(gp_data[gp],
filename=tempfolder.get_abs_path(kappa_g_filename))
write_kappa_to_hdf5_file(
gp_data[gp],
filename=tempfolder.get_abs_path(kappa_g_filename))

self._additional_cmdline_params += ['--read-gamma']
else:
if 'grid_point' in parameters_data.get_dict():
gp_string = ','.join([str(gp) for gp in parameters_data.dict.grid_point])
self._additional_cmdline_params += ['--gp={}'.format(gp_string), '--write-gamma']
gp_string = ','.join(
[str(gp) for gp in parameters_data.dict.grid_point])
self._additional_cmdline_params += [
'--gp={}'.format(gp_string), '--write-gamma']
for gp in parameters_data.dict.grid_point:
kappa_g_filename = self._OUTPUT_KAPPA + \
'm{}{}{}'.format(*parameters_data.dict.mesh) + \
'-g{}.hdf5'.format(gp)
kappa_g_filename = (
self._OUTPUT_KAPPA +
'm{}{}{}'.format(*parameters_data.dict.mesh) +
'-g{}.hdf5'.format(gp))
self._internal_retrieve_list += [kappa_g_filename]
return

# Set name for output file
kappa_filename = self._OUTPUT_KAPPA + 'm{}{}{}.hdf5'.format(*parameters_data.dict.mesh)
kappa_filename = (self._OUTPUT_KAPPA +
'm{}{}{}.hdf5'.format(*parameters_data.dict.mesh))
self._internal_retrieve_list += [kappa_filename]

0 comments on commit e183329

Please sign in to comment.