Example #1
0
 def use_parent_calculation(self,calc):
     """
     Set the parent calculation of Ph, 
     from which it will inherit the outputsubfolder.
     The link will be created from parent RemoteData to PhCalculation 
     """
     from aiida.common.exceptions import NotExistent
     
     self._check_valid_parent(calc)
     
     remotedatas = calc.get_outputs(type=RemoteData)
     if not remotedatas:
         raise NotExistent("No output remotedata found in "
                               "the parent")
     if len(remotedatas) != 1:
         raise UniquenessError("More than one output remotedata found in "
                               "the parent")
     remotedata = remotedatas[0]
     
     self._set_parent_remotedata(remotedata)
Example #2
0
    def store(self, *args, **kwargs):
        """
        Store the node, ensuring that the combination (element,name,version) is unique.
        """
        # TODO: this uniqueness check is not race-condition free.

        try:
            existing = self.get(self.element,
                                self.name,
                                self.version,
                                match_aliases=False)
        except NotExistent:
            pass
        else:
            raise UniquenessError(
                f"Gaussian Basis Set already exists for"
                f" element={self.element}, name={self.name}, version={self.version}: {existing.uuid}"
            )

        return super(BasisSet, self).store(*args, **kwargs)
Example #3
0
    def _prepare_group_for_upload(cls, group_name, group_description=None, dry_run=False):
        """Prepare a (possibly new) group to upload a POTCAR family to."""
        if not dry_run:
            group, group_created = Group.objects.get_or_create(label=group_name, type_string=cls.potcar_family_type_string)
        else:
            group = cls.get_potcar_group(group_name)
            group_created = bool(not group)
            if not group:
                group = Group(label=group_name)

        if group.user.pk != get_current_user().pk:
            raise UniquenessError(
                'There is already a POTCAR family group with name {}, but it belongs to user {}, therefore you cannot modify it'.format(
                    group_name, group.user.email))

        if group_description:
            group.description = group_description
        elif group_created:
            raise ValueError('A new POTCAR family {} should be created but no description was given!'.format(group_name))

        return group
Example #4
0
    def get_or_create_famgroup(cls, famname):
        '''Returns a PAW family group, creates it if it didn't exists'''
        from aiida.orm import Group
        from aiida.backends.djsite.utils import get_automatic_user

        # TODO: maybe replace with Group.get_or_create?
        try:
            group = Group.get(name=famname, type_string=cls.group_type)
            group_created = False
        except NotExistent:
            group = Group(name=famname,
                          type_string=cls.group_type,
                          user=get_automatic_user())
            group_created = True

        if group.user != get_automatic_user():
            raise UniquenessError("There is already a UpfFamily group "
                                  "with name {}, but it belongs to user {},"
                                  " therefore you cannot modify it".format(
                                      famname, group.user.email))
        return group, group_created
Example #5
0
    def use_parent_calculation(self, calc):
        """
        Set the parent calculation,
        from which it will inherit the outputsubfolder.
        The link will be created from parent RemoteData and NamelistCalculation
        """
        if not isinstance(calc, PwCalculation):
            raise ValueError("Parent calculation must be a PwCalculation")
        from aiida.common.exceptions import UniquenessError
        localdatas = [_[1] for _ in calc.get_outputs(also_labels=True)]
        if len(localdatas) == 0:
            raise UniquenessError(
                "No output retrieved data found in the parent"
                "calc, probably it did not finish yet, "
                "or it crashed")

        localdata = [
            _[1] for _ in calc.get_outputs(also_labels=True)
            if _[0] == 'remote_folder'
        ]
        localdata = localdata[0]
        self.use_parent_folder(localdata)
Example #6
0
    def _do_create_link(self, src, label, link_type):
        """
        Create a link from a source node with label and a link type

        :param src: The source node
        :type src: :class:`Node`
        :param label: The link label
        :param link_type: The link type
        """
        from aiida.backends.sqlalchemy import get_scoped_session
        session = get_scoped_session()
        try:
            with session.begin_nested():
                link = DbLink(input_id=src.id,
                              output_id=self.id,
                              label=label,
                              type=link_type.value)
                session.add(link)
        except SQLAlchemyError as exc:
            raise UniquenessError("There is already a link with the same "
                                  "name (raw message was {})"
                                  "".format(exc))
Example #7
0
    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_inputs(node_type=JobCalculation)
        n_parents = len(parent_calcs)
        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[0]
            overwrite_pot = True

        if ((not self._is_KkrCalc(parent_calc))):
            raise ValueError("Parent calculation must be a KkrCalculation")

        return overwrite_pot, parent_calc
Example #8
0
    def _replace_link_from(self, src, label, link_type=LinkType.UNSPECIFIED):
        """
        Replace an input link with the given label, or simply creates it
        if it does not exist.
        
        :note: In subclasses, change only this. Moreover, remember to call
           the super() method in order to properly use the caching logic!

        :param src: the source object
        :param str label: the name of the label to set the link from src.
        """
        # If both are stored, write directly on the DB
        if self.is_stored and src.is_stored:
            self._replace_dblink_from(src, label, link_type)
            # If the link was in the local cache, remove it
            # (this could happen if I first store the output node, then
            # the input node.
            try:
                del self._inputlinks_cache[label]
            except KeyError:
                pass
        else:  # at least one is not stored: set in the internal cache
            # See if I am pointing to already saved nodes and I am already
            # linking to a given node
            # It is similar to the 'add' method, but if I am replacing the
            # same node, I will not complain (k!=label)
            if src.uuid in [
                    v[0].uuid for k, v in self._inputlinks_cache.iteritems()
                    if k != label
            ]:
                raise UniquenessError(
                    "A link from node with UUID={} and "
                    "the current node (UUID={}) already exists!".format(
                        src.uuid, self.uuid))
            # I insert the link directly in the cache rather than calling
            # _add_cachelink_from because this latter performs an undesired check
            self._inputlinks_cache[label] = (src, link_type)
Example #9
0
    def get_result_parameterdata_node(self):
        """
        Return the parameterdata node.

        :raise UniquenessError: if the node is not unique
        :raise NotExistent: if the node does not exist
        """
        from aiida.orm.data.parameter import ParameterData
        from aiida.common.exceptions import NotExistent

        out_parameters = self._calc.get_outputs(type=ParameterData, also_labels=True)
        out_parameterdata = [i[1] for i in out_parameters
                             if i[0] == self.get_linkname_outparams()]

        if not out_parameterdata:
            raise NotExistent("No output .res ParameterData node found")
        elif len(out_parameterdata) > 1:
            from aiida.common.exceptions import UniquenessError

            raise UniquenessError("Output ParameterData should be found once, "
                                  "found it instead {} times"
                                  .format(len(out_parameterdata)))

        return out_parameterdata[0]
Example #10
0
 def get_extended_symmetries(self):
     """
     Return the extended dictionary of symmetries.
     """
     data = self._calc.get_outputs(node_type=ParameterData,
                                   also_labels=True)
     all_data = [
         i[1] for i in data if i[0] == self.get_linkname_outparams()
     ]
     if len(all_data) > 1:
         raise UniquenessError('More than one output parameterdata found.')
     elif not all_data:
         return []
     else:
         compact_list = all_data[0].get_dict()[
             'symmetries']  # rimetti lo zero
         new_list = []
         # copy what wasn't compact
         for element in compact_list:
             new_dict = {}
             for keys in [
                     't_rev', 'equivalent_ions', 'fractional_translation'
             ]:
                 try:
                     new_dict[keys] = element[keys]
                 except KeyError:
                     pass
             # expand the rest
             new_dict['name'] = self._possible_symmetries[
                 element['symmetry_number']]['name']
             new_dict['rotation'] = self._possible_symmetries[
                 element['symmetry_number']]['matrix']
             new_dict['inversion'] = self._possible_symmetries[
                 element['symmetry_number']]['inversion']
             new_list.append(new_dict)
         return new_list
    def set_value(cls,
                  key,
                  value,
                  with_transaction=True,
                  subspecifier_value=None,
                  other_attribs={},
                  stop_if_existing=False):
        """
        Set a new value in the DB, possibly associated to the given subspecifier.

        :note: This method also stored directly in the DB.

        :param key: a string with the key to create (must be a level-0
          attribute, that is it cannot contain the separator cls._sep).
        :param value: the value to store (a basic data type or a list or a dict)
        :param subspecifier_value: must be None if this class has no
          subspecifier set (e.g., the DbSetting class).
          Must be the value of the subspecifier (e.g., the dbnode) for classes
          that define it (e.g. DbAttribute and DbExtra)
        :param with_transaction: True if you want this function to be managed
          with transactions. Set to False if you already have a manual
          management of transactions in the block where you are calling this
          function (useful for speed improvements to avoid recursive
          transactions)
        :param other_attribs: a dictionary of other parameters, to store
          only on the level-zero attribute (e.g. for description in DbSetting).
        :param stop_if_existing: if True, it will stop with an
           UniquenessError exception if the new entry would violate an
           uniqueness constraint in the DB (same key, or same key+node,
           depending on the specific subclass). Otherwise, it will
           first delete the old value, if existent. The use with True is
           useful if you want to use a given attribute as a "locking" value,
           e.g. to avoid to perform an action twice on the same node.
           Note that, if you are using transactions, you may get the error
           only when the transaction is committed.
        """
        cls.validate_key(key)

        try:
            if with_transaction:
                sid = transaction.savepoint()

            # create_value returns a list of nodes to store
            to_store = cls.create_value(key,
                                        value,
                                        subspecifier_value=subspecifier_value,
                                        other_attribs=other_attribs)

            if to_store:
                # if not stop_if_existing:
                #     # Delete the olf values if stop_if_existing is False,
                #     # otherwise don't delete them and hope they don't
                #     # exist. If they exist, I'll get an UniquenessError
                #
                #     ## NOTE! Be careful in case the extra/attribute to
                #     ## store is not a simple attribute but a list or dict:
                #     ## like this, it should be ok because if we are
                #     ## overwriting an entry it will stop anyway to avoid
                #     ## to overwrite the main entry, but otherwise
                #     ## there is the risk that trailing pieces remain
                #     ## so in general it is good to recursively clean
                #     ## all sub-items.
                #     cls.del_value(key,
                #                   subspecifier_value=subspecifier_value)
                for my_obj in to_store:
                    my_obj.save()

                # cls.objects.bulk_create(to_store)

            if with_transaction:
                transaction.savepoint_commit(sid)
        except BaseException as exc:  # All exceptions including CTRL+C, ...
            from django.db.utils import IntegrityError
            from aiida.common.exceptions import UniquenessError

            if with_transaction:
                transaction.savepoint_rollback(sid)
            if isinstance(exc, IntegrityError) and stop_if_existing:
                raise UniquenessError(
                    'Impossible to create the required '
                    'entry '
                    "in table '{}', "
                    'another entry already exists and the creation would '
                    'violate an uniqueness constraint.\nFurther details: '
                    '{}'.format(cls.__name__, exc))
            raise
Example #12
0
    def _prepare_for_submission(self, tempfolder, inputdict):
        """
        This is the routine to be called when you want to create
        the input files and related stuff with a plugin.
        
        :param tempfolder: a aiida.common.folders.Folder subclass where
                           the plugin should put all its files.
        :param inputdict: a dictionary with the input nodes, as they would
                be returned by get_inputdata_dict (with the Code(s)!)
        """

        local_copy_list = []
        remote_copy_list = []
        remote_symlink_list = []

        # Settings can be undefined, and defaults to an empty dictionary.
        # They will be used for any input that doen't fit elsewhere.
        settings = inputdict.pop(self.get_linkname('settings'), None)
        if settings is None:
            settings_dict = {}
        else:
            if not isinstance(settings, ParameterData):
                raise InputValidationError(
                    "settings, if specified, must be of "
                    "type ParameterData")
            # Settings converted to uppercase
            settings_dict = _uppercase_dict(settings.get_dict(),
                                            dict_name='settings')
        initialise = settings_dict.pop('INITIALISE', None)
        if initialise is not None:
            if not isinstance(initialise, bool):
                raise InputValidationError("INITIALISE must be " " a boolean")
        try:
            parameters = inputdict.pop(self.get_linkname('parameters'))
        except KeyError:
            if not initialise:
                raise InputValidationError(
                    "No parameters specified for this calculation")
            else:
                pass
        if not initialise:
            if not isinstance(parameters, ParameterData):
                raise InputValidationError(
                    "parameters is not of type ParameterData")

        parent_calc_folder = inputdict.pop(self.get_linkname('parent_folder'),
                                           None)
        if parent_calc_folder is None:
            raise InputValidationError(
                "No parent calculation found, it is needed to "
                "use Yambo")
        if not isinstance(parent_calc_folder, RemoteData):
            raise InputValidationError("parent_calc_folder must be of"
                                       " type RemoteData")

        main_code = inputdict.pop(self.get_linkname('code'), None)
        if main_code is None:
            raise InputValidationError("No input code found!")

        preproc_code = inputdict.pop(self.get_linkname('preprocessing_code'),
                                     None)
        if preproc_code is not None:
            if not isinstance(preproc_code, Code):
                raise InputValidationError("preprocessing_code, if specified,"
                                           "must be of type Code")

        parent_calc = parent_calc_folder.get_inputs_dict(
            link_type=LinkType.CREATE)['remote_folder']
        yambo_parent = isinstance(parent_calc, YamboCalculation)

        # flags for yambo interfaces
        try:
            precode_parameters = inputdict.pop(
                self.get_linkname('precode_parameters'))
        except KeyError:
            precode_parameters = ParameterData(dict={})
        if not isinstance(precode_parameters, ParameterData):
            raise InputValidationError('precode_parameters is not '
                                       'of type ParameterData')
        precode_param_dict = precode_parameters.get_dict()

        # check the precode parameters given in input
        input_cmdline = settings_dict.pop('CMDLINE', None)
        import re
        precode_params_list = []
        pattern = re.compile(r"(^\-)([a-zA-Z])")
        for key, value in precode_param_dict.iteritems():
            if re.search(pattern, key) is not None:
                if key == '-O' or key == '-H' or key == '-h' or key == '-F':
                    raise InputValidationError(
                        "Precode flag {} is not allowed".format(str(key)))
                else:
                    if precode_param_dict[key] is True:
                        precode_params_list.append(str(key))
                    elif precode_param_dict[key] is False:
                        pass
                    else:
                        precode_params_list.append('{}'.format(str(key)))
                        precode_params_list.append('{}'.format(str(value)))
            else:
                raise InputValidationError(
                    "Wrong format of precode_parameters")
        # Adding manual cmdline input (e.g. for DB fragmentation)
        if input_cmdline is not None:
            precode_params_list = precode_params_list + input_cmdline

        # TODO: check that remote data must be on the same computer

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

        if not initialise:
            ###################################################
            # Prepare yambo input file
            ###################################################

            params_dict = parameters.get_dict()

            # extract boolean keys
            boolean_dict = {
                k: v
                for k, v in params_dict.iteritems() if isinstance(v, bool)
            }
            params_dict = {
                k: v
                for k, v in params_dict.iteritems()
                if k not in boolean_dict.keys()
            }

            # reorganize the dictionary and create a list of dictionaries with key, value and units
            parameters_list = []
            for k, v in params_dict.iteritems():

                if "_units" in k:
                    continue

                units_key = "{}_units".format(k)
                try:
                    units = params_dict[units_key]
                except KeyError:
                    units = None

                this_dict = {}
                this_dict['key'] = k
                this_dict['value'] = v
                this_dict['units'] = units

                parameters_list.append(this_dict)

            input_filename = tempfolder.get_abs_path(self._INPUT_FILE_NAME)

            with open(input_filename, 'w') as infile:
                infile.write(self._LOGOSTRING)

                for k, v in boolean_dict.iteritems():
                    if v:
                        infile.write("{}\n".format(k))

                for this_dict in parameters_list:
                    key = this_dict['key']
                    value = this_dict['value']
                    units = this_dict['units']

                    if isinstance(value, (tuple, list)):
                        # write the input flags for the Drude term and for the parallelization options of vers. 4
                        # (it can be implemented in a better way)
                        if key.startswith('DrudeW'):
                            value_string = " ( " + ",".join(
                                [str(_) for _ in value]) + " )"
                            the_string = "{} = {}".format(key, value_string)
                            the_string += " {}".format(units)
                            infile.write(the_string + "\n")
                            continue

                        if key == 'SE_CPU':
                            value_string = " \" " + " ".join(
                                [str(_) for _ in value]) + " \" "
                            the_string = "{} = {}".format(key, value_string)
                            infile.write("SE_ROLEs = \" q qp b  \" " + "\n")
                            infile.write(the_string + "\n")
                            continue

                        if key == 'X_all_q_CPU':
                            value_string = " \" " + " ".join(
                                [str(_) for _ in value]) + " \" "
                            the_string = "{} = {}".format(key, value_string)
                            infile.write("X_all_q_ROLEs = \" q k c v  \" " +
                                         "\n")
                            infile.write(the_string + "\n")
                            continue

                        if key == 'X_finite_q_CPU':
                            value_string = " \" " + " ".join(
                                [str(_) for _ in value]) + " \" "
                            the_string = "{} = {}".format(key, value_string)
                            infile.write("X_finite_q_ROLEs = \" q k c v  \" " +
                                         "\n")
                            infile.write(the_string + "\n")
                            continue

                        if key == 'X_q_0_CPU':
                            value_string = " \" " + " ".join(
                                [str(_) for _ in value]) + " \" "
                            the_string = "{} = {}".format(key, value_string)
                            infile.write("X_q_0_ROLEs = \" k c v  \" " + "\n")
                            infile.write(the_string + "\n")
                            continue

                        if key == 'QPkrange' or key == 'QPerange':
                            value_string = ''
                            for v in value:
                                value_string += " | ".join([str(_) for _ in v
                                                            ]) + " |\n"
                            the_string = "% {}\n {}".format(key, value_string)
                            the_string += "%"
                            infile.write(the_string + "\n")
                            continue

                        value_string = " | ".join([str(_)
                                                   for _ in value]) + " |"
                        the_string = "% {}\n {}".format(key, value_string)
                        if units is not None:
                            the_string += " {}".format(units)
                        the_string += "\n%"

                    else:
                        the_value = '"{}"'.format(value) if isinstance(
                            value, basestring) else '{}'.format(value)
                        the_string = "{} = {}".format(key, the_value)
                        if units is not None:
                            the_string += " {}".format(units)

                    infile.write(the_string + "\n")

        ############################################
        # set copy of the parent calculation
        ############################################

        parent_calcs = parent_calc_folder.get_inputs(link_type=LinkType.CREATE)
        if len(parent_calcs) > 1:
            raise UniquenessError(
                "More than one parent totalenergy calculation"
                "has been found for parent_calc_folder {}".format(
                    parent_calc_folder))
        if len(parent_calcs) == 0:
            raise InputValidationError(
                "No parent calculation associated with parent_folder {}".
                format(parent_calc_folder))
        parent_calc = parent_calcs[0]

        if yambo_parent:
            try:
                parent_settings = _uppercase_dict(
                    parent_calc.inp.settings.get_dict(),
                    dict_name='parent settings')
                parent_initialise = parent_settings['INITIALISE']
            except KeyError:
                parent_initialise = False

        if yambo_parent:
            remote_copy_list.append(
                (parent_calc_folder.get_computer().uuid,
                 os.path.join(parent_calc_folder.get_remote_path(),
                              "SAVE"), "SAVE/"))
            if not parent_initialise:
                cancopy = False
                if parent_calc.get_state() == calc_states.FINISHED:
                    cancopy = True
                if 'yambo_wrote' in parent_calc.get_outputs_dict(
                )['output_parameters'].get_dict().keys():
                    if parent_calc.get_outputs_dict(
                    )['output_parameters'].get_dict()['yambo_wrote'] == True:
                        cancopy = True
                    if parent_calc.get_outputs_dict(
                    )['output_parameters'].get_dict()['yambo_wrote'] == False:
                        cancopy = False
                if cancopy:
                    remote_copy_list.append(
                        (parent_calc_folder.get_computer().uuid,
                         os.path.join(parent_calc_folder.get_remote_path(),
                                      "aiida"), "aiida/"))
        else:
            remote_copy_list.append(
                (parent_calc_folder.get_computer().uuid,
                 os.path.join(parent_calc_folder.get_remote_path(),
                              PwCalculation._OUTPUT_SUBFOLDER,
                              "{}.save".format(parent_calc._PREFIX),
                              "*"), "."))
        ############################################
        # set Calcinfo
        ############################################

        calcinfo = CalcInfo()

        calcinfo.uuid = self.uuid

        calcinfo.local_copy_list = []
        calcinfo.remote_copy_list = remote_copy_list
        calcinfo.remote_symlink_list = []  # remote_symlink_list

        # Retrieve by default the output file and the xml file
        calcinfo.retrieve_list = []
        calcinfo.retrieve_list.append('r*')
        calcinfo.retrieve_list.append('l*')
        calcinfo.retrieve_list.append('o*')
        calcinfo.retrieve_list.append('LOG/l-*_CPU_1')
        extra_retrieved = settings_dict.pop(
            'ADDITIONAL_RETRIEVE_LIST',
            ['aiida/ndb.QP', 'aiida/ndb.HF_and_locXC'])
        for extra in extra_retrieved:
            calcinfo.retrieve_list.append(extra)

        from aiida.common.datastructures import code_run_modes, CodeInfo

        # c1 = interface dft codes and yambo (ex. p2y or a2y)
        c1 = CodeInfo()
        c1.withmpi = True
        c1.cmdline_params = precode_params_list

        # c2 = yambo initialization
        c2 = CodeInfo()
        c2.withmpi = True
        c2.cmdline_params = []
        c2.code_uuid = main_code.uuid

        # if the parent calculation is a yambo calculation skip the interface (c1) and the initialization (c2)
        if yambo_parent:
            c1 = None
            if not parent_initialise:
                c2 = None
        else:
            c1.cmdline_params = precode_params_list
            c1.code_uuid = preproc_code.uuid

        # c3 = yambo calculation
        c3 = CodeInfo()
        c3.withmpi = self.get_withmpi()
        c3.cmdline_params = [
            "-F", self._INPUT_FILE_NAME, '-J', self._OUTPUT_FILE_NAME
        ]
        c3.code_uuid = main_code.uuid

        if initialise:
            c2 = None
            c3 = None

        #calcinfo.codes_info = [c1, c2, c3] if not yambo_parent else [c3]
        if yambo_parent:
            if not parent_initialise:
                calcinfo.codes_info = [c3]
            else:
                calcinfo.codes_info = [c2, c3]
        elif initialise:
            calcinfo.codes_info = [c1]
        else:
            calcinfo.codes_info = [c1, c2, c3]

        calcinfo.codes_run_mode = code_run_modes.SERIAL

        if settings_dict:
            raise InputValidationError(
                "The following keys have been found in "
                "the settings input node, but were not understood: {}".format(
                    ",".join(settings_dict.keys())))

        return calcinfo
