Source code for aiida_kkr.calculations.voro

# -*- coding: utf-8 -*-
"""
Input plug-in for a voronoi calculation.
"""
from __future__ import print_function
from __future__ import absolute_import
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
import six

__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=six.string_types, default=cls._default_parser, non_db=True ) spec.input( 'metadata.options.input_filename', valid_type=six.string_types, default=cls._DEFAULT_INPUT_FILE, non_db=True ) spec.input( 'metadata.options.output_filename', valid_type=six.string_types, 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)