aiida_fleur.tools.merge_parameter — AiiDA-FLEUR 1.1.0 documentation

# Source code for aiida_fleur.tools.merge_parameter

    # -*- coding: utf-8 -*-
    ###############################################################################
    # Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany.         #
    #                All rights reserved.                                         #
    # This file is part of the AiiDA-FLEUR package.                               #
    #                                                                             #
    # The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur    #
    # For further information on the license, see the LICENSE.txt file            #
    # For further information please visit http://www.flapw.de or                 #
    # http://aiida-fleur.readthedocs.io/en/develop/                               #
    ###############################################################################
    """
    This module, contains a method to merge Dict nodes used by the FLEUR inpgen.
    This might also be of interest for other all-electron codes
    """
    # TODO this should be made an inline calculation or calcfunction to
    # keep the proverance!
    # Shall we allow for a python dictionary also instead of forcing paramteraData?
    # but then we can not keep the provenace...

    from __future__ import absolute_import
    from __future__ import print_function

    from aiida.plugins import DataFactory
    from aiida.orm import Bool, Dict
    from aiida.engine import calcfunction as cf
    #Dict = DataFactory('dict')

    def merge_parameter(Dict1, Dict2, overwrite=True):
        """
        Merges two Dict nodes.
        Additive: uses all namelists of both.
        If they have a namelist in common. Dict2 will overwrite the namelist
        of Dict. If this is not wanted. set overwrite = False.
        Then attributes of both will be added, but attributes from Dict1 won't
        be overwritten.

        param: AiiDA Dict Node
        param: AiiDA Dict Node

        returns: AiiDA Dict Node
        """

        from aiida.common.exceptions import InputValidationError
        #Dict = DataFactory('dict')

        # layout:
        # check input
        # get dictionaries
        # merge dictionaries into new dictionary
        # create a new Dict node

        new_dict = {}
        atoms_dict = {}
        atomlist = []
        if not isinstance(Dict1, Dict):
            raise InputValidationError('Dict1, must be of ' 'type Dict')
        if not isinstance(Dict2, Dict):
            raise InputValidationError('Dict2, must be of ' 'type Dict')
        dict1 = Dict1.get_dict()
        dict2 = Dict2.get_dict()

        for key in dict1.keys():
            if 'atom' in key:
                val = dict1.pop(key)
                atomlist.append(val)

        for key in dict2.keys():
            if 'atom' in key:
                val = dict2.pop(key)
                atomlist.append(val)

        # TODO do something on atom list,
        # we do not want doubles, check element and Id? Keep first ones?

        for i, atom in enumerate(atomlist):
            # TODO check for duplicates? what about
            key = 'atom{}'.format(i)
            atoms_dict[key] = atom

        # merge all namelists except atoms
        if overwrite:
            new_dict = dict1.copy()
            new_dict.update(dict2)
        else:
            # add second one later?
            new_dict = dict2.copy()
            new_dict.update(dict1)
            # TODO or do we want to merge the value dicts? usually does not make sense
            # for all keys...
        new_dict.update(atoms_dict)

        # be carefull with atom namelist

        return Dict(dict=new_dict)

    def merge_parameters(DictList, overwrite=True):
        """
        Merge together all parameter nodes in the given list.
        """
        #Dict = DataFactory('dict')
        paremeter_data_new = Dict(dict={})

        for i, parameter in enumerate(DictList):
            if isinstance(parameter, Dict):
                # merge
                paremeter_data_new = merge_parameter(paremeter_data_new, parameter, overwrite=overwrite)
            else:
                print(('WARNING: Entry : {} {} is not of type Dict, I skip it.'.format(i, parameter)))

        return paremeter_data_new

    @cf
    def merge_parameter_cf(Dict1, Dict2, overwrite=None):
        """
        calcfunction of merge_parameters
        """
        if overwrite is None:
            overwrite = Bool(True)
        paremeter_data_new = merge_parameter(Dict1, Dict2, overwrite=overwrite)

        return paremeter_data_new

    '''
    # TODO how to deal with a list? *args, prob is not the best, also it is not working here.
    # makeing a methods m(self, *args, **kwargs) and setting some fallbacks, does not work, because self, cannot be parsed
    # I guess...
    @cf
    def merge_parameters_wf(*Dicts, overwrite=Bool(True)):
        """
        calcfunction of merge_parameters
        """
        DictList = []
        for parameter in Dicts:
            DictList.append(parameter)
        paremeter_data_new = merge_parameters(DictList, overwrite=overwrite)

        return paremeter_data_new
    '''
    if __name__ == '__main__':
        import argparse
        #Dict = DataFactory('dict')

        parser = argparse.ArgumentParser(description='Merge a Dict node.')
        parser.add_argument('--para1', type=Dict, dest='para1', help='The first Dict node', required=True)
        parser.add_argument('--para2', type=Dict, dest='para2', help='The second Dict node', required=True)
        parser.add_argument('--overwrite',
                            type=bool,
                            dest='overwrite',
                            help='Shall values given in Dict2 overwrite the values from the first Dict?',
                            required=False)
        args = parser.parse_args()
        merge_parameter(Dict1=args.para1, Dict2=args.para1, overwrite=args.overwrite)