Example #13
0
    def _get_and_verify_hostfiles(self, tempfolder):
        """
        Check inputdict for host_Greenfunction_folder and extract impurity_info, paths to kkrflex-files and path of shapefun file

        :param inputdict: input dictionary containing all input nodes to KkrimpCalculation
        :returns:
            * imp_info: Dict node containing impurity information like position, Z_imp, cluster size, etc.
            * kkrflex_file_paths: dict of absolute file paths for the kkrflex files
            * shapefun_path: absolute path of the shapefunction file in the host calculation (needed to construct shapefun_imp)
            * shapes: mapping array of atoms to shapes (<SHAPE> input)
        :note: shapefun_path is None if host_Greenfunction calculation was not full-potential
        :raises:
            * InputValidationError, if inputdict does not contain 'host_Greenfunction'
            * InputValidationError, if host_Greenfunction_folder not of right type
            * UniquenessError, if host_Greenfunction_folder does not have exactly one parent
            * InputValidationError, if host_Greenfunction does not have an input node impurity_info
            * InputValidationError, if host_Greenfunction was not a KKRFLEX calculation
        """

        # get mandatory input nodes (extract host_Greenfunction_folder)
        host_parent = self.inputs.host_Greenfunction_folder

        # extract parent calculation
        parent_calcs = host_parent.get_incoming(node_class=CalcJob)
        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
        # extract impurity_info
        if 'impurity_info' in self.inputs:
            imp_info_inputnode = self.inputs.impurity_info
            if not isinstance(imp_info_inputnode, Dict):
                raise InputValidationError("impurity_info not of type Dict")
            if 'impurity_info' in parent_calc.get_incoming().all_link_labels():
                imp_info = parent_calc.get_incoming().get_node_by_label(
                    'impurity_info')
            else:
                imp_info = None
            if imp_info is None:
                raise InputValidationError(
                    "host_Greenfunction calculation does not have an input node impurity_info"
                )
            found_impurity_inputnode = True
            found_host_parent = True
        else:
            if 'impurity_info' in parent_calc.get_incoming().all_link_labels():
                imp_info = parent_calc.get_incoming().get_node_by_label(
                    'impurity_info')
            else:
                imp_info = None
            if imp_info is None:
                raise InputValidationError(
                    "host_Greenfunction calculation does not have an input node impurity_info"
                )
            found_impurity_inputnode = False

        # if impurity input is seperate input, check if it is the same as
        # the one from the parent calc (except for 'Zimp'). If that's not the
        # case, raise an error
        if found_impurity_inputnode and found_host_parent:
            #TODO: implement also 'ilayer_center' check
            if imp_info_inputnode.get_dict().get(
                    'Rcut') == imp_info.get_dict().get('Rcut'):
                check_consistency_imp_info = True
                try:
                    if (imp_info_inputnode.get_dict().get('hcut')
                            == imp_info.get_dict().get('hcut')
                            and imp_info_inputnode.get_dict().get(
                                'cylinder_orient')
                            == imp_info.get_dict().get('cylinder_orient')
                            and imp_info_inputnode.get_dict().get('Rimp_rel')
                            == imp_info.get_dict().get('Rimp_rel')
                            and imp_info_inputnode.get_dict().get('imp_cls')
                            == imp_info.get_dict().get('imp_cls')):
                        print(
                            'impurity_info node from input and from previous GF calculation are compatible'
                        )
                        check_consistency_imp_info = True
                    else:
                        print(
                            'impurity_info node from input and from previous GF calculation are NOT compatible!. '
                            'Please check your impurity_info nodes for consistency.'
                        )
                        check_consistency_imp_info = False
                except AttributeError:
                    print(
                        "Non default values of the impurity_info node from input and from previous "
                        "GF calculation are compatible. Default values haven't been checked"
                    )
                    check_consistency_imp_info = True
            else:
                print(
                    'impurity_info node from input and from previous GF calculation are NOT compatible!. '
                    'Please check your impurity_info nodes for consistency.')
                check_consistency_imp_info = False
            if check_consistency_imp_info:
                imp_info = imp_info_inputnode
            else:
                raise InputValidationError(
                    "impurity_info nodes (input and GF calc) are not compatible"
                )

        # check if host parent was KKRFLEX calculation
        hostfolder = parent_calc.outputs.retrieved
        input_file = hostfolder.open(KkrCalculation._DEFAULT_INPUT_FILE)
        params_host_calc = kkrparams(
            params_type='kkr'
        )  # initialize kkrparams instance to use read_keywords_from_inputcard
        params_host_calc.read_keywords_from_inputcard(inputcard=input_file)

        if 'RUNOPT' not in list(params_host_calc.get_dict().keys()):
            host_ok = False
        elif 'KKRFLEX' not in params_host_calc.get_dict().get('RUNOPT', []):
            host_ok = False
        else:
            host_ok = True

        if not host_ok:
            raise InputValidationError(
                "host_Greenfunction calculation was not a KKRFLEX run")

        # extract information from Efshift host GF input node (not mandatory)
        if 'host_Greenfunction_folder_Efshift' in self.inputs:
            host_parent_Efshift = self.inputs.host_Greenfunction_folder_Efshift
            parent_calcs_Efshift = host_parent_Efshift.get_incoming(
                node_class=CalcJob)
            parent_calc_Efshift = parent_calcs_Efshift.first().node
            hostfolder_Efshift = parent_calc_Efshift.outputs.retrieved
        else:
            hostfolder_Efshift = None

        kkrflex_file_paths = {}
        for filename in self._ALL_KKRFLEX_FILES:
            if filename in hostfolder.list_object_names():
                kkrflex_file_paths[filename] = hostfolder
            # take tmat and green file from Fermi level overwrite directory (second GF_writeout calculation)
            if hostfolder_Efshift is not None and filename in [
                    self._KKRFLEX_TMAT, self._KKRFLEX_GREEN
            ]:
                if filename in hostfolder_Efshift.list_object_names():
                    kkrflex_file_paths[filename] = hostfolder_Efshift

        # extract shapes array from parameters read from inputcard
        shapes = params_host_calc.get_dict().get('<SHAPE>', None)
        if shapes is None:
            # fallback if SHAPES is not explicityl set (assume each atom has it's own shapefun
            shapes = range(1, params_host_calc.get_dict().get('NAEZ') + 1)
        elif type(shapes) == int:
            shapes = [shapes]

        # extract input structure and voro_parent to get shapefun in next step
        try:
            structure, voro_parent = VoronoiCalculation.find_parent_structure(
                parent_calc)
        except:
            raise InputValidationError(
                "No structure node found from host GF parent")

        # extract shapefun path for read-in
        shapefun_path = {}
        if VoronoiCalculation._SHAPEFUN in voro_parent.outputs.retrieved.list_object_names(
        ):
            shapefun_path = voro_parent.outputs.retrieved
        else:
            shapefun_path = None

        return imp_info, kkrflex_file_paths, shapefun_path, shapes, parent_calc, params_host_calc, structure
Example #14
0
def upload_psf_family(folder,
                      group_name,
                      group_description,
                      stop_if_existing=True):
    """
    Upload a set of PSF files in a given group.

    :param folder: a path containing all PSF files to be added.
        Only files ending in .PSF (case-insensitive) are considered.
    :param group_name: the name of the group to create. If it exists and is
        non-empty, a UniquenessError is raised.
    :param group_description: a string to be set as the group description.
        Overwrites previous descriptions, if the group was existing.
    :param stop_if_existing: if True, check for the md5 of the files and,
        if the file already exists in the DB, raises a MultipleObjectsError.
        If False, simply adds the existing PsfData node to the group.
    """
    import os
    import aiida.common
    from aiida.common import aiidalogger
    from aiida.orm import Group
    from aiida.common.exceptions import UniquenessError, NotExistent
    from aiida.backends.utils import get_automatic_user
    from aiida.orm.querybuilder import QueryBuilder
    if not os.path.isdir(folder):
        raise ValueError("folder must be a directory")

    # only files, and only those ending with .psf or .PSF;
    # go to the real file if it is a symlink
    files = [
        os.path.realpath(os.path.join(folder, i)) for i in os.listdir(folder)
        if os.path.isfile(os.path.join(folder, i))
        and i.lower().endswith('.psf')
    ]

    nfiles = len(files)

    try:
        group = Group.get(name=group_name, type_string=PSFGROUP_TYPE)
        group_created = False
    except NotExistent:
        group = Group(name=group_name,
                      type_string=PSFGROUP_TYPE,
                      user=get_automatic_user())
        group_created = True

    if group.user != get_automatic_user():
        raise UniquenessError("There is already a PsfFamily group with name {}"
                              ", but it belongs to user {}, therefore you "
                              "cannot modify it".format(
                                  group_name, group.user.email))

    # Always update description, even if the group already existed
    group.description = group_description

    # NOTE: GROUP SAVED ONLY AFTER CHECKS OF UNICITY

    pseudo_and_created = []

    for f in files:
        md5sum = aiida.common.utils.md5_file(f)
        qb = QueryBuilder()
        qb.append(PsfData, filters={'attributes.md5': {'==': md5sum}})
        existing_psf = qb.first()

        #existing_psf = PsfData.query(dbattributes__key="md5",
        #                            dbattributes__tval = md5sum)

        if existing_psf is None:
            # return the psfdata instances, not stored
            pseudo, created = PsfData.get_or_create(f,
                                                    use_first=True,
                                                    store_psf=False)
            # to check whether only one psf per element exists
            # NOTE: actually, created has the meaning of "to_be_created"
            pseudo_and_created.append((pseudo, created))
        else:
            if stop_if_existing:
                raise ValueError("A PSF with identical MD5 to "
                                 " {} cannot be added with stop_if_existing"
                                 "".format(f))
            existing_psf = existing_psf[0]
            pseudo_and_created.append((existing_psf, False))

    # check whether pseudo are unique per element
    elements = [(i[0].element, i[0].md5sum) for i in pseudo_and_created]
    # If group already exists, check also that I am not inserting more than
    # once the same element
    if not group_created:
        for aiida_n in group.nodes:
            # Skip non-pseudos
            if not isinstance(aiida_n, PsfData):
                continue
            elements.append((aiida_n.element, aiida_n.md5sum))

    elements = set(elements)  # Discard elements with the same MD5, that would
    # not be stored twice
    elements_names = [e[0] for e in elements]

    if not len(elements_names) == len(set(elements_names)):
        duplicates = set(
            [x for x in elements_names if elements_names.count(x) > 1])
        duplicates_string = ", ".join(i for i in duplicates)
        raise UniquenessError("More than one PSF found for the elements: " +
                              duplicates_string + ".")

    # At this point, save the group, if still unstored
    if group_created:
        group.store()

    # save the psf in the database, and add them to group
    for pseudo, created in pseudo_and_created:
        if created:
            pseudo.store()

            aiidalogger.debug("New node {} created for file {}".format(
                pseudo.uuid, pseudo.filename))
        else:
            aiidalogger.debug("Reusing node {} for file {}".format(
                pseudo.uuid, pseudo.filename))

    # Add elements to the group all togetehr
    group.add_nodes(pseudo for pseudo, created in pseudo_and_created)

    nuploaded = len([_ for _, created in pseudo_and_created if created])

    return nfiles, nuploaded
