Source code for aiida_kkr.calculations.voro

# -*- coding: utf-8 -*-
"""
Input plug-in for a voronoi calculation.
"""
from aiida.engine import CalcJob
from aiida.orm import CalcJobNode, Dict, StructureData, RemoteData, SinglefileData
from aiida.common.utils import classproperty
from aiida.common.exceptions import (InputValidationError, ValidationError)
from aiida.common.datastructures import (CalcInfo, CodeInfo)
from aiida_kkr.tools.common_workfunctions import generate_inputcard_from_structure, check_2Dinput_consistency, vca_check
from aiida.common.exceptions import UniquenessError
import os

__copyright__ = (u'Copyright (c), 2017, Forschungszentrum Jülich GmbH, '
                 'IAS-1/PGI-1, Germany. All rights reserved.')
__license__ = 'MIT license, see LICENSE.txt file'
__version__ = '0.5.3'
__contributors__ = ('Jens Broeder', 'Philipp Rüßmann')


[docs] class VoronoiCalculation(CalcJob): """ AiiDA calculation plugin for a voronoi calculation (creation of starting potential and shapefun). """ #################### # File names etc. #################### # calculation plugin version _CALCULATION_PLUGIN_VERSION = __version__ # Default input and output files _DEFAULT_INPUT_FILE = 'inputcard' # will be shown with inputcat _DEFAULT_OUTPUT_FILE = 'out_voronoi' #'shell output will be shown with outputca # List of mandatory input files _INPUT_FILE_NAME = 'inputcard' # List of output files that should always be present _OUTPUT_FILE_NAME = 'out_voronoi' # template.product entry point defined in setup.json _default_parser = 'kkr.voroparser' # File names _ATOMINFO = 'atominfo.txt' _RADII = 'radii.dat' _SHAPEFUN = 'shapefun' _VERTICES = 'vertices.dat' _OUT_POTENTIAL_voronoi = 'output.pot' _POTENTIAL_IN_OVERWRITE = 'overwrite_potential'
[docs] @classmethod def define(cls, spec): """ define internals and inputs / outputs of calculation """ # reuse base class (i.e. CalcJob) functions super(VoronoiCalculation, cls).define(spec) # now define input files and parser spec.input('metadata.options.parser_name', valid_type=str, default=cls._default_parser, non_db=True) spec.input('metadata.options.input_filename', valid_type=str, default=cls._DEFAULT_INPUT_FILE, non_db=True) spec.input('metadata.options.output_filename', valid_type=str, default=cls._DEFAULT_OUTPUT_FILE, non_db=True) # define input nodes (optional ones have required=False) spec.input('parameters', valid_type=Dict, help='Use a node that specifies the input parameters') spec.input( 'structure', valid_type=StructureData, required=False, help='Use a node that specifies the input crystal structure' ) spec.input( 'parent_KKR', valid_type=RemoteData, required=False, help='Use a node that specifies a parent KKR calculation' ) spec.input( 'potential_overwrite', valid_type=SinglefileData, required=False, help='Use a node that specifies the potential which is used instead of the voronoi output potential' ) # define outputs spec.output('output_parameters', valid_type=Dict, required=True, help='results of the calculation') spec.default_output_node = 'output_parameters' # define exit codes, also used in parser spec.exit_code(301, 'ERROR_NO_OUTPUT_FILE', message='Voronoi output file not found') spec.exit_code(302, 'ERROR_VORONOI_PARSING_FAILED', message='Voronoi parser retuned an error')
[docs] def prepare_for_submission(self, tempfolder): """Create the input files from the input nodes passed to this instance of the `CalcJob`. :param tempfolder: an `aiida.common.folders.Folder` to temporarily write files on disk :return: `aiida.common.datastructures.CalcInfo` instance """ # Check inputdict parameters = self.inputs.parameters if 'structure' in self.inputs: structure = self.inputs.structure found_structure = True else: found_structure = False vca_structure = False if found_structure: # for VCA: check if input structure and parameter node define VCA structure vca_structure = vca_check(structure, parameters) code = self.inputs.code # check if a parent folder containing a potential file (out_potential) is given if 'parent_KKR' in self.inputs: parent_calc_folder = self.inputs.parent_KKR found_parent = True else: found_parent = False if found_parent: # check if parent is either Voronoi or previous KKR calculation overwrite_potential, parent_calc = self._check_valid_parent(parent_calc_folder) #cross check if no structure was given and extract structure from parent if found_structure and not vca_structure: raise InputValidationError( 'parent_KKR and structure found in input. ' 'Can only use either parent_KKR or structure in input.' ) else: structure_remote_KKR, voro_parent = self.find_parent_structure(parent_calc) if not vca_structure: structure = structure_remote_KKR else: # check consistency of input vca structure and structure from remote KKR folder # TODO check consistency pass else: overwrite_potential = False if not found_structure: raise InputValidationError('Neither structure nor parent_KKR specified for this ' 'calculation') # check if overwrite potential is given explicitly if 'potential_overwrite' in self.inputs: potfile_overwrite = self.inputs.potential_overwrite has_potfile_overwrite = True else: has_potfile_overwrite = False if has_potfile_overwrite: overwrite_potential = True if not found_structure: raise InputValidationError( 'Input structure needed for this calculation ' "(using 'potential_overwrite' input node)" ) ################################### # Check for 2D case twoDimcheck, msg = check_2Dinput_consistency(structure, parameters) if not twoDimcheck: raise InputValidationError(msg) # Prepare inputcard from Structure and input parameter data with tempfolder.open(self._INPUT_FILE_NAME, u'w') as input_file: try: use_alat_input = parameters.get_dict().get('use_input_alat', False) use_alat_input = parameters.get_dict().get('USE_INPUT_ALAT', use_alat_input) natom, nspin, newsosol, warnings_write_inputcard = generate_inputcard_from_structure( parameters, structure, input_file, isvoronoi=True, vca_structure=vca_structure, use_input_alat=use_alat_input, ) except ValueError as e: raise InputValidationError(f'Input Dict not consistent: {e}') # Decide what files to copy local_copy_list = [] if overwrite_potential: # copy the right files #TODO check first if file, exists and throw # warning, now this will throw an error if found_parent and self._is_KkrCalc(parent_calc): outfolder = parent_calc.outputs.retrieved # copy from remote folder copylist = [parent_calc.process_class._OUT_POTENTIAL] elif has_potfile_overwrite: outfolder = potfile_overwrite # copy from potential sfd copylist = [potfile_overwrite.filename] else: copylist = [] for file1 in copylist: filename = file1 if (found_parent or has_potfile_overwrite) and file1 == copylist[0]: filename = self._POTENTIAL_IN_OVERWRITE local_copy_list.append((outfolder.uuid, file1, filename)) # Prepare CalcInfo to be returned to aiida calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.local_copy_list = local_copy_list calcinfo.remote_copy_list = [] calcinfo.retrieve_list = [ self._OUTPUT_FILE_NAME, self._ATOMINFO, self._RADII, self._SHAPEFUN, self._VERTICES, self._INPUT_FILE_NAME, ] # pass on overwrite potential if this was given in input # (KkrCalculation checks if this file is there and takes this file instead of _OUT_POTENTIAL_voronoi # if given) if overwrite_potential: calcinfo.retrieve_list += [self._POTENTIAL_IN_OVERWRITE] else: calcinfo.retrieve_list += [self._OUT_POTENTIAL_voronoi] codeinfo = CodeInfo() codeinfo.cmdline_params = [] codeinfo.stdout_name = self._OUTPUT_FILE_NAME codeinfo.code_uuid = code.uuid calcinfo.codes_info = [codeinfo] return calcinfo
[docs] def _check_valid_parent(self, parent_calc_folder): """ Check that calc is a valid parent for a FleurCalculation. It can be a VoronoiCalculation, KKRCalculation """ overwrite_pot = False # extract parent calculation parent_calcs = parent_calc_folder.get_incoming(node_class=CalcJobNode) n_parents = len(parent_calcs.all_link_labels()) if n_parents != 1: raise UniquenessError( 'Input RemoteData is child of {} ' 'calculation{}, while it should have a single parent' ''.format(n_parents, '' if n_parents == 0 else 's') ) else: parent_calc = parent_calcs.first().node overwrite_pot = True if ((not self._is_KkrCalc(parent_calc))): raise ValueError('Parent calculation must be a KkrCalculation') return overwrite_pot, parent_calc
[docs] def _is_KkrCalc(self, calc): """ check if calc contains the file out_potential """ is_KKR = False if calc.process_type == 'aiida.calculations:kkr.kkr': retrieved_node = calc.get_retrieved_node() if 'out_potential' in retrieved_node.list_object_names(): is_KKR = True return is_KKR
[docs] @classmethod def find_parent_structure(self, parent_folder): """ Find the Structure node recuresively in chain of parent calculations (structure node is input to voronoi calculation) This is a copy of the find_parent_structure that moved to tools.find_parent to keep backwards compatibility. """ from aiida_kkr.tools.find_parent import find_parent_structure return find_parent_structure(parent_folder)