Example #15
0
    def _prepare_for_submission(self, tempfolder, inputdict):
        """
        Create input files.

            :param tempfolder: aiida.common.folders.Folder subclass where
                the plugin should put all its files.
            :param inputdict: dictionary of the input nodes as they would
                be returned by get_inputs_dict
        """

        has_parent = False
        local_copy_list = []
        # Check inputdict
        try:
            parameters = inputdict.pop(self.get_linkname('parameters'))
        except KeyError:
            raise InputValidationError(
                "No parameters specified for this calculation")
        if not isinstance(parameters, ParameterData):
            raise InputValidationError("parameters not of type ParameterData")

        try:
            imp_info = inputdict.pop(self.get_linkname('impurity_info'))
            found_imp_info = True
        except KeyError:
            imp_info = None
            found_imp_info = False
        if found_imp_info and not isinstance(imp_info, ParameterData):
            raise InputValidationError(
                "impurity_info not of type ParameterData")

        try:
            code = inputdict.pop(self.get_linkname('code'))
        except KeyError:
            raise InputValidationError(
                "No code specified for this calculation")

        # get qdos inputs
        try:
            kpath = inputdict.pop(self.get_linkname('kpoints'))
            found_kpath = True
        except KeyError:
            found_kpath = False

        try:
            parent_calc_folder = inputdict.pop(
                self.get_linkname('parent_folder'))
        except KeyError:
            raise InputValidationError(
                "Voronoi or previous KKR files needed for KKR calculation, "
                "you need to provide a Parent Folder/RemoteData node.")

        #TODO deal with data from folder data if calculation is continued on a different machine
        if not isinstance(parent_calc_folder, RemoteData):
            raise InputValidationError(
                "parent_calc_folder must be of type RemoteData")

        # extract parent calculation
        parent_calcs = parent_calc_folder.get_inputs(node_type=JobCalculation)
        n_parents = len(parent_calcs)
        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"))
            parent_calc = parent_calcs[0]
            has_parent = True
        if n_parents == 1:
            parent_calc = parent_calcs[0]
            has_parent = True

        # check if parent is either Voronoi or previous KKR calculation
        self._check_valid_parent(parent_calc)

        # extract parent input parameter dict for following check
        try:
            parent_inp_dict = parent_calc.inp.parameters.get_dict()
        except:
            self.logger.error(
                "Failed trying to find input parameter of parent {}".format(
                    parent_calc))
            raise InputValidationError(
                "No parameter node found of parent calculation.")

        # check if no keys are illegally overwritten (i.e. compare with keys in self._do_never_modify)
        for key in parameters.get_dict().keys():
            value = parameters.get_dict()[key]
            #self.logger.info("Checking {} {}".format(key, value))
            if not value is None:
                if key in self._do_never_modify:
                    oldvalue = parent_inp_dict[key]
                    if oldvalue is None and key in __kkr_default_params__:
                        oldvalue = __kkr_default_params__.get(key)
                    if value != oldvalue:
                        self.logger.error(
                            "You are trying to set keyword {} = {} but this is not allowed since the structure would be modified. Please use a suitable workfunction instead."
                            .format(key, value))
                        raise InputValidationError(
                            "You are trying to modify a keyword that is not allowed to be changed! (key={}, oldvalue={}, newvalue={})"
                            .format(key, oldvalue, value))

        #TODO check for remote folder (starting from folder data not implemented yet)
        # if voronoi calc check if folder from db given, or get folder from rep.
        # Parent calc does not has to be on the same computer.
        # so far we copy every thing from local computer ggf if kkr we want to copy remotely

        # get StructureData node from Parent if Voronoi
        structure = None
        self.logger.info(
            "KkrCalculation: Get structure node from voronoi parent")
        if isinstance(parent_calc, VoronoiCalculation):
            self.logger.info("KkrCalculation: Parent is Voronoi calculation")
            try:
                structure, voro_parent = VoronoiCalculation.find_parent_structure(
                    parent_calc)
            except:
                self.logger.error(
                    'KkrCalculation: Could not get structure from Voronoi parent.'
                )
                raise ValidationError("Cound not find structure node")
        elif isinstance(parent_calc, KkrCalculation):
            self.logger.info("KkrCalculation: Parent is KKR calculation")
            try:
                self.logger.info(
                    'KkrCalculation: extract structure from KKR parent')
                structure, voro_parent = VoronoiCalculation.find_parent_structure(
                    parent_calc)
            except:
                self.logger.error('Could not get structure from parent.')
                raise ValidationError(
                    'Cound not find structure node starting from parent {}'.
                    format(parent_calc))
        else:
            self.logger.error(
                "KkrCalculation: Parent is neither Voronoi nor KKR calculation!"
            )
            raise ValidationError('Cound not find structure node')

        if inputdict:
            self.logger.error(
                'KkrCalculation: Unknown inputs for structure lookup')
            raise ValidationError("Unknown inputs")

        # for VCA: check if input structure and parameter node define VCA structure
        vca_structure = vca_check(structure, parameters)

        ###################################

        # prepare scoef file if impurity_info was given
        write_scoef = False
        runopt = parameters.get_dict().get('RUNOPT', None)
        kkrflex_opt = False
        if runopt is not None:
            if 'KKRFLEX' in runopt:
                kkrflex_opt = True
        if kkrflex_opt:
            write_scoef = True
        elif found_imp_info:
            self.logger.info(
                'Found impurity_info in inputs of the calculation, automatically add runopt KKRFLEX'
            )
            write_scoef = True
            runopt = parameters.get_dict().get('RUNOPT', [])
            runopt.append('KKRFLEX')
            parameters = update_params_wf(
                parameters,
                ParameterData(
                    dict={
                        'RUNOPT': runopt,
                        'nodename': 'update_KKRFLEX',
                        'nodedesc': 'Update Parameter node with KKRFLEX runopt'
                    }))
        if found_imp_info and write_scoef:
            scoef_filename = os.path.join(tempfolder.get_abs_path(''),
                                          self._SCOEF)
            imp_info_dict = imp_info.get_dict()
            Rcut = imp_info_dict.get('Rcut', None)
            hcut = imp_info_dict.get('hcut', -1.)
            cylinder_orient = imp_info_dict.get('cylinder_orient',
                                                [0., 0., 1.])
            ilayer_center = imp_info_dict.get('ilayer_center', 0)
            for i in range(len(cylinder_orient)):
                try:
                    len(cylinder_orient[i])
                    vec_shape = False
                except TypeError:
                    vec_shape = True
            if ilayer_center > len(structure.sites) - 1:
                raise IndexError(
                    'Index of the reference site is out of range! Possible values: 0 to {}.'
                    .format(len(structure.sites) - 1))
            elif Rcut < 0:
                raise ValueError('Cutoff radius has to be positive!')
            elif vec_shape == False or len(cylinder_orient) != 3:
                raise TypeError(
                    'Input orientation vector ({}) has the wrong shape! It needs to be a 3D-vector!'
                    .format(cylinder_orient))
            else:
                print('Input parameters for make_scoef read in correctly!')
                make_scoef(structure, Rcut, scoef_filename, hcut,
                           cylinder_orient, ilayer_center)
        elif write_scoef:
            self.logger.info(
                'Need to write scoef file but no impurity_info given!')
            raise ValidationError(
                'Found RUNOPT KKRFLEX but no impurity_info in inputs')

        # Check for 2D case
        twoDimcheck, msg = check_2Dinput_consistency(structure, parameters)
        if not twoDimcheck:
            raise InputValidationError(msg)

        # set shapes array either from parent voronoi run or read from inputcard in kkrimporter calculation
        if parent_calc.get_parser_name() != 'kkr.kkrimporterparser':
            # get shapes array from voronoi parent
            shapes = voro_parent.res.shapes
        else:
            # extract shapes from input parameters node constructed by kkrimporter calculation
            shapes = voro_parent.inp.parameters.get_dict().get('<SHAPE>')

        #
        use_alat_input = parameters.get_dict().get('use_input_alat', False)

        # qdos option, ensure low T, E-contour, qdos run option and write qvec.dat file
        if found_kpath:
            # check qdos settings
            change_values = []
            runopt = parameters.get_dict().get('RUNOPT')
            if runopt is None: runopt = []
            runopt = [i.strip() for i in runopt]
            if 'qdos' not in runopt:
                runopt.append('qdos')
                change_values.append(['RUNOPT', runopt])
            tempr = parameters.get_dict().get('TEMPR')
            if tempr is None or tempr > 100.:
                change_values.append(['TEMPR', 50.])
            N1 = parameters.get_dict().get('TEMPR')
            if N1 is None or N1 > 0:
                change_values.append(['NPT1', 0])
            N2 = parameters.get_dict().get('NPT2')
            if N2 is None:
                change_values.append(['NPT2', 100])
            N3 = parameters.get_dict().get('NPT3')
            if N3 is None or N3 > 0.:
                change_values.append(['NPT3', 0])
            NPOL = parameters.get_dict().get('NPOL')
            if NPOL is None or NPOL > 0.:
                change_values.append(['NPOL', 0])
            if change_values != []:
                new_params = {
                    'nodename':
                    'changed_params_qdos',
                    'nodedesc':
                    'Changed parameters to mathc qdos mode. Changed values: {}'
                    .format(change_values)
                }
                for key, val in change_values:
                    new_params[key] = val
                new_params_node = ParameterData(dict=new_params)
                parameters = update_params_wf(parameters, new_params_node)
            # write qvec.dat file
            kpath_array = kpath.get_kpoints()
            # convert automatically to internal units
            if use_alat_input:
                alat = parameters.get_dict().get('ALATBASIS')
            else:
                alat = get_alat_from_bravais(
                    array(structure.cell),
                    is3D=structure.pbc[2]) * get_Ang2aBohr()
            kpath_array = kpath_array * (alat / 2. / pi)
            qvec = ['%i\n' % len(kpath_array)]
            qvec += [
                '%e %e %e\n' % (kpt[0], kpt[1], kpt[2]) for kpt in kpath_array
            ]
            qvecpath = tempfolder.get_abs_path(self._QVEC)
            with open(qvecpath, 'w') as file:
                file.writelines(qvec)

        # Prepare inputcard from Structure and input parameter data
        input_filename = tempfolder.get_abs_path(self._INPUT_FILE_NAME)
        natom, nspin, newsosol = generate_inputcard_from_structure(
            parameters,
            structure,
            input_filename,
            parent_calc,
            shapes=shapes,
            vca_structure=vca_structure,
            use_input_alat=use_alat_input)

        #################
        # Decide what files to copy based on settings to the code (e.g. KKRFLEX option needs scoef)
        if has_parent:
            # copy the right files #TODO check first if file, exists and throw
            # warning, now this will throw an error
            outfolderpath = parent_calc.out.retrieved.folder.abspath
            outfolderpath = os.path.join(outfolderpath, 'path')
            self.logger.info("out folder path {}".format(outfolderpath))

            copylist = []
            if isinstance(parent_calc, KkrCalculation):
                copylist = self._copy_filelist_kkr
                # TODO ggf copy remotely...

            if isinstance(parent_calc, VoronoiCalculation):
                copylist = [parent_calc._SHAPEFUN]
                # copy either overwrite potential or voronoi output potential
                # (voronoi caclualtion retreives only one of the two)
                if parent_calc._POTENTIAL_IN_OVERWRITE in os.listdir(
                        outfolderpath):
                    copylist.append(parent_calc._POTENTIAL_IN_OVERWRITE)
                else:
                    copylist.append(parent_calc._OUT_POTENTIAL_voronoi)

            #change copylist in case the calculation starts from an imported calculation
            if parent_calc.get_parser_name() == 'kkr.kkrimporterparser':
                copylist = []
                if not os.path.exists(
                        os.path.join(outfolderpath, self._OUT_POTENTIAL)):
                    copylist.append(self._POTENTIAL)
                else:
                    copylist.append(self._OUT_POTENTIAL)
                if os.path.exists(os.path.join(outfolderpath, self._SHAPEFUN)):
                    copylist.append(self._SHAPEFUN)

            # create local_copy_list from copylist and change some names automatically
            for file1 in copylist:
                filename = file1
                if (file1 == 'output.pot' or file1 == self._OUT_POTENTIAL
                        or (isinstance(parent_calc, VoronoiCalculation)
                            and file1 == parent_calc._POTENTIAL_IN_OVERWRITE)):
                    filename = self._POTENTIAL
                local_copy_list.append(
                    (os.path.join(outfolderpath,
                                  file1), os.path.join(filename)))

            # for set-ef option:
            ef_set = parameters.get_dict().get('ef_set', None)
            if ef_set is not None:
                print('local copy list before change: {}'.format(
                    local_copy_list))
                print(
                    "found 'ef_set' in parameters: change EF of potential to this value"
                )
                potcopy_info = [
                    i for i in local_copy_list if i[1] == self._POTENTIAL
                ][0]
                with open(potcopy_info[0]) as file:
                    # change potential and copy list
                    local_copy_list.remove(potcopy_info)
                    pot_new_name = tempfolder.get_abs_path(self._POTENTIAL +
                                                           '_new_ef')
                    local_copy_list.append((pot_new_name, self._POTENTIAL))

                    # change potential
                    txt = file.readlines()
                    potstart = []
                    for iline in range(len(txt)):
                        line = txt[iline]
                        if 'exc:' in line:
                            potstart.append(iline)
                    for ipotstart in potstart:
                        tmpline = txt[ipotstart + 3]
                        tmpline = tmpline.split()
                        newline = '%10.5f%20.14f%20.14f\n' % (float(
                            tmpline[0]), ef_set, float(tmpline[-1]))
                        txt[ipotstart + 3] = newline
                    # write new file
                    pot_new_ef = open(pot_new_name, 'w')
                    pot_new_ef.writelines(txt)
                    pot_new_ef.close()

            # TODO different copy lists, depending on the keywors input
            print('local copy list: {}'.format(local_copy_list))
            self.logger.info('local copy list: {}'.format(local_copy_list))

        # Prepare CalcInfo to be returned to aiida
        calcinfo = CalcInfo()
        calcinfo.uuid = self.uuid
        calcinfo.local_copy_list = local_copy_list
        calcinfo.remote_copy_list = []

        # TODO retrieve list needs some logic, retrieve certain files,
        # only if certain input keys are specified....
        calcinfo.retrieve_list = [
            self._DEFAULT_OUTPUT_FILE, self._INPUT_FILE_NAME, self._POTENTIAL,
            self._SHAPEFUN, self._SCOEF, self._NONCO_ANGLES_OUT,
            self._OUT_POTENTIAL, self._OUTPUT_0_INIT, self._OUTPUT_000,
            self._OUTPUT_2, self._OUT_TIMING_000
        ]

        # for special cases add files to retireve list:

        # 1. dos calculation, add *dos* files if NPOL==0
        retrieve_dos_files = False
        print('NPOL in parameter input:', parameters.get_dict()['NPOL'])
        if 'NPOL' in parameters.get_dict().keys():
            if parameters.get_dict()['NPOL'] == 0:
                retrieve_dos_files = True
        if 'TESTOPT' in parameters.get_dict().keys():
            testopts = parameters.get_dict()['TESTOPT']
            if testopts is not None:
                stripped_test_opts = [i.strip() for i in testopts]
                if 'DOS' in stripped_test_opts:
                    retrieve_dos_files = True
        if retrieve_dos_files:
            print('adding files for dos output', self._COMPLEXDOS,
                  self._DOS_ATOM, self._LMDOS)
            add_files = [self._COMPLEXDOS]
            for iatom in range(natom):
                add_files.append(self._DOS_ATOM % (iatom + 1))
                for ispin in range(nspin):
                    add_files.append(
                        (self._LMDOS % (iatom + 1, ispin + 1)).replace(
                            ' ', '0'))
            calcinfo.retrieve_list += add_files

        # 2. KKRFLEX calculation
        retrieve_kkrflex_files = False
        if 'RUNOPT' in parameters.get_dict().keys():
            runopts = parameters.get_dict()['RUNOPT']
            if runopts is not None:
                stripped_run_opts = [i.strip() for i in runopts]
                if 'KKRFLEX' in stripped_run_opts:
                    retrieve_kkrflex_files = True
        if retrieve_kkrflex_files:
            add_files = self._ALL_KKRFLEX_FILES
            print('adding files for KKRFLEX output', add_files)
            calcinfo.retrieve_list += add_files

        # 3. qdos claculation
        retrieve_qdos_files = False
        if 'RUNOPT' in parameters.get_dict().keys():
            runopts = parameters.get_dict()['RUNOPT']
            if runopts is not None:
                stripped_run_opts = [i.strip() for i in runopts]
                if 'qdos' in stripped_run_opts:
                    retrieve_qdos_files = True
        if retrieve_qdos_files:
            print('adding files for qdos output', self._QDOS_ATOM, self._QVEC)
            add_files = [self._QVEC]
            for iatom in range(natom):
                for ispin in range(nspin):
                    add_files.append(
                        (self._QDOS_ATOM % (iatom + 1, ispin + 1)).replace(
                            ' ', '0'))
            calcinfo.retrieve_list += add_files

        codeinfo = CodeInfo()
        codeinfo.cmdline_params = []
        codeinfo.code_uuid = code.uuid
        codeinfo.stdout_name = self._DEFAULT_OUTPUT_FILE
        calcinfo.codes_info = [codeinfo]

        return calcinfo
Example #16
0
    def prepare_for_submission(self, tempfolder):
        """
        Create input files.

            :param tempfolder: aiida.common.folders.Folder subclass where
                the plugin should put all its files.
            :param inputdict: dictionary of the input nodes as they would
                be returned by get_inputs_dict
        """

        has_parent = False
        local_copy_list = []

        # get mandatory input nodes
        parameters = self.inputs.parameters
        code = self.inputs.code
        parent_calc_folder = self.inputs.parent_folder

        # now check for optional nodes

        # for GF writeout
        if 'impurity_info' in self.inputs:
            imp_info = self.inputs.impurity_info
            found_imp_info = True
        else:
            imp_info = None
            found_imp_info = False

        # for qdos funcitonality
        if 'kpoints' in self.inputs:
            kpath = self.inputs.kpoints
            found_kpath = True
        else:
            found_kpath = 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"))
            # TODO change to exit code
        if n_parents == 1:
            parent_calc = parent_calcs.first().node
            has_parent = True

        # check if parent is either Voronoi or previous KKR calculation
        #self._check_valid_parent(parent_calc)

        # extract parent input parameter dict for following check
        try:
            parent_inp_dict = parent_calc.inputs.parameters.get_dict()
        except:
            self.logger.error(
                "Failed trying to find input parameter of parent {}".format(
                    parent_calc))
            raise InputValidationError(
                "No parameter node found of parent calculation.")

        # check if no keys are illegally overwritten (i.e. compare with keys in self._do_never_modify)
        for key in list(parameters.get_dict().keys()):
            value = parameters.get_dict()[key]
            #self.logger.info("Checking {} {}".format(key, value))
            if not value is None:
                if key in self._do_never_modify:
                    oldvalue = parent_inp_dict[key]
                    if oldvalue is None and key in __kkr_default_params__:
                        oldvalue = __kkr_default_params__.get(key)
                    if value == oldvalue:
                        values_eqivalent = True
                    else:
                        values_eqivalent = False
                        # check if values match up to certain numerical accuracy
                        if type(value) == float:
                            if abs(value - oldvalue) < self._eps:
                                values_eqivalent = True
                        elif type(value) == list or type(value) == ndarray:
                            tmp_value, tmp_oldvalue = array(value).reshape(
                                -1), array(oldvalue).reshape(-1)
                            values_eqivalent_tmp = []
                            for ival in range(len(tmp_value)):
                                if abs(tmp_value[ival] -
                                       tmp_oldvalue[ival]) < self._eps:
                                    values_eqivalent_tmp.append(True)
                                else:
                                    values_eqivalent_tmp.append(False)
                            if all(values_eqivalent_tmp) and len(value) == len(
                                    oldvalue):
                                values_eqivalent = True
                    if not values_eqivalent:
                        self.logger.error(
                            "You are trying to set keyword {} = {} but this is not allowed since the structure would be modified. Please use a suitable workfunction instead."
                            .format(key, value))
                        raise InputValidationError(
                            "You are trying to modify a keyword that is not allowed to be changed! (key={}, oldvalue={}, newvalue={})"
                            .format(key, oldvalue, value))

        #TODO check for remote folder (starting from folder data not implemented yet)
        # if voronoi calc check if folder from db given, or get folder from rep.
        # Parent calc does not has to be on the same computer.
        # so far we copy every thing from local computer ggf if kkr we want to copy remotely

        # get StructureData node from Parent if Voronoi
        structure = None
        self.logger.info(
            "KkrCalculation: Get structure node from voronoi parent")
        try:
            structure, voro_parent = VoronoiCalculation.find_parent_structure(
                parent_calc)
        except:
            self.logger.error(
                'KkrCalculation: Could not get structure from Voronoi parent ({}).'
                .format(parent_calc))
            raise ValidationError(
                "Cound not find structure node from parent {}".format(
                    parent_calc))

        # for VCA: check if input structure and parameter node define VCA structure
        vca_structure = vca_check(structure, parameters)

        ###################################

        # check whether or not the alat from the input parameters are used (this enters as a scaling factor for some parameters)
        use_alat_input = parameters.get_dict().get('use_input_alat', False)

        # prepare scoef file if impurity_info was given
        write_scoef = False
        runopt = parameters.get_dict().get('RUNOPT', None)
        kkrflex_opt = False
        if runopt is not None:
            if 'KKRFLEX' in runopt:
                kkrflex_opt = True
        if kkrflex_opt:
            write_scoef = True
        elif found_imp_info:
            self.logger.info(
                'Found impurity_info in inputs of the calculation, automatically add runopt KKRFLEX'
            )
            write_scoef = True
            runopt = parameters.get_dict().get('RUNOPT', [])
            runopt.append('KKRFLEX')
            parameters = update_params_wf(
                parameters,
                Dict(
                    dict={
                        'RUNOPT': runopt,
                        'nodename': 'update_KKRFLEX',
                        'nodedesc': 'Update Parameter node with KKRFLEX runopt'
                    }))
        if found_imp_info and write_scoef:
            imp_info_dict = imp_info.get_dict()
            Rcut = imp_info_dict.get('Rcut', None)
            hcut = imp_info_dict.get('hcut', -1.)
            cylinder_orient = imp_info_dict.get('cylinder_orient',
                                                [0., 0., 1.])
            ilayer_center = imp_info_dict.get('ilayer_center', 0)
            for i in range(len(cylinder_orient)):
                try:
                    len(cylinder_orient[i])
                    vec_shape = False
                except TypeError:
                    vec_shape = True
            if ilayer_center > len(structure.sites) - 1:
                raise IndexError(
                    'Index of the reference site is out of range! Possible values: 0 to {}.'
                    .format(len(structure.sites) - 1))
            elif Rcut < 0:
                raise ValueError('Cutoff radius has to be positive!')
            elif vec_shape == False or len(cylinder_orient) != 3:
                raise TypeError(
                    'Input orientation vector ({}) has the wrong shape! It needs to be a 3D-vector!'
                    .format(cylinder_orient))
            else:
                print('Input parameters for make_scoef read in correctly!')
                with tempfolder.open(self._SCOEF, 'w') as scoef_file:
                    if use_alat_input:
                        alat_input = parameters.get_dict().get(
                            'ALATBASIS', None) / get_Ang2aBohr()
                        self.logger.info('alat_input is ' + str(alat_input))
                    else:
                        self.logger.info('alat_input is None')
                        alat_input = None
                    make_scoef(structure, Rcut, scoef_file, hcut,
                               cylinder_orient, ilayer_center, alat_input)
        elif write_scoef:
            self.logger.info(
                'Need to write scoef file but no impurity_info given!')
            raise ValidationError(
                'Found RUNOPT KKRFLEX but no impurity_info in inputs')

        # Check for 2D case
        twoDimcheck, msg = check_2Dinput_consistency(structure, parameters)
        if not twoDimcheck:
            raise InputValidationError(msg)

        # set shapes array either from parent voronoi run or read from inputcard in kkrimporter calculation
        if parent_calc.process_label == 'VoronoiCalculation' or parent_calc.process_label == 'KkrCalculation':
            # get shapes array from voronoi parent
            shapes = voro_parent.outputs.output_parameters.get_dict().get(
                'shapes')
        else:
            # extract shapes from input parameters node constructed by kkrimporter calculation
            shapes = voro_parent.inputs.parameters.get_dict().get('<SHAPE>')
        self.logger.info('Extracted shapes: {}'.format(shapes))

        # qdos option, ensure low T, E-contour, qdos run option and write qvec.dat file
        if found_kpath:
            # check qdos settings
            change_values = []
            runopt = parameters.get_dict().get('RUNOPT')
            if runopt is None: runopt = []
            runopt = [i.strip() for i in runopt]
            if 'qdos' not in runopt:
                runopt.append('qdos')
                change_values.append(['RUNOPT', runopt])
            tempr = parameters.get_dict().get('TEMPR')
            if tempr is None or tempr > 100.:
                change_values.append(['TEMPR', 50.])
            N1 = parameters.get_dict().get('NPT1')
            if N1 is None or N1 > 0:
                change_values.append(['NPT1', 0])
            N2 = parameters.get_dict().get('NPT2')
            if N2 is None:
                change_values.append(['NPT2', 100])
            N3 = parameters.get_dict().get('NPT3')
            if N3 is None or N3 > 0.:
                change_values.append(['NPT3', 0])
            NPOL = parameters.get_dict().get('NPOL')
            if NPOL is None or NPOL > 0.:
                change_values.append(['NPOL', 0])
            if change_values != []:
                new_params = {}
                #{'nodename': 'changed_params_qdos', 'nodedesc': 'Changed parameters to mathc qdos mode. Changed values: {}'.format(change_values)}
                for key, val in parameters.get_dict().items():
                    new_params[key] = val
                for key, val in change_values:
                    new_params[key] = val
                new_params_node = Dict(dict=new_params)
                #parameters = update_params_wf(parameters, new_params_node)
                parameters = new_params_node
            # write qvec.dat file
            kpath_array = kpath.get_kpoints(cartesian=True)
            # convert automatically to internal units
            alat = get_alat_from_bravais(
                array(
                    structure.cell), is3D=structure.pbc[2]) * get_Ang2aBohr()
            if use_alat_input:
                alat_input = parameters.get_dict().get('ALATBASIS')
            else:
                alat_input = alat
            kpath_array = kpath_array * (
                alat_input / alat) / get_Ang2aBohr() / (2 * pi / alat)
            # now write file
            qvec = ['%i\n' % len(kpath_array)]
            qvec += [
                '%e %e %e\n' % (kpt[0], kpt[1], kpt[2]) for kpt in kpath_array
            ]
            with tempfolder.open(self._QVEC, 'w') as qvecfile:
                qvecfile.writelines(qvec)

        # Prepare inputcard from Structure and input parameter data
        with tempfolder.open(self._INPUT_FILE_NAME, u'w') as input_file:
            natom, nspin, newsosol, warnings_write_inputcard = generate_inputcard_from_structure(
                parameters,
                structure,
                input_file,
                parent_calc,
                shapes=shapes,
                vca_structure=vca_structure,
                use_input_alat=use_alat_input)

        #################
        # Decide what files to copy based on settings to the code (e.g. KKRFLEX option needs scoef)
        if has_parent:
            # copy the right files #TODO check first if file, exists and throw
            # warning, now this will throw an error
            outfolder = parent_calc.outputs.retrieved

            copylist = []
            if parent_calc.process_class == KkrCalculation:
                copylist = [self._OUT_POTENTIAL]
                # TODO ggf copy remotely from remote node if present ...

            elif parent_calc.process_class == VoronoiCalculation:
                copylist = [parent_calc.process_class._SHAPEFUN]
                # copy either overwrite potential or voronoi output potential
                # (voronoi caclualtion retreives only one of the two)
                if parent_calc.process_class._POTENTIAL_IN_OVERWRITE in outfolder.list_object_names(
                ):
                    copylist.append(
                        parent_calc.process_class._POTENTIAL_IN_OVERWRITE)
                else:
                    copylist.append(
                        parent_calc.process_class._OUT_POTENTIAL_voronoi)

            #change copylist in case the calculation starts from an imported calculation
            else:  #if parent_calc.process_class == KkrImporterCalculation:
                if self._OUT_POTENTIAL in outfolder.list_object_names():
                    copylist.append(self._OUT_POTENTIAL)
                else:
                    copylist.append(self._POTENTIAL)
                if self._SHAPEFUN in outfolder.list_object_names():
                    copylist.append(self._SHAPEFUN)

            # create local_copy_list from copylist and change some names automatically
            for file1 in copylist:
                # deal with special case that file is written to another name
                if (file1 == 'output.pot' or file1 == self._OUT_POTENTIAL or
                    (parent_calc.process_class == VoronoiCalculation and file1
                     == parent_calc.process_class._POTENTIAL_IN_OVERWRITE)):
                    filename = self._POTENTIAL
                else:
                    filename = file1
                # now add to copy list
                local_copy_list.append((outfolder.uuid, file1, filename))

                # add shapefun file from voronoi parent if needed
                if self._SHAPEFUN not in copylist:
                    try:
                        struc, voro_parent = VoronoiCalculation.find_parent_structure(
                            parent_calc)
                    except ValueError:
                        return self.exit_codes.ERROR_NO_SHAPEFUN_FOUND
                    # copy shapefun from retrieved of voro calc
                    voro_retrieved = voro_parent.outputs.retrieved
                    local_copy_list.append(
                        (voro_retrieved.uuid, VoronoiCalculation._SHAPEFUN,
                         self._SHAPEFUN))

            # for set-ef option:
            ef_set = parameters.get_dict().get('ef_set', None)
            if ef_set is not None:
                print('local copy list before change: {}'.format(
                    local_copy_list))
                print(
                    "found 'ef_set' in parameters: change EF of potential to this value"
                )
                potcopy_info = [
                    i for i in local_copy_list if i[2] == self._POTENTIAL
                ][0]
                with load_node(potcopy_info[0]).open(
                        potcopy_info[1]) as potfile:
                    # remove previous output potential from copy list
                    local_copy_list.remove(potcopy_info)
                    # create potential here by readin in old potential and overwriting with changed Fermi energy
                    with tempfolder.open(self._POTENTIAL, 'w') as pot_new_ef:
                        # change potential
                        txt = potfile.readlines()
                        potstart = []
                        for iline in range(len(txt)):
                            line = txt[iline]
                            if 'exc:' in line:
                                potstart.append(iline)
                        for ipotstart in potstart:
                            tmpline = txt[ipotstart + 3]
                            tmpline = tmpline.split()
                            newline = '%10.5f%20.14f%20.14f\n' % (float(
                                tmpline[0]), ef_set, float(tmpline[-1]))
                            txt[ipotstart + 3] = newline
                        # write new file
                        pot_new_ef.writelines(txt)
                    # now this directory contains the updated potential file, thus it is not needed to put it in the local copy list anymore

            # TODO different copy lists, depending on the keywors input
            print('local copy list: {}'.format(local_copy_list))
            self.logger.info('local copy list: {}'.format(local_copy_list))

        # Prepare CalcInfo to be returned to aiida
        calcinfo = CalcInfo()
        calcinfo.uuid = self.uuid
        calcinfo.local_copy_list = local_copy_list
        calcinfo.remote_copy_list = []

        # TODO retrieve list needs some logic, retrieve certain files,
        # only if certain input keys are specified....
        calcinfo.retrieve_list = [
            self._DEFAULT_OUTPUT_FILE, self._INPUT_FILE_NAME, self._SCOEF,
            self._NONCO_ANGLES_OUT, self._OUT_POTENTIAL, self._OUTPUT_0_INIT,
            self._OUTPUT_000, self._OUTPUT_2, self._OUT_TIMING_000
        ]

        # for special cases add files to retireve list:

        # 1. dos calculation, add *dos* files if NPOL==0
        retrieve_dos_files = False
        print('NPOL in parameter input:', parameters.get_dict()['NPOL'])
        if 'NPOL' in list(parameters.get_dict().keys()):
            if parameters.get_dict()['NPOL'] == 0:
                retrieve_dos_files = True
        if 'TESTOPT' in list(parameters.get_dict().keys()):
            testopts = parameters.get_dict()['TESTOPT']
            if testopts is not None:
                stripped_test_opts = [i.strip() for i in testopts]
                if 'DOS' in stripped_test_opts:
                    retrieve_dos_files = True
        if retrieve_dos_files:
            print('adding files for dos output', self._COMPLEXDOS,
                  self._DOS_ATOM, self._LMDOS)
            add_files = [self._COMPLEXDOS]
            for iatom in range(natom):
                add_files.append(self._DOS_ATOM % (iatom + 1))
                for ispin in range(nspin):
                    add_files.append(
                        (self._LMDOS % (iatom + 1, ispin + 1)).replace(
                            ' ', '0'))
            calcinfo.retrieve_list += add_files

        # 2. KKRFLEX calculation
        retrieve_kkrflex_files = False
        if 'RUNOPT' in list(parameters.get_dict().keys()):
            runopts = parameters.get_dict()['RUNOPT']
            if runopts is not None:
                stripped_run_opts = [i.strip() for i in runopts]
                if 'KKRFLEX' in stripped_run_opts:
                    retrieve_kkrflex_files = True
        if retrieve_kkrflex_files:
            add_files = self._ALL_KKRFLEX_FILES
            print('adding files for KKRFLEX output', add_files)
            calcinfo.retrieve_list += add_files

        # 3. qdos claculation
        retrieve_qdos_files = False
        if 'RUNOPT' in list(parameters.get_dict().keys()):
            runopts = parameters.get_dict()['RUNOPT']
            if runopts is not None:
                stripped_run_opts = [i.strip() for i in runopts]
                if 'qdos' in stripped_run_opts:
                    retrieve_qdos_files = True
        if retrieve_qdos_files:
            print('adding files for qdos output', self._QDOS_ATOM, self._QVEC)
            add_files = [self._QVEC]
            for iatom in range(natom):
                for ispin in range(nspin):
                    add_files.append(
                        (self._QDOS_ATOM % (iatom + 1, ispin + 1)).replace(
                            ' ', '0'))
                # retrieve also qdos_sx,y,z files if written out
                add_files.append(
                    (self._QDOS_SX % (iatom + 1)).replace(' ', '0'))
                add_files.append(
                    (self._QDOS_SY % (iatom + 1)).replace(' ', '0'))
                add_files.append(
                    (self._QDOS_SZ % (iatom + 1)).replace(' ', '0'))
            calcinfo.retrieve_list += add_files

        # 4. Jij calculation
        retrieve_Jij_files = False
        if 'RUNOPT' in list(parameters.get_dict().keys()):
            runopts = parameters.get_dict()['RUNOPT']
            if runopts is not None:
                stripped_run_opts = [i.strip() for i in runopts]
                if 'XCPL' in stripped_run_opts:
                    retrieve_Jij_files = True
        if retrieve_Jij_files:
            add_files = [self._SHELLS_DAT] + [
                self._Jij_ATOM % iatom for iatom in range(1, natom + 1)
            ]
            print('adding files for Jij output', add_files)
            calcinfo.retrieve_list += add_files

        codeinfo = CodeInfo()
        codeinfo.cmdline_params = []
        codeinfo.code_uuid = code.uuid
        codeinfo.stdout_name = self._DEFAULT_OUTPUT_FILE
        calcinfo.codes_info = [codeinfo]

        return calcinfo
Example #17
0
    def from_cp2k(cls, fhandle, filters=None, duplicate_handling="ignore"):
        """
        Constructs a list with basis set objects from a Basis Set in CP2K format

        :param fhandle: open file handle
        :param filters: a dict with attribute filter functions
        :param duplicate_handling: how to handle duplicates ("ignore", "error", "new" (version))
        :rtype: list
        """
        if not filters:
            filters = {}

        def matches_criteria(bset):
            return all(fspec(bset[field]) for field, fspec in filters.items())

        def exists(bset):
            try:
                cls.get(bset["element"], bset["name"], match_aliases=False)
            except NotExistent:
                return False

            return True

        bsets = [
            bs for bs in (_basissetdata2dict(bs)
                          for bs in BasisSetData.datafile_iter(fhandle))
            if matches_criteria(bs)
        ]

        if duplicate_handling == "ignore":  # simply filter duplicates
            bsets = [bs for bs in bsets if not exists(bs)]

        elif duplicate_handling == "error":
            for bset in bsets:
                try:
                    latest = cls.get(bset["element"],
                                     bset["name"],
                                     match_aliases=False)
                except NotExistent:
                    pass
                else:
                    raise UniquenessError(
                        f"Gaussian Basis Set already exists for"
                        f" element={bset['element']}, name={bset['name']}: {latest.uuid}"
                    )

        elif duplicate_handling == "new":
            for bset in bsets:
                try:
                    latest = cls.get(bset["element"],
                                     bset["name"],
                                     match_aliases=False)
                except NotExistent:
                    pass
                else:
                    bset["version"] = latest.version + 1

        else:
            raise ValueError(
                f"Specified duplicate handling strategy not recognized: '{duplicate_handling}'"
            )

        return [cls(**bs) for bs in bsets]
def neworder_potential_wf(settings_node, parent_calc_folder,
                          **kwargs):  #, parent_calc_folder2=None):
    """
    Workfunction to create database structure for aiida_kkr.tools.modify_potential.neworder_potential function
    A temporary file is written in a Sandbox folder on the computer specified via 
    the input computer node before the output potential is stored as SingleFileData 
    in the Database.
    
    :param settings_node: settings for the neworder_potentail function (ParameterData)
    :param parent_calc_folder: parent calculation remote folder node where the input 
        potential is retreived from (RemoteData)
    :param parent_calc_folder2: *optional*, parent calculation remote folder node where 
        the second input potential is retreived from in case 'pot2' and 'replace_newpos' 
        are also set in settings_node (RemoteData)
    
    :returns: output_potential node (SingleFileData) 
        
    .. note::
        
        The settings_node dictionary needs to be of the following form::
            
            settings_dict = {'pot1': '<filename_input_potential>',  'out_pot': '<filename_output_potential>', 'neworder': [list of intended order in output potential]} 
        
        Optional entries are::
            
            'pot2': '<filename_second_input_file>'
            'replace_newpos': [[position in neworder list which is replace with potential from pot2, position in pot2 that is chosen for replacement]]
            'label': 'label_for_output_node'
            'description': 'longer_description_for_output_node'
    """
    import os
    from aiida_kkr.tools.tools_kkrimp import modify_potential
    from aiida.common.folders import SandboxFolder
    from aiida.common.exceptions import UniquenessError
    from aiida.orm.calculation.job import JobCalculation
    from aiida.orm import DataFactory

    if 'parent_calc_folder2' in kwargs.keys():
        parent_calc_folder2 = kwargs.get('parent_calc_folder2', None)
    else:
        parent_calc_folder2 = None

    # get aiida data types used here
    ParameterData = DataFactory('parameter')
    RemoteData = DataFactory('remote')
    SingleFileData = DataFactory('singlefile')

    # check input consistency
    if not isinstance(settings_node, ParameterData):
        raise InputValidationError(
            'settings_node needs to be a valid aiida ParameterData node')
    if not isinstance(parent_calc_folder, RemoteData):
        raise InputValidationError(
            'parent_calc_folder needs to be a valid aiida RemoteData node')
    if parent_calc_folder2 is not None and not isinstance(
            parent_calc_folder2, RemoteData):
        raise InputValidationError(
            'parent_calc_folder2 needs to be a valid aiida RemoteData node')

    settings_dict = settings_node.get_dict()
    pot1 = settings_dict.get('pot1', None)
    if pot1 is None:
        raise InputValidationError(
            'settings_node_dict needs to have key "pot1" containing the filename of the input potential'
        )
    out_pot = settings_dict.get('out_pot', None)
    if out_pot is None:
        raise InputValidationError(
            'settings_node_dict needs to have key "out_pot" containing the filename of the input potential'
        )
    neworder = settings_dict.get('neworder', None)
    if neworder is None:
        raise InputValidationError(
            'settings_node_dict needs to have key "neworder" containing the list of new positions'
        )
    pot2 = settings_dict.get('pot2', None)
    replace_newpos = settings_dict.get('replace_newpos', None)

    # Create Sandbox folder for generation of output potential file
    # and construct output potential
    with SandboxFolder() as tempfolder:
        # Get abolute paths of input files from parent calc and filename
        parent_calcs = parent_calc_folder.get_inputs(node_type=JobCalculation)
        n_parents = len(parent_calcs)
        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[0]
        remote_path = parent_calc.out.retrieved.get_abs_path('')
        pot1_path = os.path.join(remote_path, pot1)

        # extract nspin from parent calc's input parameter node
        nspin = parent_calc.inp.parameters.get_dict().get('NSPIN')
        neworder_spin = []
        for iatom in neworder:
            for ispin in range(nspin):
                neworder_spin.append(iatom * nspin + ispin)
        neworder = neworder_spin

        # Copy optional files?
        if pot2 is not None and parent_calc_folder2 is not None:
            parent_calcs = parent_calc_folder2.get_inputs(
                node_type=JobCalculation)
            n_parents = len(parent_calcs)
            if n_parents != 1:
                raise UniquenessError(
                    "Input RemoteData of parent_calc_folder2 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[0]
            remote_path = parent_calc.out.retrieved.get_abs_path('')
            pot2_path = os.path.join(remote_path, pot2)
        else:
            pot2_path = None

        # change file path to Sandbox folder accordingly
        out_pot_path = tempfolder.get_abs_path(out_pot)

        # run neworder_potential function
        modify_potential().neworder_potential(pot1_path,
                                              out_pot_path,
                                              neworder,
                                              potfile_2=pot2_path,
                                              replace_from_pot2=replace_newpos)

        # store output potential to SingleFileData
        output_potential_sfd_node = SingleFileData(file=out_pot_path)

        lbl = settings_dict.get('label', None)
        if lbl is not None:
            output_potential_sfd_node.label = lbl
        desc = settings_dict.get('description', None)
        if desc is not None:
            output_potential_sfd_node.description = desc

        #TODO create shapefun sfd node accordingly
        """
        out_shape_path = 
        
        output_shapefun_sfd_node = SingleFileData(file=out_shape_path)
        
        lbl2 = settings_dict.get('label_shape', None)
        if lbl2 is None and lbl is not None:
            lbl2 = lbl
        if lbl2 is not None:
            output_shapefun_sfd_node.label = lbl2
        desc2 = settings_dict.get('description_shape', None)
        if desc2 is None and desc is not None:
            desc2 = desc
        if desc2 is not None:
            output_shapefun_sfd_node.description = desc2
        
        return output_potential_sfd_node, output_shapefun_sfd_node
        """
        return output_potential_sfd_node
Example #19
0
    def prepare_for_submission(self, folder):
        """
        This is the routine to be called when you make a FLEUR calculation.
        This routine checks the inputs and modifies copy lists accordingly.
        The standard files to be copied are given here.

        :param folder: a aiida.common.folders.Folder subclass where
                           the plugin should put all its files.
        """

        local_copy_list = []
        remote_copy_list = []
        remote_symlink_list = []
        mode_retrieved_filelist = []
        filelist_tocopy_remote = []
        settings_dict = {}

        has_fleurinp = False
        has_parent = False
        fleurinpgen = False
        copy_remotely = True
        with_hdf5 = False

        code = self.inputs.code

        codesdesc = code.description
        # TODO: ggf also check settings
        # In code description we write with what libs the code was compiled
        # we look for certain keywords in the description
        # also ggf, to be back comportable, the plugin should know the version number
        if codesdesc is not None:
            if 'hdf5' in codesdesc:
                with_hdf5 = True
            elif 'Hdf5' in codesdesc:
                with_hdf5 = True
            elif 'HDF5' in codesdesc:
                with_hdf5 = True
            else:
                with_hdf5 = False
        # a Fleur calc can be created from a fleurinpData alone
        # (then no parent is needed) all files are in the repo, but usually it is
        # a child of a inpgen calc or an other fleur calc (some or all files are
        # in a remote source). if the User has not changed something, the
        # calculation does not need theoretical a new FleurinpData it could use
        # the one from the parent, but the plug-in desgin is in a way that it has
        # to be there and it just copies files if changes occurred..

        if 'fleurinpdata' in self.inputs:
            fleurinp = self.inputs.fleurinpdata
        else:
            fleurinp = None

        if fleurinp is None:
            has_fleurinp = False
        else:
            has_fleurinp = True

        if 'parent_folder' in self.inputs:
            parent_calc_folder = self.inputs.parent_folder
        else:
            parent_calc_folder = None

        if parent_calc_folder is None:
            has_parent = False
            if not has_fleurinp:
                raise InputValidationError('No parent calculation found and no fleurinp data '
                                           'given, need either one or both for a '
                                           "'fleurcalculation'.")
        else:
            # extract parent calculation
            parent_calcs = parent_calc_folder.get_incoming(node_class=CalcJob).all()
            n_parents = len(parent_calcs)
            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'))
            parent_calc = parent_calcs[0].node
            parent_calc_class = parent_calc.process_class
            has_parent = True

            # check that it is a valid parent
            # self._check_valid_parent(parent_calc)

            # if inpgen calc do
            # check if folder from db given, or get folder from rep.
            # Parent calc does not has to be on the same computer.

            if parent_calc_class is FleurCalculation:
                new_comp = self.node.computer
                old_comp = parent_calc.computer
                if new_comp.uuid != old_comp.uuid:
                    # don't copy files, copy files locally
                    copy_remotely = False
            elif parent_calc_class is FleurinputgenCalculation:
                fleurinpgen = True
                new_comp = self.node.computer
                old_comp = parent_calc.computer
                if new_comp.uuid != old_comp.uuid:
                    # don't copy files, copy files locally
                    copy_remotely = False
            else:
                raise InputValidationError("parent_calc, must be either an 'inpgen calculation' or"
                                           " a 'fleur calculation'.")

        # check existence of settings (optional)
        if 'settings' in self.inputs:
            settings = self.inputs.settings
        else:
            settings = None

        if settings is None:
            settings_dict = {}
        else:
            settings_dict = settings.get_dict()

        # check for for allowed keys, ignore unknown keys but warn.
        for key in settings_dict.keys():
            if key not in self._settings_keys:
                self.logger.warning(
                    'settings dict key %s for Fleur calculation'
                    'not recognized, only %s are allowed.'
                    '', key, str(self._settings_keys))

        # TODO: Detailed check of FleurinpData
        # if certain files are there in fleurinpData
        # from where to copy

        # file copy stuff TODO check in fleur input
        if has_fleurinp:
            # add files belonging to fleurinp into local_copy_list
            allfiles = fleurinp.files
            for file1 in allfiles:
                local_copy_list.append((fleurinp.uuid, file1, file1))
            modes = fleurinp.get_fleur_modes()

            # add files to mode_retrieved_filelist
            if modes['band']:
                mode_retrieved_filelist.append(self._BAND_FILE_NAME)
                mode_retrieved_filelist.append(self._BAND_GNU_FILE_NAME)
            if modes['dos']:
                mode_retrieved_filelist.append(self._DOS_FILE_NAME)
            if modes['forces']:
                # if l_f="T" retrieve relax.xml
                mode_retrieved_filelist.append(self._RELAX_FILE_NAME)
            if modes['ldau']:
                if with_hdf5:
                    mode_retrieved_filelist.append(self._NMMPMAT_HDF5_FILE_NAME)
                else:
                    mode_retrieved_filelist.append(self._NMMPMAT_FILE_NAME)
            if modes['force_theorem']:
                if 'remove_from_retrieve_list' not in settings_dict:
                    settings_dict['remove_from_retrieve_list'] = []
                if with_hdf5:
                    settings_dict['remove_from_retrieve_list'].append(self._CDN_LAST_HDF5_FILE_NAME)
                else:
                    settings_dict['remove_from_retrieve_list'].append(self._CDN1_FILE_NAME)

            # if noco, ldau, gw...
            # TODO: check from where it was copied, and copy files of its parent
            # if needed

        if has_parent:
            # copy necessary files
            # TODO: check first if file exist and throw a warning if not
            outfolder_uuid = parent_calc.outputs.retrieved.uuid
            self.logger.info('out folder path %s', outfolder_uuid)

            outfolder_filenames = [x.name for x in parent_calc.outputs.retrieved.list_objects()]
            has_nmmpmat_file = self._NMMPMAT_FILE_NAME in outfolder_filenames
            if (self._NMMPMAT_FILE_NAME in outfolder_filenames or \
                self._NMMPMAT_HDF5_FILE_NAME in outfolder_filenames):
                if has_fleurinp:
                    if 'n_mmp_mat' in fleurinp.files:
                        self.logger.warning('Ingnoring n_mmp_mat from fleurinp. '
                                            'There is already an n_mmp_mat file '
                                            'for the parent calculation')
                        local_copy_list.remove((fleurinp.uuid, 'n_mmp_mat', 'n_mmp_mat'))

            if fleurinpgen and (not has_fleurinp):
                for file1 in self._copy_filelist_inpgen:
                    local_copy_list.append((outfolder_uuid, os.path.join(file1), os.path.join(file1)))
            elif not fleurinpgen and (not has_fleurinp):  # fleurCalc
                # need to copy inp.xml from the parent calc
                if with_hdf5:
                    copylist = self._copy_scf_hdf
                elif has_nmmpmat_file:
                    copylist = self._copy_scf_ldau_nohdf
                else:
                    copylist = self._copy_scf
                for file1 in copylist:
                    local_copy_list.append((outfolder_uuid, file1[0], file1[1]))
                # TODO: get inp.xml from parent fleurinpdata; otherwise it will be doubled in rep
            elif fleurinpgen and has_fleurinp:
                # everything is taken care of
                pass
            elif not fleurinpgen and has_fleurinp:
                # inp.xml will be copied from fleurinp
                if with_hdf5:
                    copylist = self._copy_scf_noinp_hdf
                elif has_nmmpmat_file:
                    copylist = self._copy_scf_ldau_noinp_nohdf
                else:
                    copylist = self._copy_scf_noinp
                for file1 in copylist:
                    local_copy_list.append((outfolder_uuid, file1[0], file1[1]))

            # TODO: not on same computer -> copy needed files from repository
            # if they are not there throw an error
            if copy_remotely:  # on same computer.
                # from fleurmodes
                if modes['dos']:
                    pass
                elif modes['band']:
                    pass
                else:
                    filelist_tocopy_remote = filelist_tocopy_remote + \
                        self._copy_filelist_scf_remote
                # from settings, user specified
                # TODO: check if list?
                for file1 in settings_dict.get('additional_remotecopy_list', []):
                    filelist_tocopy_remote.append(file1)

                for file1 in settings_dict.get('remove_from_remotecopy_list', []):
                    if file1 in filelist_tocopy_remote:
                        filelist_tocopy_remote.remove(file1)

                for file1 in filelist_tocopy_remote:
                    remote_copy_list.append(
                        (parent_calc_folder.computer.uuid, os.path.join(parent_calc_folder.get_remote_path(),
                                                                        file1), self._get_output_folder))

                self.logger.info('remote copy file list %s', str(remote_copy_list))

        # create a JUDFT_WARN_ONLY file in the calculation folder
        with io.StringIO(u'/n') as handle:
            warn_only_filename = self._JUDFT_WARN_ONLY_INFO_FILE_NAME
            folder.create_file_from_filelike(handle, filename=warn_only_filename, mode='w')

        ########## MAKE CALCINFO ###########

        calcinfo = CalcInfo()

        calcinfo.uuid = self.uuid
        # Empty command line by default
        #cmdline_params = settings_dict.pop('CMDLINE', [])
        # calcinfo.cmdline_params = (list(cmdline_params)
        #                           + ["-in", self._INPUT_FILE_NAME])

        self.logger.info('local copy file list %s', str(local_copy_list))

        calcinfo.local_copy_list = local_copy_list
        calcinfo.remote_copy_list = remote_copy_list
        calcinfo.remote_symlink_list = remote_symlink_list

        # Retrieve by default the output file and the xml file
        retrieve_list = []
        retrieve_list.append(self._OUTXML_FILE_NAME)
        retrieve_list.append(self._INPXML_FILE_NAME)
        retrieve_list.append(self._SHELLOUTPUT_FILE_NAME)
        retrieve_list.append(self._ERROR_FILE_NAME)
        retrieve_list.append(self._USAGE_FILE_NAME)
        # retrieve_list.append(self._TIME_INFO_FILE_NAME)
        # retrieve_list.append(self._OUT_FILE_NAME)
        if with_hdf5:
            retrieve_list.append(self._CDN_LAST_HDF5_FILE_NAME)
        else:
            retrieve_list.append(self._CDN1_FILE_NAME)

        for mode_file in mode_retrieved_filelist:
            retrieve_list.append(mode_file)
        self.logger.info('retrieve_list: %s', str(retrieve_list))

        # user specific retrieve
        add_retrieve = settings_dict.get('additional_retrieve_list', [])
        self.logger.info('add_retrieve: %s', str(add_retrieve))
        for file1 in add_retrieve:
            retrieve_list.append(file1)

        remove_retrieve = settings_dict.get('remove_from_retrieve_list', [])
        for file1 in remove_retrieve:
            if file1 in retrieve_list:
                retrieve_list.remove(file1)

        calcinfo.retrieve_list = []
        for file1 in retrieve_list:
            calcinfo.retrieve_list.append(file1)

        codeinfo = CodeInfo()
        # should look like: codepath -xmlInput < inp.xml > shell.out 2>&1
        walltime_sec = self.node.get_attribute('max_wallclock_seconds')
        cmdline_params = []  # , "-wtime", "{}".format(walltime_sec)]"-xml"

        cmdline_params.append('-minimalOutput')

        if with_hdf5:
            cmdline_params.append('-last_extra')
            cmdline_params.append('-no_send')

        if walltime_sec:
            walltime_min = int(max(1, walltime_sec / 60))
            cmdline_params.append('-wtime')
            cmdline_params.append('{}'.format(int(walltime_min)))

        # user specific commandline_options
        for command in settings_dict.get('cmdline', []):
            cmdline_params.append(command)

        codeinfo.cmdline_params = list(cmdline_params)
        # + ["<", self._INPXML_FILE_NAME,
        # ">", self._SHELLOUTPUT_FILE_NAME, "2>&1"]
        codeinfo.code_uuid = code.uuid
        codeinfo.withmpi = self.node.get_attribute('max_wallclock_seconds')
        codeinfo.stdin_name = None  # self._INPUT_FILE_NAME
        codeinfo.stdout_name = self._SHELLOUTPUT_FILE_NAME
        #codeinfo.join_files = True
        codeinfo.stderr_name = self._ERROR_FILE_NAME

        calcinfo.codes_info = [codeinfo]

        return calcinfo
Example #20
0
    def from_cp2k(cls,
                  fhandle,
                  filters=None,
                  duplicate_handling="ignore",
                  ignore_invalid=False):
        """
        Constructs a list with pseudopotential objects from a Pseudopotential in CP2K format

        :param fhandle: open file handle
        :param filters: a dict with attribute filter functions
        :param duplicate_handling: how to handle duplicates ("ignore", "error", "new" (version))
        :param ignore_invalid: whether to ignore invalid entries silently
        :rtype: list
        """
        from cp2k_input_tools.pseudopotentials import PseudopotentialData

        if not filters:
            filters = {}

        def matches_criteria(pseudo):
            return all(
                fspec(pseudo[field]) for field, fspec in filters.items())

        def exists(pseudo):
            try:
                cls.get(pseudo["element"], pseudo["name"], match_aliases=False)
            except NotExistent:
                return False

            return True

        pseudos = [
            p for p in (_pseudodata2dict(p)
                        for p in PseudopotentialData.datafile_iter(
                            fhandle, keep_going=ignore_invalid))
            if matches_criteria(p)
        ]

        if duplicate_handling == "ignore":  # simply filter duplicates
            pseudos = [p for p in pseudos if not exists(p)]

        elif duplicate_handling == "error":
            for pseudo in pseudos:
                try:
                    latest = cls.get(pseudo["element"],
                                     pseudo["name"],
                                     match_aliases=False)
                except NotExistent:
                    pass
                else:
                    raise UniquenessError(
                        f"Gaussian Pseudopotential already exists for"
                        f" element={pseudo['element']}, name={pseudo['name']}: {latest.uuid}"
                    )

        elif duplicate_handling == "new":
            for pseudo in pseudos:
                try:
                    latest = cls.get(pseudo["element"],
                                     pseudo["name"],
                                     match_aliases=False)
                except NotExistent:
                    pass
                else:
                    pseudo["version"] = latest.version + 1

        else:
            raise ValueError(
                f"Specified duplicate handling strategy not recognized: '{duplicate_handling}'"
            )

        return [cls(**p) for p in pseudos]
def upload_psml_family(folder,
                       group_label,
                       group_description,
                       stop_if_existing=True):
    """
    Upload a set of PSML files in a given group.

    :param folder: a path containing all PSML files to be added.
        Only files ending in .psml (case sensitive) are considered.
    :param group_label: the name of the group to create. If it exists and is
        non-empty, a UniquenessError is raised.
    :param group_description: a string to be set as the group description.
        Overwrites previous descriptions, if the group was existing.
    :param stop_if_existing: if True, check for the md5 of the files and,
        if the file already exists in the DB, raises a MultipleObjectsError.
        If False, simply adds the existing PsmlData node to the group.
    """
    import os
    from aiida import orm
    from aiida.common import AIIDA_LOGGER as aiidalogger
    from aiida.common.exceptions import UniquenessError
    from aiida.orm.querybuilder import QueryBuilder
    from aiida_siesta.groups.pseudos import PsmlFamily

    message = (  #pylint: disable=invalid-name
        'This function has been deprecated and will be removed in `v2.0.0`. ' +
        '`upload_psml_family` is substitued by `fam.create_from_folder` ' +
        'where `fam` is an instance of the families classes in `aiida_pseudo.groups.family`.'
    )

    warnings.warn(message, AiidaSiestaDeprecationWarning)

    if not os.path.isdir(folder):
        raise ValueError("folder must be a directory")

    # only files, and only those ending with .psml;
    # go to the real file if it is a symlink
    files = [
        os.path.realpath(os.path.join(folder, i)) for i in os.listdir(folder)
        if os.path.isfile(os.path.join(folder, i)) and i.endswith('.psml')
    ]

    nfiles = len(files)

    automatic_user = orm.User.objects.get_default()
    #group, group_created = orm.Group.objects.get_or_create(
    #    label=group_label, type_string=PSMLGROUP_TYPE, user=automatic_user
    #)
    group, group_created = PsmlFamily.objects.get_or_create(
        label=group_label, user=automatic_user)

    if group.user.email != automatic_user.email:
        raise UniquenessError(
            "There is already a PsmlFamily group with name {}"
            ", but it belongs to user {}, therefore you "
            "cannot modify it".format(group_label, group.user.email))

    # Always update description, even if the group already existed
    group.description = group_description

    # NOTE: GROUP SAVED ONLY AFTER CHECKS OF UNICITY

    pseudo_and_created = []

    for afile in files:
        md5sum = md5_file(afile)
        qb = QueryBuilder()
        qb.append(PsmlData, filters={'attributes.md5': {'==': md5sum}})
        existing_psml = qb.first()

        #existing_psml = PsmlData.query(dbattributes__key="md5",
        #                            dbattributes__tval = md5sum)

        if existing_psml is None:
            # return the psmldata instances, not stored
            pseudo, created = PsmlData.get_or_create(afile,
                                                     use_first=True,
                                                     store_psml=False)
            # to check whether only one psml per element exists
            # NOTE: actually, created has the meaning of "to_be_created"
            pseudo_and_created.append((pseudo, created))
        else:
            if stop_if_existing:
                raise ValueError("A PSML with identical MD5 to "
                                 " {} cannot be added with stop_if_existing"
                                 "".format(afile))
            existing_psml = existing_psml[0]
            pseudo_and_created.append((existing_psml, False))

    # check whether pseudo are unique per element
    elements = [(i[0].element, i[0].md5sum) for i in pseudo_and_created]
    # If group already exists, check also that I am not inserting more than
    # once the same element
    if not group_created:
        for aiida_n in group.nodes:
            # Skip non-pseudos
            if not isinstance(aiida_n, PsmlData):
                continue
            elements.append((aiida_n.element, aiida_n.md5sum))

    elements = set(elements)  # Discard elements with the same MD5, that would
    # not be stored twice
    elements_names = [e[0] for e in elements]

    if not len(elements_names) == len(set(elements_names)):
        duplicates = {x for x in elements_names if elements_names.count(x) > 1}
        duplicates_string = ", ".join(i for i in duplicates)
        raise UniquenessError("More than one PSML found for the elements: " +
                              duplicates_string + ".")

    # At this point, save the group, if still unstored
    if group_created:
        group.store()

    # save the psml in the database, and add them to group
    for pseudo, created in pseudo_and_created:
        if created:
            pseudo.store()

            aiidalogger.debug("New node {} created for file {}".format(
                pseudo.uuid, pseudo.filename))
        else:
            aiidalogger.debug("Reusing node {} for file {}".format(
                pseudo.uuid, pseudo.filename))

    # Add elements to the group all togetehr
    group.add_nodes([pseudo for pseudo, created in pseudo_and_created])

    nuploaded = len([_ for _, created in pseudo_and_created if created])

    return nfiles, nuploaded
Example #22
0
 def _get_and_verify_hostfiles(self, inputdict):
     """
     Check inputdict for host_Greenfunction_folder and extract impurity_info, paths to kkrflex-files and path of shapefun file
     
     :param inputdict: input dictionary containing all input nodes to KkrimpCalculation
     :returns: 
         * imp_info: ParameterData node containing impurity information like position, Z_imp, cluster size, etc.
         * kkrflex_file_paths: dict of absolute file paths for the kkrflex files
         * shapefun_path: absolute path of the shapefunction file in the host calculation (needed to construct shapefun_imp)
         * shapes: mapping array of atoms to shapes (<SHAPE> input)
     :note: shapefun_path is None if host_Greenfunction calculation was not full-potential
     :raises: 
         * InputValidationError, if inputdict does not contain 'host_Greenfunction'
         * InputValidationError, if host_Greenfunction_folder not of right type
         * UniquenessError, if host_Greenfunction_folder does not have exactly one parent
         * InputValidationError, if host_Greenfunction does not have an input node impurity_info
         * InputValidationError, if host_Greenfunction was not a KKRFLEX calculation
     """
     # get host_parent node and check consistency
     try:
         host_parent = inputdict.pop(self.get_linkname('host_Greenfunction_folder'))
     except KeyError:
         raise InputValidationError("No host_Greenfunction_folder specified for this calculation")
     # check host parent type
     if not isinstance(host_parent, RemoteData):
         raise InputValidationError("host_Greenfunction_folder not of type RemoteData")
     # extract parent calculation
     parent_calcs = host_parent.get_inputs(node_type=JobCalculation)
     n_parents = len(parent_calcs)
     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[0]
         
     # extract impurity_info
     imp_info = parent_calc.get_inputs_dict().get('impurity_info', None)
     if imp_info is None:
         raise InputValidationError("host_Greenfunction calculation does not have an input node impurity_info")
         
     # check if host parent was KKRFLEX calculation
     hostfolderpath = parent_calc.out.retrieved.folder.abspath
     hostfolderpath = os.path.join(hostfolderpath, 'path')
     input_file = os.path.join(hostfolderpath, KkrCalculation()._DEFAULT_INPUT_FILE)
     params_host_calc = kkrparams(params_type='kkr') # initialize kkrparams instance to use read_keywords_from_inputcard
     params_host_calc.read_keywords_from_inputcard(inputcard=input_file)
     
     if 'RUNOPT' not in params_host_calc.get_dict().keys():
         host_ok = False
     elif 'KKRFLEX' not in params_host_calc.get_dict().get('RUNOPT', []):
         host_ok = False
     else:
         host_ok = True
         
     if not host_ok:
         raise InputValidationError("host_Greenfunction calculation was not a KKRFLEX run")
     
     # extract absolute paths of kkrflex_* files
     kkrflex_file_paths = {}
     for file in self._ALL_KKRFLEX_FILES:
         file_abspath = os.path.join(hostfolderpath, file)
         if os.path.exists(file_abspath):
             kkrflex_file_paths[file] = file_abspath
             
     # extract absolute path of host shapefun
     file_abspath = os.path.join(hostfolderpath, KkrCalculation()._SHAPEFUN)
     if os.path.exists(file_abspath):
         shapefun_path = file_abspath
     else:
         shapefun_path = None
         
     # extract shapes array from parameters read from inputcard
     shapes = params_host_calc.get_dict().get('<SHAPE>', None)
     if type(shapes)==int:
         shapes = [shapes]
         
     # extract input structure
     try:
         structure, voro_parent = VoronoiCalculation.find_parent_structure(parent_calc)
     except:
         structure, voro_parent = None, None
     if structure is None:
         raiseInputValidationError("No structure node found from host GF parent")
         
     return imp_info, kkrflex_file_paths, shapefun_path, shapes, parent_calc, params_host_calc, structure
Example #23
0
    def _prepare_for_submission(self,tempfolder,inputdict):        
        """
        This is the routine to be called when you want to create
        the input files and related stuff with a plugin.
        
        :param tempfolder: a aiida.common.folders.Folder subclass where
                           the plugin should put all its files.
        :param inputdict: a dictionary with the input nodes, as they would
                be returned by get_inputdata_dict (without the Code!)
        """
        try:
            code = inputdict.pop(self.get_linkname('code'))
        except KeyError:
            raise InputValidationError("No code specified for this calculation")

        local_copy_list = []
        remote_copy_list = []
        remote_symlink_list = []
        
        try:
            parameters = inputdict.pop(self.get_linkname('parameters'))
        except KeyError:
            raise InputValidationError("No parameters specified for this calculation")
        if not isinstance(parameters, ParameterData):
            raise InputValidationError("parameters is not of type ParameterData")
        
        try:
            qpoints = inputdict.pop(self.get_linkname('qpoints'))
        except KeyError:
            raise InputValidationError("No qpoints specified for this calculation")
        if not isinstance(qpoints, KpointsData):
            raise InputValidationError("qpoints is not of type KpointsData")

        # Settings can be undefined, and defaults to an empty dictionary.
        # They will be used for any input that doen't fit elsewhere.
        settings = inputdict.pop(self.get_linkname('settings'),None)
        if settings is None:
            settings_dict = {}
        else:
            if not isinstance(settings,  ParameterData):
                raise InputValidationError("settings, if specified, must be of "
                                           "type ParameterData")
            # Settings converted to uppercase
            settings_dict = _uppercase_dict(settings.get_dict(),
                                            dict_name='settings')

        parent_calc_folder = inputdict.pop(self.get_linkname('parent_folder'),None)
        if parent_calc_folder is None:
            raise InputValidationError("No parent calculation found, needed to "
                                       "compute phonons")
        # TODO: to be a PwCalculation is not sufficient: it could also be a nscf
        # calculation that is invalid for phonons
        
        if not isinstance(parent_calc_folder, RemoteData):
            raise InputValidationError("parent_calc_folder, if specified,"
                                       "must be of type RemoteData")

        restart_flag = False
        # extract parent calculation
        parent_calcs = parent_calc_folder.get_inputs(node_type=JobCalculation)
        n_parents = len(parent_calcs)
        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"))
        parent_calc = parent_calcs[0]
        # check that it is a valid parent
        self._check_valid_parent(parent_calc)
        
        if not isinstance(parent_calc, PwCalculation):
            restart_flag = True

        # Also, the parent calculation must be on the same computer
        new_comp = self.get_computer()
        old_comp = parent_calc.get_computer()
        if ( not new_comp.uuid == old_comp.uuid ):
            raise InputValidationError("PhCalculation must be launched on the same computer"
                          " of the parent: {}".format(old_comp.get_name()))

        # put by default, default_parent_output_folder = ./out
        try:
            default_parent_output_folder = parent_calc._OUTPUT_SUBFOLDER
        except AttributeError:
            try:
                default_parent_output_folder = parent_calc._get_output_folder()
            except AttributeError:
                raise InputValidationError("Parent of PhCalculation  does not "
                                           "have a default output subfolder")
        #os.path.join(
        #                   parent_calc.OUTPUT_SUBFOLDER, 
        #                  '{}.save'.format(parent_calc.PREFIX))
        parent_calc_out_subfolder = settings_dict.pop('PARENT_CALC_OUT_SUBFOLDER',
                                                      default_parent_output_folder)      

        # Here, there should be no other inputs
        if inputdict:
            raise InputValidationError("The following input data nodes are "
                "unrecognized: {}".format(inputdict.keys()))

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

        # I put the first-level keys as uppercase (i.e., namelist and card names)
        # and the second-level keys as lowercase
        # (deeper levels are unchanged)
        input_params = _uppercase_dict(parameters.get_dict(),
                                       dict_name='parameters')
        input_params = {k: _lowercase_dict(v, dict_name=k) 
                        for k, v in input_params.iteritems()}

        prepare_for_d3 = settings_dict.pop('PREPARE_FOR_D3',False)
        if prepare_for_d3:
            self._blocked_keywords += [('INPUTPH', 'fildrho'),
                                       ('INPUTPH', 'drho_star%open'),
                                       ('INPUTPH', 'drho_star%ext'),
                                       ('INPUTPH', 'drho_star%dir')]
        
        # I remove unwanted elements (for the moment, instead, I stop; to change when
        # we setup a reasonable logging)
        for nl, flag in self._blocked_keywords:
            if nl in input_params:
                if flag in input_params[nl]:
                    raise InputValidationError(
                        "You cannot specify explicitly the '{}' flag in the '{}' "
                        "namelist or card.".format(flag, nl))
        
        # Set some variables (look out at the case! NAMELISTS should be uppercase,
        # internal flag names must be lowercase)
        if 'INPUTPH' not in input_params:
            raise InputValidationError("No namelist INPUTPH found in input") # I cannot decide what to do in the calculation
        input_params['INPUTPH']['outdir'] = self._OUTPUT_SUBFOLDER
        input_params['INPUTPH']['iverbosity'] = 1 # in human language 1=high
        input_params['INPUTPH']['prefix'] = self._PREFIX
        input_params['INPUTPH']['fildyn'] = self._OUTPUT_DYNAMICAL_MATRIX_PREFIX
        if prepare_for_d3:
            input_params['INPUTPH']['fildrho'] = self._DRHO_PREFIX
            input_params['INPUTPH']['drho_star%open'] = True
            input_params['INPUTPH']['drho_star%ext'] = self._DRHO_STAR_EXT
            input_params['INPUTPH']['drho_star%dir'] = self._FOLDER_DRHO
        
        # qpoints part
        try:
            mesh,offset = qpoints.get_kpoints_mesh()
            
            if any([i!=0. for i in offset]):
                raise NotImplementedError("Computation of phonons on a mesh with"
                    " non zero offset is not implemented, at the level of ph.x")
            
            input_params["INPUTPH"]["ldisp"] = True
            input_params["INPUTPH"]["nq1"] = mesh[0]
            input_params["INPUTPH"]["nq2"] = mesh[1]
            input_params["INPUTPH"]["nq3"] = mesh[2]
            
            postpend_text = None
            
        except AttributeError:
            # this is the case where no mesh was set. Maybe it's a list
            try:
                list_of_points = qpoints.get_kpoints(cartesian=True)
            except AttributeError as e:
                # In this case, there are no info on the qpoints at all
                raise InputValidationError("Neither a qpoints mesh or a valid "
                                           "list of qpoints was found in input",
                                           e.message)
            # change to 2pi/a coordinates
            lattice_parameter = numpy.linalg.norm(qpoints.cell[0])
            list_of_points *= lattice_parameter / (2.*numpy.pi)
            # add here the list of point coordinates            
            if len(list_of_points)>1:
                input_params["INPUTPH"]["qplot"] = True
                input_params["INPUTPH"]["ldisp"] = True
                postpend_text = "{}\n".format(len(list_of_points))
                for points in list_of_points:
                    postpend_text += "{}  {}  {}  1\n".format(*points)
                # Note: the weight is fixed to 1, because ph.x calls these 
                # things weights but they are not such. If they are going to 
                # exist with the meaning of weights, they will be supported
            else:
                input_params["INPUTPH"]["ldisp"] = False
                postpend_text = ""
                for points in list_of_points:
                    postpend_text += "{}  {}  {}\n".format(*points)
            
        
        # =================== NAMELISTS ========================
        
        # customized namelists, otherwise not present in the distributed ph code
        try:
            namelists_toprint = settings_dict.pop('NAMELISTS')
            if not isinstance(namelists_toprint, list):
                raise InputValidationError(
                    "The 'NAMELISTS' value, if specified in the settings input "
                    "node, must be a list of strings")
        except KeyError: # list of namelists not specified in the settings; do automatic detection
            namelists_toprint = self._compulsory_namelists
        
        input_filename = tempfolder.get_abs_path(self._INPUT_FILE_NAME)

        # create a folder for the dynamical matrices
        if not restart_flag: # if it is a restart, it will be copied over
            tempfolder.get_subfolder(self._FOLDER_DYNAMICAL_MATRIX,
                                     create=True)
        
        with open(input_filename,'w') as infile:
            infile.write('AiiDA calculation\n')
            for namelist_name in namelists_toprint:
                infile.write("&{0}\n".format(namelist_name))
                # namelist content; set to {} if not present, so that we leave an 
                # empty namelist
                namelist = input_params.pop(namelist_name,{})
                for k, v in sorted(namelist.iteritems()):
                    infile.write(get_input_data_text(k,v))
                infile.write("/\n")
            
            # add list of qpoints if required
            if postpend_text is not None:
                infile.write(postpend_text)
            
            #TODO: write nat_todo
            
        if input_params:
            raise InputValidationError(
                "The following namelists are specified in input_params, but are "
                "not valid namelists for the current type of calculation: "
                "{}".format(",".join(input_params.keys())))
        
        # copy the parent scratch
        symlink = settings_dict.pop('PARENT_FOLDER_SYMLINK',
                                    _default_symlink_usage) # a boolean
        if symlink:
            # I create a symlink to each file/folder in the parent ./out
            tempfolder.get_subfolder(self._OUTPUT_SUBFOLDER, create=True)
            
            remote_symlink_list.append( (parent_calc_folder.get_computer().uuid,
                                         os.path.join(parent_calc_folder.get_remote_path(),
                                                      parent_calc_out_subfolder,
                                                      "*"),
                                         self._OUTPUT_SUBFOLDER
                                         ) )
            
            # I also create a symlink for the ./pseudo folder
            # TODO: suppress this when the recover option of QE will be fixed 
            # (bug when trying to find pseudo file) 
            remote_symlink_list.append((parent_calc_folder.get_computer().uuid,
                                        os.path.join(parent_calc_folder.get_remote_path(),
                                                     self._get_pseudo_folder()),
                                        self._get_pseudo_folder()
                                        ))
            #pass
        else:
            # here I copy the whole folder ./out
            remote_copy_list.append(
                (parent_calc_folder.get_computer().uuid,
                 os.path.join(parent_calc_folder.get_remote_path(),
                              parent_calc_out_subfolder),
                 self._OUTPUT_SUBFOLDER))
            # I also copy the ./pseudo folder
            # TODO: suppress this when the recover option of QE will be fixed 
            # (bug when trying to find pseudo file) 
            remote_copy_list.append(
                (parent_calc_folder.get_computer().uuid,
                 os.path.join(parent_calc_folder.get_remote_path(),
                              self._get_pseudo_folder()),
                        self._get_pseudo_folder()))
            
        
        if restart_flag: # in this case, copy in addition also the dynamical matrices
            if symlink:
                remote_symlink_list.append(
                    (parent_calc_folder.get_computer().uuid,
                     os.path.join(parent_calc_folder.get_remote_path(),
                              self._FOLDER_DYNAMICAL_MATRIX),
                     self._FOLDER_DYNAMICAL_MATRIX))

            else:
                # copy the dynamical matrices
                remote_copy_list.append(
                    (parent_calc_folder.get_computer().uuid,
                     os.path.join(parent_calc_folder.get_remote_path(),
                              self._FOLDER_DYNAMICAL_MATRIX),
                     '.'))
                # no need to copy the _ph0, since I copied already the whole ./out folder
        
        # here we may create an aiida.EXIT file
        create_exit_file = settings_dict.pop('ONLY_INITIALIZATION',False)
        if create_exit_file:
            exit_filename = tempfolder.get_abs_path(
                             '{}.EXIT'.format(self._PREFIX))
            with open(exit_filename,'w') as f:
                f.write('\n')

        calcinfo = CalcInfo()
        
        calcinfo.uuid = self.uuid
        # Empty command line by default
        cmdline_params = settings_dict.pop('CMDLINE', [])
        
        calcinfo.local_copy_list = local_copy_list
        calcinfo.remote_copy_list = remote_copy_list
        calcinfo.remote_symlink_list = remote_symlink_list
        
        codeinfo = CodeInfo()
        codeinfo.cmdline_params = (list(cmdline_params)
                                   + ["-in", self._INPUT_FILE_NAME])
        codeinfo.stdout_name = self._OUTPUT_FILE_NAME
        codeinfo.code_uuid = code.uuid
        calcinfo.codes_info = [codeinfo]
        
        # Retrieve by default the output file and the xml file
        calcinfo.retrieve_list = []
        calcinfo.retrieve_list.append(self._OUTPUT_FILE_NAME)
        calcinfo.retrieve_list.append(self._FOLDER_DYNAMICAL_MATRIX)
        calcinfo.retrieve_list.append(  
                os.path.join(self._OUTPUT_SUBFOLDER,
                             '_ph0',
                             '{}.phsave'.format(self._PREFIX),
                             self._OUTPUT_XML_TENSOR_FILE_NAME))
        
        extra_retrieved = settings_dict.pop('ADDITIONAL_RETRIEVE_LIST', [])
        for extra in extra_retrieved:
            calcinfo.retrieve_list.append( extra )
        
        if settings_dict:
            raise InputValidationError("The following keys have been found in "
                "the settings input node, but were not understood: {}".format(
                ",".join(settings_dict.keys())))
        
        return calcinfo
Example #24
0
    def upload_basisset_family(cls,
                               folder,
                               group_name,
                               group_description,
                               stop_if_existing=True,
                               extension=".basis",
                               dry_run=False):
        """
        Upload a set of Basis Set files in a given group.

        :param folder: a path containing all Basis Set files to be added.
            Only files ending in the set extension (case-insensitive) are considered.
        :param group_name: the name of the group to create. If it exists and is
            non-empty, a UniquenessError is raised.
        :param group_description: a string to be set as the group description.
            Overwrites previous descriptions, if the group was existing.
        :param stop_if_existing: if True, check for the md5 of the files and,
            if the file already exists in the DB, raises a MultipleObjectsError.
            If False, simply adds the existing BasisSetData node to the group.
        :param extension: the filename extension to look for
        :param dry_run: If True, do not change the database.
        """
        from aiida.common import aiidalogger
        from aiida.orm import Group
        from aiida.common.exceptions import UniquenessError, NotExistent
        from aiida_crystal17.aiida_compatability import get_automatic_user

        automatic_user = get_automatic_user()

        if not os.path.isdir(folder):
            raise ValueError("folder must be a directory")

        # only files, and only those ending with specified exension;
        # go to the real file if it is a symlink
        files = [
            os.path.realpath(os.path.join(folder, i))
            for i in os.listdir(folder)
            if os.path.isfile(os.path.join(folder, i))
            and i.lower().endswith(extension)
        ]

        nfiles = len(files)

        try:
            group = Group.get(name=group_name, type_string=BASISGROUP_TYPE)
            group_created = False
        except NotExistent:
            group = Group(name=group_name,
                          type_string=BASISGROUP_TYPE,
                          user=automatic_user)
            group_created = True

        if group.user.email != automatic_user.email:
            raise UniquenessError(
                "There is already a BasisFamily group with name {}"
                ", but it belongs to user {}, therefore you "
                "cannot modify it".format(group_name, group.user.email))

        # Always update description, even if the group already existed
        group.description = group_description

        # NOTE: GROUP SAVED ONLY AFTER CHECKS OF UNICITY

        basis_and_created = _retrieve_basis_sets(files, stop_if_existing)
        # check whether basisset are unique per element
        elements = [(i[0].element, i[0].md5sum) for i in basis_and_created]
        # If group already exists, check also that I am not inserting more than
        # once the same element
        if not group_created:
            for aiida_n in group.nodes:
                # Skip non-basis sets
                if not isinstance(aiida_n, BasisSetData):
                    continue
                elements.append((aiida_n.element, aiida_n.md5sum))

        elements = set(
            elements)  # Discard elements with the same MD5, that would
        # not be stored twice
        elements_names = [e[0] for e in elements]

        if not len(elements_names) == len(set(elements_names)):
            duplicates = set(
                [x for x in elements_names if elements_names.count(x) > 1])
            duplicates_string = ", ".join(i for i in duplicates)
            raise UniquenessError(
                "More than one Basis found for the elements: " +
                duplicates_string + ".")

        # At this point, save the group, if still unstored
        if group_created and not dry_run:
            group.store()

        # save the basis set in the database, and add them to group
        for basisset, created in basis_and_created:
            if created:
                if not dry_run:
                    basisset.store()

                aiidalogger.debug("New node {0} created for file {1}".format(  # pylint: disable=logging-format-interpolation
                    basisset.uuid, basisset.filename))
            else:
                aiidalogger.debug("Reusing node {0} for file {1}".format(  # pylint: disable=logging-format-interpolation
                    basisset.uuid, basisset.filename))

        # Add elements to the group all together
        if not dry_run:
            group.add_nodes(basis for basis, created in basis_and_created)

        nuploaded = len([_ for _, created in basis_and_created if created])

        return nfiles, nuploaded
Example #25
0
    def _prepare_for_submission(self, tempfolder, inputdict):
        """
        This is the routine to be called when you make a fleur calculation
        Here should be checked if all the files are there to run fleur.
        And input files (inp.xml) can be modified.

        :param tempfolder: a aiida.common.folders.Folder subclass where
                           the plugin should put all its files.
        :param inputdict: a dictionary with the input nodes, as they would
                be returned by get_inputdata_dict (without the Code!)
        """

        #   from aiida.common.utils import get_unique_filename, get_suggestion

        local_copy_list = []
        remote_copy_list = []
        remote_symlink_list = []
        mode_retrieved_filelist = []
        #filelocal_copy_list = []
        #filelist_tocopy = []
        filelist_tocopy_remote = []
        settings_dict = {}

        #fleur_calc = False
        #new_inp_file = False
        #ignore_mode = False
        has_fleurinp = False
        has_parent = False
        #restart_flag = False
        fleurinpgen = False
        copy_remotely = True

        ##########################################
        ############# INPUT CHECK ################
        ##########################################

        try:
            code = inputdict.pop(self.get_linkname('code'))
        except KeyError:
            raise InputValidationError(
                "No code specified for this calculation")

        # a Fleur calc can be created from a fleurinpData alone
        #(then no parent is needed) all files are in the repo, but usually it is
        # a child of a inpgen calc or an other fleur calc (some or all files are
        # in a remote source). if the User has not changed something, the
        #calculation does not need theoretical a new FleurinpData it could use
        #the one from the parent, but the plug-in desgin is in a way that it has
        # to be there and it just copies files if changes occured..

        fleurinp = inputdict.pop(self.get_linkname('fleurinpdata'), None)
        if fleurinp is None:
            #xml_inp_dict = {}
            has_fleurinp = False
        else:
            if not isinstance(fleurinp, FleurinpData):
                raise InputValidationError(
                    "The FleurinpData node given is not of type FleurinpData.")
            has_fleurinp = True
        parent_calc_folder = inputdict.pop(self.get_linkname('parent_folder'),
                                           None)
        #print parent_calc_folder
        if parent_calc_folder is None:
            has_parent = False
            if not has_fleurinp:
                raise InputValidationError(
                    "No parent calculation found and no fleurinp data "
                    "given, need either one or both for a "
                    "'fleurcalculation'.")
        else:  #
            if not isinstance(parent_calc_folder, RemoteData):
                raise InputValidationError("parent_calc_folder, if specified,"
                                           "must be of type RemoteData")

            # extract parent calculation
            parent_calcs = parent_calc_folder.get_inputs(
                node_type=JobCalculation)
            n_parents = len(parent_calcs)
            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"))
            parent_calc = parent_calcs[0]
            has_parent = True
            #print parent_calc
            # check that it is a valid parent
            #self._check_valid_parent(parent_calc)

            # if inpgen calc do
            # check if folder from db given, or get folder from rep.
            # Parent calc does not has to be on the same computer.

            if isinstance(parent_calc, FleurCalculation):
                new_comp = self.get_computer()
                old_comp = parent_calc.get_computer()
                if new_comp.uuid != old_comp.uuid:
                    #dont copy files, copy files localy
                    copy_remotely = False
                    #raise InputValidationError(
                    #    "FleurCalculation must be launched on the same computer"
                    #    " of the parent: {}".format(old_comp.get_name()))
            elif isinstance(parent_calc, FleurinputgenCalculation):
                fleurinpgen = True
                new_comp = self.get_computer()
                old_comp = parent_calc.get_computer()
                if new_comp.uuid != old_comp.uuid:
                    #dont copy files, copy files localy
                    copy_remotely = False
            else:
                raise InputValidationError(
                    "parent_calc, must be either an 'inpgen calculation' or"
                    " a 'fleur calculation'.")

        # check existence of settings (optional)
        settings = inputdict.pop(self.get_linkname('settings'), None)
        #print('settings: {}'.format(settings))
        if settings is None:
            settings_dict = {}
        else:
            if not isinstance(settings, ParameterData):
                raise InputValidationError(
                    "settings, if specified, must be of "
                    "type ParameterData")
            else:
                settings_dict = settings.get_dict()
        #check for for allowed keys, ignor unknown keys but warn.
        for key in settings_dict.keys():
            if key not in self._settings_keys:
                #TODO warrning
                self.logger.info("settings dict key {} for Fleur calculation"
                                 "not reconized, only {} are allowed."
                                 "".format(key, self._settings_keys))
        #print settings_dict
        # Here, there should be no other inputs
        if inputdict:
            raise InputValidationError("The following input data nodes are "
                                       "unrecognized: {}".format(
                                           inputdict.keys()))

        #TODO: Detailed check of FleurinpData
        # if certain files are there in fleurinpData.
        # from where to copy

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

        # file copy stuff TODO check in fleur input
        if has_fleurinp:
            self._DEFAULT_INPUT_FILE = fleurinp.get_file_abs_path(
                self._INPXML_FILE_NAME)

            #local_copy_list.append((
            #    fleurinp.get_file_abs_path(self._INPXML_FILE_NAME),
            #    self._INPXML_FILE_NAME))
            #copy ALL files from inp.xml
            allfiles = fleurinp.files
            for file1 in allfiles:
                local_copy_list.append(
                    (fleurinp.get_file_abs_path(file1), file1))
            modes = fleurinp.get_fleur_modes()

            # add files to mode_retrieved_filelist
            if modes['band']:
                mode_retrieved_filelist.append(self._BAND_FILE_NAME)
                mode_retrieved_filelist.append(self._BAND_GNU_FILE_NAME)
            if modes['dos']:
                mode_retrieved_filelist.append(self._DOS_FILE_NAME)
            if modes['forces']:
                print 'FORCES!!!'
                mode_retrieved_filelist.append(self._NEW_XMlINP_FILE_NAME)
                mode_retrieved_filelist.append(self._FORCE_FILE_NAME)
            if modes['ldau']:
                mode_retrieved_filelist.append(self._NMMPMAT_FILE_NAME)
            #if noco, ldau, gw...
            # TODO: check from where it was copied, and copy files of its parent
            # if needed
        #self.logger.info("@@@@@@@@@@@@@@@@@@@@@@@@has_parent {}".format(has_parent))

        if has_parent:
            # copy the right files #TODO check first if file, exist and throw
            # warning, now this will throw an error
            outfolderpath = parent_calc.out.retrieved.folder.abspath
            self.logger.info("out folder path {}".format(outfolderpath))

            #print outfolderpath
            if fleurinpgen and (not has_fleurinp):
                for file1 in self._copy_filelist_inpgen:
                    local_copy_list.append(
                        (os.path.join(outfolderpath, 'path',
                                      file1), os.path.join(file1)))
            elif not fleurinpgen and (not has_fleurinp):  # fleurCalc
                for file1 in self._copy_filelist_scf:
                    local_copy_list.append(
                        (os.path.join(outfolderpath, 'path',
                                      file1), os.path.join(file1)))
                filelist_tocopy_remote = filelist_tocopy_remote  # + self._copy_filelist_scf_remote
                #TODO get inp.xml from parent fleurinpdata, since otherwise it will be doubled in repo
            elif fleurinpgen and has_fleurinp:
                # everything is taken care of
                pass
            elif not fleurinpgen and has_fleurinp:
                # input file is already taken care of
                for file1 in self._copy_filelist_scf1:
                    local_copy_list.append(
                        (os.path.join(outfolderpath, 'path',
                                      file1), os.path.join(file1)))
                filelist_tocopy_remote = filelist_tocopy_remote  # + self._copy_filelist_scf_remote

            # TODO not on same computer -> copy needed files from repository,
            # if they are not there, throw error
            if copy_remotely:  # on same computer.
                #print('copy files remotely')

                # from fleurmodes
                if modes['pot8']:
                    filelist_tocopy_remote = filelist_tocopy_remote + self._copy_filelist_scf_remote
                    filelist_tocopy_remote.append(self._POT_FILE_NAME)
                #    #filelist_tocopy_remote.append(self._POT2_FILE_NAME)
                elif modes['dos']:
                    pass
                elif modes['band']:
                    pass
                else:
                    filelist_tocopy_remote = filelist_tocopy_remote + self._copy_filelist_scf_remote
                # from settings, user specified
                #TODO check if list?
                for file1 in settings_dict.get('additional_remotecopy_list',
                                               []):
                    filelist_tocopy_remote.append(file1)

                for file1 in settings_dict.get('remove_from_remotecopy_list',
                                               []):
                    if file1 in filelist_tocopy_remote:
                        filelist_tocopy_remote.remove(file1)

                for file1 in filelist_tocopy_remote:
                    remote_copy_list.append(
                        (parent_calc_folder.get_computer().uuid,
                         os.path.join(parent_calc_folder.get_remote_path(),
                                      file1), self._OUTPUT_FOLDER))
                #print remote_copy_list
                #self.logger.info("remote copy file list {}".format(remote_copy_list))

        ########## MAKE CALCINFO ###########

        calcinfo = CalcInfo()

        calcinfo.uuid = self.uuid
        # Empty command line by default
        #cmdline_params = settings_dict.pop('CMDLINE', [])
        #calcinfo.cmdline_params = (list(cmdline_params)
        #                           + ["-in", self._INPUT_FILE_NAME])
        #print local_copy_list
        self.logger.info("local copy file list {}".format(local_copy_list))

        calcinfo.local_copy_list = local_copy_list
        calcinfo.remote_copy_list = remote_copy_list
        #(remotemachinename, remoteabspath, relativedestpath)
        calcinfo.remote_symlink_list = remote_symlink_list
        #calcinfo.stdout_name = self._OUTPUT_FILE_NAME

        # Retrieve by default the output file and the xml file
        retrieve_list = []
        retrieve_list.append(self._OUTXML_FILE_NAME)
        retrieve_list.append(self._INPXML_FILE_NAME)
        #calcinfo.retrieve_list.append(self._OUTPUT_FILE_NAME)
        retrieve_list.append(self._SHELLOUTPUT_FILE_NAME)
        retrieve_list.append(self._CDN1_FILE_NAME)
        retrieve_list.append(self._ERROR_FILE_NAME)
        #calcinfo.retrieve_list.append(self._TIME_INFO_FILE_NAME)
        retrieve_list.append(self._OUT_FILE_NAME)
        #calcinfo.retrieve_list.append(self._INP_FILE_NAME)
        #calcinfo.retrieve_list.append(self._ENPARA_FILE_NAME)
        #calcinfo.retrieve_list.append(self._SYMOUT_FILE_NAME)
        #calcinfo.retrieve_list.append(self._KPTS_FILE_NAME)

        # if certain things are modefied, flags set,
        #other files should be retrieved, example DOS.x...
        #print "mode_retrieved_filelist", repr(mode_retrieved_filelist)
        for mode_file in mode_retrieved_filelist:
            retrieve_list.append(mode_file)
        #print('retrieve_list: {}'.format(retrieve_list))

        # user specific retrieve
        add_retrieve = settings_dict.get('additional_retrieve_list', [])
        #print('add_retrieve: {}'.format(add_retrieve))
        for file1 in add_retrieve:
            retrieve_list.append(file1)

        remove_retrieve = settings_dict.get('remove_from_retrieve_list', [])
        for file1 in remove_retrieve:
            if file1 in retrieve_list:
                retrieve_list.remove(file1)

        calcinfo.retrieve_list = []
        for file1 in retrieve_list:
            calcinfo.retrieve_list.append(file1)

        codeinfo = CodeInfo()
        # should look like: codepath -xmlInput < inp.xml > shell.out 2>&1
        walltime_sec = self.get_max_wallclock_seconds()
        #self.logger.info("!!!!!!!!!!!!!!!!!!! walltime_sec : {}"
        #                         "".format(walltime_sec))
        cmdline_params = ["-xml"]  #, "-wtime", "{}".format(walltime_sec)]
        #walltime_sec = self.get_max_wallclock_seconds()
        #print('walltime: {}'.format(walltime_sec))
        if walltime_sec:
            walltime_min = max(1, walltime_sec / 60)
            cmdline_params.append("-wtime")
            cmdline_params.append("{}".format(walltime_min))

        # user specific commandline_options
        for command in settings_dict.get('cmdline', []):
            cmdline_params.append(command)

        codeinfo.cmdline_params = list(cmdline_params)
        # + ["<", self._INPXML_FILE_NAME,
        # ">", self._SHELLOUTPUT_FILE_NAME, "2>&1"]
        codeinfo.code_uuid = code.uuid
        codeinfo.withmpi = self.get_withmpi()
        codeinfo.stdin_name = self._INPUT_FILE_NAME
        codeinfo.stdout_name = self._SHELLOUTPUT_FILE_NAME
        #codeinfo.join_files = True
        codeinfo.stderr_name = self._ERROR_FILE_NAME

        calcinfo.codes_info = [codeinfo]
        '''
        # not needed in new version
        if fleurinpgen:# execute twice, as long start density stop
            codeinfo1 = CodeInfo()
            cmdline_params = ["-xmlInput"]
            codeinfo1.cmdline_params = list(cmdline_params)
            # + ["<", self._INPUT_FILE_NAME])#,
	        # ">",self._OUTPUT_FILE_NAME]
            codeinfo1.code_uuid = code.uuid
            codeinfo1.withmpi = self.get_withmpi()
            codeinfo1.stdin_name = self._INPUT_FILE_NAME
            codeinfo1.stdout_name = self._SHELLOUTPUT_FILE_NAME
            calcinfo.codes_info.append(codeinfo1)

        if settings_dict:
            raise InputValidationError("The following keys have been found in "
                "the settings input node, but were not understood: {}".format(
                ",".join(settings_dict.keys())))
        '''
        return calcinfo
Example #26
0
def upload_upf_family(folder,
                      group_label,
                      group_description,
                      stop_if_existing=True):
    """Upload a set of UPF files in a given group.

    :param folder: a path containing all UPF files to be added.
        Only files ending in .UPF (case-insensitive) are considered.
    :param group_label: the name of the group to create. If it exists and is non-empty, a UniquenessError is raised.
    :param group_description: string to be set as the group description. Overwrites previous descriptions.
    :param stop_if_existing: if True, check for the md5 of the files and, if the file already exists in the DB, raises a
        MultipleObjectsError. If False, simply adds the existing UPFData node to the group.
    """
    # pylint: disable=too-many-locals,too-many-branches
    import os

    from aiida import orm
    from aiida.common import AIIDA_LOGGER
    from aiida.common.exceptions import UniquenessError
    from aiida.common.files import md5_file

    if not os.path.isdir(folder):
        raise ValueError('folder must be a directory')

    # only files, and only those ending with .upf or .UPF;
    # go to the real file if it is a symlink
    filenames = [
        os.path.realpath(os.path.join(folder, i)) for i in os.listdir(folder)
        if os.path.isfile(os.path.join(folder, i))
        and i.lower().endswith('.upf')
    ]

    nfiles = len(filenames)

    automatic_user = orm.User.objects.get_default()
    group, group_created = orm.Group.objects.get_or_create(
        label=group_label, type_string=UPFGROUP_TYPE, user=automatic_user)

    if group.user.email != automatic_user.email:
        raise UniquenessError(
            'There is already a UpfFamily group with label {}'
            ', but it belongs to user {}, therefore you '
            'cannot modify it'.format(group_label, group.user.email))

    # Always update description, even if the group already existed
    group.description = group_description

    # NOTE: GROUP SAVED ONLY AFTER CHECKS OF UNICITY

    pseudo_and_created = []

    for filename in filenames:
        md5sum = md5_file(filename)
        builder = orm.QueryBuilder()
        builder.append(UpfData, filters={'attributes.md5': {'==': md5sum}})
        existing_upf = builder.first()

        if existing_upf is None:
            # return the upfdata instances, not stored
            pseudo, created = UpfData.get_or_create(filename,
                                                    use_first=True,
                                                    store_upf=False)
            # to check whether only one upf per element exists
            # NOTE: actually, created has the meaning of "to_be_created"
            pseudo_and_created.append((pseudo, created))
        else:
            if stop_if_existing:
                raise ValueError('A UPF with identical MD5 to '
                                 ' {} cannot be added with stop_if_existing'
                                 ''.format(filename))
            existing_upf = existing_upf[0]
            pseudo_and_created.append((existing_upf, False))

    # check whether pseudo are unique per element
    elements = [(i[0].element, i[0].md5sum) for i in pseudo_and_created]
    # If group already exists, check also that I am not inserting more than
    # once the same element
    if not group_created:
        for aiida_n in group.nodes:
            # Skip non-pseudos
            if not isinstance(aiida_n, UpfData):
                continue
            elements.append((aiida_n.element, aiida_n.md5sum))

    elements = set(elements)  # Discard elements with the same MD5, that would
    # not be stored twice
    elements_names = [e[0] for e in elements]

    if not len(elements_names) == len(set(elements_names)):
        duplicates = {x for x in elements_names if elements_names.count(x) > 1}
        duplicates_string = ', '.join(i for i in duplicates)
        raise UniquenessError('More than one UPF found for the elements: ' +
                              duplicates_string + '.')

        # At this point, save the group, if still unstored
    if group_created:
        group.store()

    # save the upf in the database, and add them to group
    for pseudo, created in pseudo_and_created:
        if created:
            pseudo.store()

            AIIDA_LOGGER.debug('New node {} created for file {}'.format(
                pseudo.uuid, pseudo.filename))
        else:
            AIIDA_LOGGER.debug('Reusing node {} for file {}'.format(
                pseudo.uuid, pseudo.filename))

    # Add elements to the group all togetehr
    group.add_nodes([pseudo for pseudo, created in pseudo_and_created])

    nuploaded = len([_ for _, created in pseudo_and_created if created])

    return nfiles, nuploaded
Example #27
0
    def upload_basisset_family(
        cls,
        folder,
        group_name,
        group_description,
        stop_if_existing=True,
        extension=".basis",
        dry_run=False,
    ):
        """
        Upload a set of Basis Set files in a given group.

        :param folder: a path (str or pathlib.Path) containing all Basis Set files to be added.
            Only files ending in set extension (case-sensitive) considered
        :param group_name: the name of the group to create. If it exists and is
            non-empty, a UniquenessError is raised.
        :param group_description: a string to be set as the group description.
            Overwrites previous descriptions, if the group was existing.
        :param stop_if_existing: if True, check for the md5 of the files and,
            if file already exists in the DB, raises a MultipleObjectsError.
            If False, simply adds the existing BasisSetData node to the group.
        :param extension: the filename extension to look for
        :param dry_run: If True, do not change the database.
        """
        if isinstance(folder, str):
            folder = pathlib.Path(folder)

        if not folder.is_dir():
            raise ValueError("folder must be a directory")

        paths = [
            p.resolve() for p in folder.glob("*{}".format(extension)) if p.is_file()
        ]

        automatic_user = User.objects.get_default()
        group, group_created = BasisSetFamily.objects.get_or_create(
            label=group_name, user=automatic_user
        )

        if group.user.email != automatic_user.email:
            raise UniquenessError(
                "There is already a BasisSetFamily group with name {}"
                ", but it belongs to user {}, therefore you "
                "cannot modify it".format(group_name, group.user.email)
            )

        # Always update description, even if the group already existed
        group.description = group_description

        # NOTE: GROUP SAVED ONLY AFTER CHECKS OF UNICITY

        basis_and_created = retrieve_basis_sets(paths, stop_if_existing)
        # check whether basisset are unique per element
        elements = [(i[0].element, i[0].md5sum) for i in basis_and_created]
        # If group already exists, check also that I am not inserting more than
        # once the same element
        if not group_created:
            for aiida_n in group.nodes:
                # Skip non-basis sets
                if not isinstance(aiida_n, BasisSetData):
                    continue
                elements.append((aiida_n.element, aiida_n.md5sum))

        elements = set(elements)  # Discard elements with the same MD5, that would
        # not be stored twice
        elements_names = [e[0] for e in elements]

        if not len(elements_names) == len(set(elements_names)):
            duplicates = set([x for x in elements_names if elements_names.count(x) > 1])
            duplicates_string = ", ".join(i for i in duplicates)
            raise UniquenessError(
                ("More than one Basis found for the elements: " "{}").format(
                    duplicates_string
                )
            )

        # At this point, save the group, if still unstored
        if group_created and not dry_run:
            group.store()

        # save the basis set in the database, and add them to group
        for basisset, created in basis_and_created:
            if created and not dry_run:
                basisset.store()

        # Add elements to the group all together
        if not dry_run:
            group.add_nodes([basis for basis, created in basis_and_created])

        nuploaded = len([_ for _, created in basis_and_created if created])

        return len(paths), nuploaded