Exemplo n.º 1
0
    def validate_parameters(param_data, potential_object) -> bool:
        """Validate the inputs for an optimization calculation.

        :param param_data: input parameters for the optimization calculations
        :type param_data: orm.Dict
        :param potential_object: LAMMPS potential
        :type potential_object: EmpiricalPotential
        :raises InputValidationError: if there is no parameters data passed
        :raises InputValidationError: if the units of the parameters and
            the potential are different.
        :return: whether the parameters are valid or not
        :rtype: bool
        """
        if param_data is None:
            raise InputValidationError('parameter data not set')
        validate_against_schema(param_data.get_dict(), 'optimize.schema.json')

        # ensure the potential and paramters are in the same unit systems
        # TODO convert between unit systems (e.g. using https://pint.readthedocs.io)
        if 'units' in param_data.get_dict():
            punits = param_data.get_dict()['units']
            if not punits == potential_object.default_units:
                raise InputValidationError(
                    f'the units of the parameters ({punits}) and potential '
                    f'({potential_object.default_units}) are different')

        return True
Exemplo n.º 2
0
    def _get_following_text(self, inputdict, settings):
        """
        Add the kpoints after the namelist.
        
        This function should consume the content of inputdict (if it requires
        a different node) or the keys inside settings, using the 'pop' method,
        so that inputdict and settings should remain empty at the end of 
        _prepare_for_submission, if all flags/nodes were recognized
        """
        from aiida.common.exceptions import InputValidationError

        try:
            kpoints = inputdict.pop(self.get_linkname('kpoints'))
        except KeyError:
            raise InputValidationError(
                "No kpoints specified for this calculation")
        if not isinstance(kpoints, KpointsData):
            raise InputValidationError("kpoints is not of type KpointsData")

        try:
            klist = kpoints.get_kpoints()
        except AttributeError:
            klist = kpoints.get_kpoints_mesh(print_list=True)

        retlist = ["{}".format(len(klist))]
        for k in klist:
            retlist.append("{:18.10f} {:18.10f} {:18.10f}".format(*k))

        return "\n".join(retlist) + "\n"
Exemplo n.º 3
0
    def _check_and_extract_input_nodes(self, tempfolder):
        """
        Extract input nodes from inputdict and check consitency of input nodes
        :param inputdict: dict of inputnodes
        :returns:
            * parameters (aiida_kkr.tools.kkr_params.kkrparams), optional: parameters of KKRimp that end up in config.cfg
            * code (KKRimpCodeNode): code of KKRimp on some machine
            * imp_info (DictNode): parameter node of the impurity information, extracted from host_parent_calc
            * kkrflex_file_paths (dict): dictionary of {filenames: absolute_path_to_file} for the kkrflex-files
            * shapfun_path (str): absolute path of the shapefunction of the host parent calculation
            * host_parent_calc (KkrCalculation): node of the parent host calculation where the kkrflex-files were created
            * impurity_potential (SinglefileData): single file data node containing the starting potential for the impurity calculation
            * parent_calc_folder (RemoteData): remote directory of a parent KKRimp calculation
        """

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

        # now check for optional nodes
        if 'parameters' in self.inputs:
            parameters = self.inputs.parameters
        else:
            parameters = None
        if parameters is not None:  # convert to kkrparams instance
            parameters = kkrparams(params_type='kkrimp',
                                   **parameters.get_dict())

        # get hostfiles
        imp_info, kkrflex_file_paths, shapfun_path, shapes, host_parent_calc, params_host, structure = self._get_and_verify_hostfiles(
            tempfolder)

        # check impurity potential or parent calculation input
        # impurity_potential
        if 'impurity_potential' in self.inputs:
            impurity_potential = self.inputs.impurity_potential
            found_imp_pot = True
        else:
            impurity_potential = None
            found_imp_pot = False
        # parent calculation folder
        if 'parent_calc_folder' in self.inputs:
            parent_calc_folder = self.inputs.parent_calc_folder
            found_parent_calc = True
        else:
            parent_calc_folder = None
            found_parent_calc = False
        # consistency checks
        if not found_parent_calc and not found_imp_pot:
            raise InputValidationError(
                "Neither impurity_potential nor parent_calc_folder specified for this calculation.\n"
                "Please provide either impurity_potential or parent_calc_folder."
            )
        elif found_parent_calc and found_imp_pot:
            raise InputValidationError(
                "Both impurity_potential and parent_calc_folder specified for this calculation.\n"
                "Please provide one one, i.e. either impurity_potential or parent_calc_folder."
            )

        # Done checking inputs, returning...
        return parameters, code, imp_info, kkrflex_file_paths, shapfun_path, shapes, host_parent_calc, params_host, impurity_potential, parent_calc_folder, structure
Exemplo n.º 4
0
    def _retrieve_basis_sets(self, inputdict, instruct):
        """ retrieve BasisSetData objects from the inputdict, associate them with an atomic element
        and validate a 1-to-1 mapping between the two

        :param inputdict: dictionary of inputs
        :param instruct: input StructureData
        :return: basissets dict {element: BasisSetData}
        """
        basissets = {}
        # I create here a dictionary that associates each kind name to a basisset
        for link in inputdict.keys():
            if link.startswith(self._get_linkname_basisset_prefix()):
                element = link[len(self._get_linkname_basisset_prefix()):]
                the_basisset = inputdict.pop(link)
                if not isinstance(the_basisset, BasisSetData):
                    raise InputValidationError(
                        "basisset for element '{}' is not of "
                        "type BasisSetData".format(element))
                basissets[element] = the_basisset

        # Check retrieved elements match the required elements
        elements_required = [k.symbol for k in instruct.kinds]
        if set(elements_required) != set(basissets.keys()):
            err_msg = (
                "Mismatch between the defined basissets and the list of "
                "elements of the structure. Basissets: {}; elements: {}".
                format(",".join(basissets.keys()), ",".join(
                    list(elements_required))))
            raise InputValidationError(err_msg)

        return basissets
Exemplo n.º 5
0
    def get_name_from_quantum_numbers(cls, angular_momentum,
                                      magnetic_number=None):
        """
        Returns the orbital_name correponding to the angular_momentum alone,
        or to both angular_number with magnetic_number. For example using
        angular_momentum=1 and magnetic_number=1 will return "Px"
        """
        # importing a copy of the conversion_dict
        convert_ref = copy.deepcopy(conversion_dict)
        orbital_name = [x for x in convert_ref if
                any([convert_ref[x][y]['angular_momentum'] ==
                angular_momentum for y in convert_ref[x]])]
        if len(orbital_name) == 0:
            raise InputValidationError("No orbital name corresponding to the "
            "angular_momentum {} could be found".format(angular_momentum))
        if magnetic_number is not None:
            # finds angu
            orbital_name = orbital_name[0]
            orbital_name = [x for x in convert_ref[orbital_name] if
                            convert_ref[orbital_name][x]['magnetic_number']
                            == magnetic_number]

            if len(orbital_name) == 0:
                raise InputValidationError("No orbital name corresponding to "
                                           "the magnetic_number {} could be "
                                           "found".format(magnetic_number))
        return orbital_name[0]
Exemplo n.º 6
0
    def _validate_inputs(self, inputdict):
        """ Validate input links.
        """
        # Check code
        try:
            code = inputdict.pop(self.get_linkname('code'))
        except KeyError:
            raise InputValidationError("No code specified for this "
                                       "calculation")

        # Check input files
        try:
            surface_sample = inputdict.pop(self.get_linkname('surface_sample'))
            if not isinstance(surface_sample, SinglefileData):
                raise InputValidationError(
                    "surface_sample not of type SinglefileData")
        except KeyError:
            raise InputValidationError(
                "No input structure specified for calculation")

        try:
            cell = inputdict.pop(self.get_linkname('cell'))
            if not isinstance(cell, SinglefileData):
                raise InputValidationError("cell not of type SinglefileData")
        except KeyError:
            raise InputValidationError(
                "No input structure specified for calculation")

        # Check that nothing is left unparsed
        if inputdict:
            raise ValidationError("Unrecognized inputs: {}".format(inputdict))

        return code, surface_sample, cell
Exemplo n.º 7
0
    def _get_validated_parameters_dict(self, parameters):
        param_dict_raw = parameters.get_dict()

        # keys to lowercase, check for duplicates
        param_dict = {
            key.lower(): value
            for key, value in param_dict_raw.items()
        }
        if len(param_dict) != len(param_dict_raw):
            counter = Counter([k.lower() for k in param_dict_raw])
            counter = {key: val for key, val in counter if val > 1}
            raise InputValidationError(
                'The following keys were found more than once in the parameters: {}. Check for duplicates written in upper- / lowercase.'
                .format(counter))

        # check for blocked keywords
        existing_blocked_keys = []
        for key in self._blocked_parameter_keys:
            if key in param_dict:
                existing_blocked_keys.append(key)
        if existing_blocked_keys:
            raise InputValidationError(
                'The following blocked keys were found in the parameters: {}'.
                format(existing_blocked_keys))

        return param_dict
Exemplo n.º 8
0
def build_response(status=200, headers=None, data=None):
    """

    :param status: status of the response, e.g. 200=OK, 400=bad request
    :param headers: dictionary for additional header k,v pairs,
    e.g. X-total-count=<number of rows resulting from query>
    :param data: a dictionary with the data returned by the Resource
    :return: a Flask response object
    """

    ## Type checks
    # mandatory parameters
    if not isinstance(data, dict):
        raise InputValidationError("data must be a dictionary")

    # non-mandatory parameters
    if status is not None:
        try:
            status = int(status)
        except ValueError:
            raise InputValidationError("status must be an integer")

    if headers is not None and not isinstance(headers, dict):
        raise InputValidationError("header must be a dictionary")

    # Build response
    response = jsonify(data)
    response.status_code = status

    if headers is not None:
        for k, v in headers.iteritems():
            response.headers[k] = v

    return response
Exemplo n.º 9
0
    def get_name_from_quantum_numbers(cls, angular_momentum, magnetic_number=None):
        """
        Returns the orbital_name correponding to the angular_momentum alone,
        or to both angular_number with magnetic_number. For example using
        angular_momentum=1 and magnetic_number=1 will return "Px"
        """
        orbital_name = [
            x for x in CONVERSION_DICT
            if any([CONVERSION_DICT[x][y]['angular_momentum'] == angular_momentum for y in CONVERSION_DICT[x]])
        ]
        if not orbital_name:
            raise InputValidationError(
                'No orbital name corresponding to the '
                'angular_momentum {} could be found'.format(angular_momentum)
            )
        if magnetic_number is not None:
            # finds angular momentum
            orbital_name = orbital_name[0]
            orbital_name = [
                x for x in CONVERSION_DICT[orbital_name]
                if CONVERSION_DICT[orbital_name][x]['magnetic_number'] == magnetic_number
            ]

            if not orbital_name:
                raise InputValidationError(
                    'No orbital name corresponding to '
                    'the magnetic_number {} could be '
                    'found'.format(magnetic_number)
                )
        return orbital_name[0]
Exemplo n.º 10
0
def finilize_cross_results(cross_data, gap_threshold):
    """Analyze the final result of kpt-cross calculation, and return valid crossings."""
    if not isinstance(cross_data, orm.ArrayData):
        raise InputValidationError(
            'Invalide type {} for parameter `cross_data`'.format(
                type(cross_data)))
    if not isinstance(gap_threshold, orm.Float):
        raise InputValidationError(
            'Invalide type {} for parameter `gap_threshold`'.format(
                type(gap_threshold)))

    gap_thr = gap_threshold.value
    kpts = cross_data.get_array('kpoints')
    gaps = cross_data.get_array('gaps')

    w1 = np.where(gaps <= gap_thr)[0]
    w2 = np.where(gaps > gap_thr)[0]

    crossings = kpts[w1, :]
    low_gap = kpts[w2, :]

    res = orm.ArrayData()
    res.set_array('crossings', crossings)
    res.set_array('cr_gaps', gaps[w1])
    res.set_array('low_gap', low_gap)
    res.set_array('cr_lg', gaps[w2])

    return res
Exemplo n.º 11
0
 def start(self):
     # for kpoints, we will need to have the scf step, and  use YamboWorkflow not YamboRestartWf
     #
     self.ctx.max_iterations = 20
     self.ctx.iteration = 0
     self.ctx.skip_prescf = False
     self.ctx.very_first = True
     convergence_parameters_dict = self.inputs.convergence_parameters.get_dict(
     )
     # Mandatory inputs
     try:
         self.ctx.variable_to_converge = convergence_parameters_dict[
             'variable_to_converge']
     except KeyError:
         raise InputValidationError(
             'variable_to_converge not defined in input!')
     try:
         self.ctx.start_value = convergence_parameters_dict['start_value']
     except KeyError:
         raise InputValidationError('start_value not defined in input!')
     try:
         self.ctx.step = convergence_parameters_dict['step']
     except KeyError:
         raise InputValidationError('step not defined in input!')
     try:
         self.ctx.max_value = convergence_parameters_dict['max_value']
     except KeyError:
         raise InputValidationError('max_value not defined in input!')
     try:
         self.ctx.conv_tol = convergence_parameters_dict['conv_tol']
     except KeyError:
         raise InputValidationError('conv_tol not defined in input!')
     # Optional inputs
     try:
         self.ctx.conv_window = convergence_parameters_dict['conv_window']
     except KeyError:
         self.ctx.conv_window = 3
     try:
         self.ctx.loop_length = convergence_parameters_dict['loop_length']
     except KeyError:
         self.ctx.loop_length = 4
     self.ctx.distance_kpoints = self.ctx.start_value
     self.ctx.en_diffs = []
     if self.ctx.variable_to_converge == 'bands':
         self.ctx.conv_elem = {'BndsRnXp': [], 'GbndRnge': []}
     elif self.ctx.variable_to_converge == 'W_cutoff':
         self.ctx.conv_elem = {'NGsBlkXp': []}
     elif self.ctx.variable_to_converge == 'FFT_cutoff':
         self.ctx.conv_elem = {'FFTGvecs': []}
     elif self.ctx.variable_to_converge == 'kpoints':
         self.ctx.conv_elem = {'kpoints': []}
     else:
         self.ctx.conv_elem = {self.ctx.variable_to_converge: []}
         self.report(
             'WARNING: the variable to converge is {}, not recognized but I try anyway to converge it'
         )
     self.report("Setup step completed.")
Exemplo n.º 12
0
def generate_cubic_grid(structure, centers, distance, dim):
    """Generate a cubic grids centered in `centers` of size `distance` and dimensionality `dim`.

    :param structure: aiida.orm.StructureData node  used to get the cell of the material.
    :param centers: aiida.orm.ArrayData containing an array named `centers`.
                    Each element of `centers` is used to generate a cubic grid around it.
    :param distance: aiida.orm.Float indicating the lateral size of the cubic grid.
    :param dim: aiida.orm.Int determining the dimensionality of the grid.
                e.g.: dim=1 -> 5x1x1   dim = 2 -> 5x5x1   dim = 3 -> 5x5x5

    :return: aiida.orm.KpointsData containing the generated grids.
    """
    if not isinstance(structure, orm.StructureData):
        raise InputValidationError(
            'Invalide type {} for parameter `structure`'.format(
                type(structure)))
    if not isinstance(centers, orm.ArrayData):
        raise InputValidationError(
            'Invalide type {} for parameter `centers`'.format(type(centers)))
    if not isinstance(distance, orm.Float):
        raise InputValidationError(
            'Invalide type {} for parameter `distance`'.format(type(distance)))

    npoints = 5

    centers = centers.get_array('pinned')
    dist = distance.value / (npoints - 1)
    dim = dim.value

    # yapf: disable
    l    = np.arange(-(npoints-1)//2, (npoints-1)//2 + 1) + ((npoints + 1)%2) * 0.5
    lx   = l
    ly   = l if dim > 1 else [0,]
    lz   = l if dim > 2 else [0,]
    grid = np.array(list(product(lx, ly, lz))) * dist

    res = np.empty((0,3))
    for n,c in enumerate(centers):
        new = c + grid
        if n == 0:
            attach = new
        else:
            old_tree = KDTree(res)
            new_tree = KDTree(new)

            query = new_tree.query_ball_tree(old_tree, r=dist*1.74)

            attach = np.array([new[n] for n,q in enumerate(query) if not q])

        if len(attach):
            res = np.vstack((res, attach))

    kpt = orm.KpointsData()
    kpt.set_cell_from_structure(structure)
    kpt.set_kpoints(res, cartesian=True)

    return kpt
Exemplo n.º 13
0
    def _generate_NEBinputdata(self,neb_parameters,settings_dict):
        """ 
        This methods generate the input data for the NEB part of the calculation
        """
        # 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(neb_parameters.get_dict(),
                                       dict_name='parameters')
        input_params = {k: _lowercase_dict(v, dict_name=k)
                        for k, v in input_params.iteritems()}
        
        # For the neb input there is no blocked keyword
        
        # Create an empty dictionary for the compulsory namelist 'PATH'
        # if not present
        if 'PATH' not in input_params:
            input_params['PATH'] = {}

        # In case of climbing image, we need the corresponding card
        climbing_image = False
        if input_params['PATH'].get('ci_scheme','no-ci').lower()  in ['manual']:
            climbing_image = True
            try: 
                climbing_image_list = settings_dict.pop("CLIMBING_IMAGES")
            except KeyError:
                raise InputValidationError("No climbing image specified for this calculation")
            if not isinstance(climbing_image_list, list):
                raise InputValidationError("Climbing images should be provided as a list")
            if [ i  for i in climbing_image_list if i<2 or i >= input_params['PATH'].get('num_of_images',2)]:
                raise InputValidationError("The climbing images should be in the range between the first "
                                           "and the last image")

            climbing_image_card = "CLIMBING_IMAGES\n"
            climbing_image_card += ", ".join([str(_) for _ in climbing_image_list]) + "\n"
 

        inputfile = ""    
        inputfile += "&PATH\n"
        # namelist content; set to {} if not present, so that we leave an 
        # empty namelist
        namelist = input_params.pop('PATH', {})
        for k, v in sorted(namelist.iteritems()):
            inputfile += convert_input_to_namelist_entry(k, v)
        inputfile += "/\n"

        # Write cards now
        if climbing_image:
            inputfile += climbing_image_card

        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())))

        return inputfile
Exemplo n.º 14
0
    def validate_input(self):
        """
        # validate input and find out which path (1, or 2) to take
        # return True means run voronoi if false run kkr directly
        """
        inputs = self.inputs

        if 'remote_data' in inputs:
            input_ok = True
        else:
            error = 'ERROR: No remote_data was provided as Input'
            self.ctx.errors.append(error)
            self.control_end_wc(error)
            input_ok = False

        # extract correct remote folder of last calculation if input remote_folder node is not from KkrCalculation but kkr_scf_wc workflow
        input_remote = self.inputs.remote_data
        # check if input_remote has single KkrCalculation parent
        parents = input_remote.get_inputs(node_type=JobCalculation)
        nparents = len(parents)
        if nparents != 1:
            # extract parent workflow and get uuid of last calc from output node
            parent_workflow = input_remote.inp.last_RemoteData
            if not isinstance(parent_workflow, WorkCalculation):
                raise InputValidationError(
                    "Input remote_data node neither output of a KKR/voronoi calculation nor of kkr_scf_wc workflow"
                )
            parent_workflow_out = parent_workflow.out.output_kkr_scf_wc_ParameterResults
            uuid_last_calc = parent_workflow_out.get_dict().get(
                'last_calc_nodeinfo').get('uuid')
            last_calc = load_node(uuid_last_calc)
            if not isinstance(last_calc, KkrCalculation) and not isinstance(
                    last_calc, VoronoiCalculation):
                raise InputValidationError(
                    "Extracted last_calc node not of type KkrCalculation: check remote_data input node"
                )
            # overwrite remote_data node with extracted remote folder
            output_remote = last_calc.out.remote_folder
            self.inputs.remote_data = output_remote

        if 'kkr' in inputs:
            try:
                test_and_get_codenode(inputs.kkr,
                                      'kkr.kkr',
                                      use_exceptions=True)
            except ValueError:
                error = ("The code you provided for kkr does not "
                         "use the plugin kkr.kkr")
                self.ctx.errors.append(error)
                self.control_end_wc(error)
                input_ok = False

        # set self.ctx.input_params_KKR
        self.ctx.input_params_KKR = get_parent_paranode(
            self.inputs.remote_data)

        return input_ok
Exemplo n.º 15
0
 def start(self):
     """This function performs some neccessary checks to ensure all neccessary information is provided, and stores  the provided parameters in  self.ctx variables."""
     self.ctx.max_iterations = 20
     self.ctx.iteration = 0
     self.ctx.skip_prescf = False
     self.ctx.very_first = True
     convergence_parameters_dict = self.inputs.convergence_parameters.get_dict(
     )
     # Mandatory inputs
     try:
         self.ctx.variable_to_converge = convergence_parameters_dict[
             'variable_to_converge']
     except KeyError:
         raise InputValidationError(
             'variable_to_converge not defined in input!')
     try:
         self.ctx.start_value = convergence_parameters_dict['start_value']
     except KeyError:
         raise InputValidationError('start_value not defined in input!')
     try:
         self.ctx.step = convergence_parameters_dict['step']
     except KeyError:
         raise InputValidationError('step not defined in input!')
     try:
         self.ctx.max_value = convergence_parameters_dict['max_value']
     except KeyError:
         raise InputValidationError('max_value not defined in input!')
     try:
         self.ctx.conv_tol = convergence_parameters_dict['conv_tol']
     except KeyError:
         raise InputValidationError('conv_tol not defined in input!')
     # Optional inputs
     try:
         self.ctx.conv_window = convergence_parameters_dict['conv_window']
     except KeyError:
         self.ctx.conv_window = 3
     try:
         self.ctx.loop_length = convergence_parameters_dict['loop_length']
     except KeyError:
         self.ctx.loop_length = 4
     self.ctx.distance_kpoints = self.ctx.start_value
     self.ctx.en_diffs = []
     if self.ctx.variable_to_converge == 'bands':
         self.ctx.conv_elem = {'BndsRnXp': [], 'GbndRnge': []}
     elif self.ctx.variable_to_converge == 'W_cutoff':
         self.ctx.conv_elem = {'NGsBlkXp': []}
     elif self.ctx.variable_to_converge == 'FFT_cutoff':
         self.ctx.conv_elem = {'FFTGvecs': []}
     elif self.ctx.variable_to_converge == 'kpoints':
         self.ctx.conv_elem = {'kpoints': []}
     else:
         self.ctx.conv_elem = {self.ctx.variable_to_converge: []}
         self.report(
             'WARNING: the variable to converge is {}, not recognized but I try anyway to converge it'
         )
     self.report("Setup step completed.")
Exemplo n.º 16
0
def generate_kpt_cross(structure, kpoints, step):
    """Generate a x,y,z cross around each point.

    :param structure: The StructureData to be used.
    :param kpoints: The original list of kpoints in crystal coordinates.
    :param step: The size of the step for the cross.

    :return: A KpointsData object containing all the kpt generated, including the original ones
    """
    if not isinstance(structure, orm.StructureData):
        raise InputValidationError(
            'Invalide type {} for parameter `structure`'.format(
                type(structure)))
    if not isinstance(kpoints, orm.ArrayData):
        raise InputValidationError(
            'Invalide type {} for parameter `kpoints`'.format(type(kpoints)))
    if not isinstance(step, orm.Float):
        raise InputValidationError(
            'Invalide type {} for parameter `step`'.format(type(step)))

    try:
        kpt_cryst = kpoints.get_array('kpoints')
    except:
        kpt_cryst = kpoints.get_array('crossings')
    try:
        skips = kpoints.get_array('skips')
    except:
        skips = [0] * len(kpt_cryst)

    step = step.value

    cell = structure.cell
    recipr = recipr_base(cell)
    kpts_cart = np.dot(kpt_cryst, recipr)

    # Apply cross shifts to original kpts
    shifts = np.array([
        [step, 0, 0],
        [0, step, 0],
        [0, 0, step],
        [0, 0, 0],
        [-step, 0, 0],
        [0, -step, 0],
        [0, 0, -step],
    ])
    app = np.empty((0, 3))
    for s, k in zip(skips, kpts_cart):
        if s:
            continue
        app = np.vstack((app, k + shifts))

    new_kpt = orm.KpointsData()
    new_kpt.set_cell(cell)
    new_kpt.set_kpoints(app, cartesian=True)

    return new_kpt
Exemplo n.º 17
0
    def validate_input_parameters(self, input_nodes):
        """
        Validate the parameters input node and create from it the input parameter dictionary that contains
        all the necessary namelists and their flags that should be written to the input file of the calculation

        :param input_nodes: dictionary of sanitized and validated input nodes
        :returns: input_parameters a dictionary with input namelists and their flags
        """
        qpoints = input_nodes[self.get_linkname('qpoints')]
        parameters = input_nodes[self.get_linkname('parameters')].get_dict()

        # Transform first-level keys (i.e. namelist and card names) to uppercase and second-level to lowercase
        input_parameters = _uppercase_dict(parameters, dict_name='parameters')
        input_parameters = {
            k: _lowercase_dict(v, dict_name=k)
            for k, v in input_parameters.iteritems()
        }

        # Check that required namelists are present
        for namelist in self._compulsory_namelists:
            if not namelist in input_parameters:
                raise InputValidationError(
                    "the required namelist '{}' was not defined".format(
                        namelist))

        # Check for presence of blocked keywords
        for namelist, flag in self._blocked_keywords:
            if namelist in input_parameters and flag in input_parameters[
                    namelist]:
                raise InputValidationError(
                    "explicit definition of the '{}' "
                    "flag in the '{}' namelist or card is not allowed".format(
                        flag, namelist))

        # Validate qpoint input node
        try:
            mesh, offset = qpoints.get_kpoints_mesh()
        except AttributeError:
            raise NotImplementedError(
                'support for explicit qpoints is not implemented, only uniform meshes'
            )

        if any([i != 0. for i in offset]):
            raise NotImplementedError(
                'support for qpoint meshes with non-zero offsets is not implemented'
            )

        input_parameters['INPUTHP']['iverbosity'] = 2
        input_parameters['INPUTHP']['outdir'] = self._OUTPUT_SUBFOLDER
        input_parameters['INPUTHP']['prefix'] = self._PREFIX
        input_parameters['INPUTHP']['nq1'] = mesh[0]
        input_parameters['INPUTHP']['nq2'] = mesh[1]
        input_parameters['INPUTHP']['nq3'] = mesh[2]

        return input_parameters
Exemplo n.º 18
0
def crop_kpoints(structure, kpt_data, centers, radius):
    """Crop a given set of k-points `kpt_data` that are within a spherical radius `r` from a set of centers `centers`.

    :param structure: aiida.orm.StructureData used to get the cell of the material.
    :param kpt_data: aiida.orm.KpointsData to crop.
    :param centers: aiida.orm.ArrayData containing an array named `centers`.
                    Each element of `centers` is used as the center of a spherical cropping.
    :param radius: radius of the sphere cropping.

    :return: aiida.orm.KpointsData node containing the cropped kpoints
    """
    if not isinstance(structure, orm.StructureData):
        raise InputValidationError(
            'Invalide type {} for parameter `structure`'.format(
                type(structure)))
    if not isinstance(kpt_data, orm.KpointsData):
        raise InputValidationError(
            'Invalide type {} for parameter `kpt_data`'.format(type(kpt_data)))
    if not isinstance(centers, orm.ArrayData):
        raise InputValidationError(
            'Invalide type {} for parameter `centers`'.format(type(centers)))
    if not isinstance(radius, orm.Float):
        raise InputValidationError(
            'Invalide type {} for parameter `radius`'.format(type(radius)))
    centers = centers.get_array('centers')
    if len(centers.shape) != 2 or centers.shape[1] != 3:
        raise InputValidationError(
            'Invalide shape {} for array `centers`. Expected (*,3)'.format(
                centers.shape))

    r = radius.value
    cell = np.array(structure.cell)
    recipr = recipr_base(cell)

    try:
        kpt_cryst = np.array(kpt_data.get_kpoints_mesh(print_list=True))
    except MemoryError:
        return orm.Bool(False)
    kpt_cart = np.dot(kpt_cryst, recipr)

    c_cryst = centers
    c_cart = np.dot(c_cryst, recipr)

    kpt_cart = KDTree(kpt_cart)
    centers = KDTree(c_cart)

    query = kpt_cart.query_ball_tree(centers, r=r)

    where = [n for n, l in enumerate(query) if len(l)]

    new = orm.KpointsData()
    new.set_kpoints(kpt_cryst[where])

    return new
Exemplo n.º 19
0
def _create_win_string(
    parameters,
    kpoints,
    structure=None,
    kpoint_path=None,
    projections=None,
    random_projections=False,
):
    from aiida.orm import DataFactory
    from aiida.orm.data.base import List

    # prepare the main input text
    input_file_lines = []
    if isinstance(parameters, DataFactory('parameter')):
        parameters = parameters.get_dict()
    try:
        parameters.setdefault('mp_grid', kpoints.get_kpoints_mesh()[0])
    except AttributeError:
        pass
    input_file_lines += _format_parameters(parameters)

    block_inputs = {}
    if projections is None:
        # If no projections are specified, random projections is used (Dangerous!)
        if random_projections:
            block_inputs['projections'] = ['random']
        else:
            block_inputs['projections'] = []
    elif isinstance(projections, (tuple, list)):
        if random_projections:
            raise InputValidationError(
                'random_projections cannot be True with (tuple,list) projections.'
                'Instead, use "random" string as first element of the list.')
        block_inputs['projections'] = projections
    elif isinstance(projections, List):
        if random_projections:
            raise InputValidationError(
                'random_projections cannot be True if with List-type projections.'
                'Instead, use "random" string as first element of the List.')
        block_inputs['projections'] = projections.get_attr('list')
    else:
        block_inputs['projections'] = _format_all_projections(
            projections, random_projections=True)

    if structure is not None:
        block_inputs['unit_cell_cart'] = _format_unit_cell(structure)
        block_inputs['atoms_cart'] = _format_atoms_cart(structure)
    if kpoints is not None:
        block_inputs['kpoints'] = _format_kpoints(kpoints)
    if kpoint_path is not None:
        block_inputs['kpoint_path'] = _format_kpoint_path(kpoint_path)
    input_file_lines += _format_block_inputs(block_inputs)

    return '\n'.join(input_file_lines) + '\n'
Exemplo n.º 20
0
def load_group(identifier=None, pk=None, uuid=None, label=None, query_with_dashes=True):
    """
    Load a group by one of its identifiers: pk, uuid or label. If the type of the identifier is unknown
    simply pass it without a keyword and the loader will attempt to infer the type

    :param identifier: pk (integer), uuid (string) or label (string) of a group
    :param pk: pk of a group
    :param uuid: uuid of a group, or the beginning of the uuid
    :param label: label of a group
    :param bool query_with_dashes: allow to query for a uuid with dashes
    :returns: the group instance
    :raise InputValidationError: if none or more than one of the identifiers are supplied
    :raise TypeError: if the provided identifier has the wrong type
    :raise NotExistent: if no matching Group is found
    :raise MultipleObjectsError: if more than one Group was found
    """
    from aiida.orm.utils.loaders import IdentifierType, GroupEntityLoader

    # Verify that at least and at most one identifier is specified
    inputs_provided = [value is not None for value in (identifier, pk, uuid, label)].count(True)
    if inputs_provided == 0:
        raise InputValidationError("one of the parameters 'identifier', pk', 'uuid' or 'label' has to be specified")
    elif inputs_provided > 1:
        raise InputValidationError("only one of parameters 'identifier', pk', 'uuid' or 'label' has to be specified")

    if pk is not None:

        if not isinstance(pk, int):
            raise TypeError('a pk has to be an integer')

        identifier = pk
        identifier_type = IdentifierType.ID

    elif uuid is not None:

        if not isinstance(uuid, basestring):
            raise TypeError('uuid has to be a string type')

        identifier = uuid
        identifier_type = IdentifierType.UUID

    elif label is not None:

        if not isinstance(label, basestring):
            raise TypeError('label has to be a string type')

        identifier = label
        identifier_type = IdentifierType.LABEL
    else:
        identifier = str(identifier)
        identifier_type = None

    return GroupEntityLoader.load_entity(identifier, identifier_type, query_with_dashes=query_with_dashes)
Exemplo n.º 21
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_inputs_dict (with the Code!)
        """
        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:
            code = inputdict.pop(self.get_linkname('code'))
        except KeyError:
            raise InputValidationError("No code specified for this "
                                       "calculation")
        if inputdict:
            raise ValidationError("Cannot add other nodes beside parameters")

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

        input_json = parameters.get_dict()

        # write all the input to a file
        input_filename = tempfolder.get_abs_path(self._INPUT_FILE_NAME)
        with open(input_filename, 'w') as infile:
            json.dump(input_json, infile)

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

        calcinfo = CalcInfo()
        calcinfo.uuid = self.uuid
        calcinfo.local_copy_list = []
        calcinfo.remote_copy_list = []
        calcinfo.retrieve_list = [self._OUTPUT_FILE_NAME]

        codeinfo = CodeInfo()
        codeinfo.cmdline_params = [
            self._INPUT_FILE_NAME, self._OUTPUT_FILE_NAME
        ]
        codeinfo.code_uuid = code.uuid
        calcinfo.codes_info = [codeinfo]

        return calcinfo
Exemplo n.º 22
0
    def load_inpxml(self,
                    validate_xml_schema=True,
                    return_included_tags=False,
                    **kwargs):
        """
        Returns the lxml etree and the schema dictionary corresponding to the version. If validate_xml_schema=True
        the file will also be validated against the schema

        Keyword arguments are passed on to the parser
        """
        from masci_tools.io.io_fleurxml import load_inpxml
        from masci_tools.util.xml.common_functions import validate_xml

        self._validate()

        with self.open(path='inp.xml', mode='rb') as inpxmlfile:
            try:
                xmltree, schema_dict = load_inpxml(inpxmlfile, **kwargs)
            except ValueError as exc:
                # prob inp.xml file broken
                err_msg = (
                    'The inp.xml file is probably broken, could not parse it to an xml etree.'
                )
                raise InputValidationError(err_msg) from exc
            except FileNotFoundError as exc:
                # prob inp.xml file broken
                err_msg = (
                    'The inp.xml file is probably broken, could not find corresponding input schema.'
                )
                raise InputValidationError(err_msg) from exc

        xmltree, included_tags = self._include_files(xmltree)
        develop_version = self.inp_version != schema_dict['inp_version']

        if validate_xml_schema and not develop_version:
            try:
                validate_xml(xmltree,
                             schema_dict.xmlschema,
                             error_header=
                             'Input file is not validated against the schema')
            except etree.DocumentInvalid as err:
                raise InputValidationError(err) from err
        elif develop_version:
            self.logger.warning(
                f'You are using a Fleur input file with file version {self.inp_version}.\n'
                'This version has no corresponding XML Schema stored in masci-tools.\n'
                'Unexpected Errors can occur. If that is the case you can try to add the '
                'XML Schema for this file version to masci-tools')

        if return_included_tags:
            return xmltree, schema_dict, included_tags
        else:
            return xmltree, schema_dict
Exemplo n.º 23
0
    def validate_input(self):
        """
        # validate input and find out which path (1, or 2) to take
        # return True means run voronoi if false run kkr directly
        """
        inputs = self.inputs

        if 'remote_data' in inputs:
            input_ok = True
        else:
            input_ok = False
            return self.exit_codes.ERROR_NO_INPUT_REMOTE_DATA

        # extract correct remote folder of last calculation if input remote_folder node is not from KkrCalculation but kkr_scf_wc workflow
        input_remote = self.inputs.remote_data
        # check if input_remote has single KkrCalculation parent
        parents = input_remote.get_incoming(node_class=CalcJobNode)
        nparents = len(parents.all_link_labels())
        if nparents != 1:
            # extract parent workflow and get uuid of last calc from output node
            parent_workflow = input_remote.inputs.last_RemoteData
            if not isinstance(parent_workflow, WorkChainNode):
                raise InputValidationError(
                    "Input remote_data node neither output of a KKR/voronoi calculation nor of kkr_scf_wc workflow"
                )
            parent_workflow_out = parent_workflow.outputs.output_kkr_scf_wc_ParameterResults
            uuid_last_calc = parent_workflow_out.get_dict().get(
                'last_calc_nodeinfo').get('uuid')
            last_calc = load_node(uuid_last_calc)
            if not isinstance(last_calc, KkrCalculation) and not isinstance(
                    last_calc, VoronoiCalculation):
                raise InputValidationError(
                    "Extracted last_calc node not of type KkrCalculation: check remote_data input node"
                )
            # overwrite remote_data node with extracted remote folder
            output_remote = last_calc.outputs.remote_folder
            self.inputs.remote_data = output_remote

        if 'kkr' in inputs:
            try:
                test_and_get_codenode(inputs.kkr,
                                      'kkr.kkr',
                                      use_exceptions=True)
            except ValueError:
                input_ok = False
                return self.exit_codes.ERROR_KKRCODE_NOT_CORRECT

        # set self.ctx.input_params_KKR
        self.ctx.input_params_KKR = get_parent_paranode(
            self.inputs.remote_data)

        return input_ok
Exemplo n.º 24
0
def analyze_kpt_cross(bands_data, old_data, gap_threshold):
    """Analyze the result of kpt-cross calculation, returning the list of lowst gap and skippable points."""
    if not isinstance(bands_data, orm.BandsData):
        raise InputValidationError(
            'Invalide type {} for parameter `bands_data`'.format(
                type(bands_data)))
    if not isinstance(old_data, orm.ArrayData):
        raise InputValidationError(
            'Invalide type {} for parameter `old_data`'.format(type(old_data)))
    if not isinstance(gap_threshold, orm.Float):
        raise InputValidationError(
            'Invalide type {} for parameter `gap_threshold`'.format(
                type(gap_threshold)))

    gap_thr = gap_threshold.value
    calculation = bands_data.creator
    gaps = get_gap_array_from_PwCalc(calculation)
    kpt_cryst = bands_data.get_kpoints()

    res = orm.ArrayData()

    gaps = np.array(gaps).reshape(-1, 7)

    min_pos = np.argmin(gaps, axis=1)
    min_gap = np.min(gaps, axis=1)

    app = np.where((min_pos == 3) | (min_gap < gap_thr))[0]
    new_skips = np.zeros(min_pos.shape)
    new_skips[app] = 1
    app_kpt = kpt_cryst.reshape(-1, 7, 3)
    new_kpt = app_kpt[list(range(len(min_pos))), min_pos, :]

    try:
        kpt = old_data.get_array('kpoints')
        gaps = old_data.get_array('gaps')
        skips = old_data.get_array('skips')
    except:
        kpt = new_kpt
        gaps = min_gap
        skips = new_skips
    else:
        w = np.where(skips == 0)

        kpt[w] = new_kpt
        gaps[w] = min_gap
        skips[w] = new_skips

    res.set_array('skips', skips)
    res.set_array('kpoints', kpt)
    res.set_array('gaps', gaps)

    return res
    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
        """
        # Check inputdict
        try:
            parameters = inputdict.pop(self.get_linkname('parameters'))
        except KeyError:
            raise InputValidationError("No parameters specified for this "
                                       "calculation")
        if not isinstance(parameters, MultiplyParameters):
            raise InputValidationError("parameters not of type "
                                       "MultiplyParameters")
        try:
            code = inputdict.pop(self.get_linkname('code'))
        except KeyError:
            raise InputValidationError("No code specified for this "
                                       "calculation")
        if inputdict:
            raise ValidationError("Unknown inputs besides MultiplyParameters")

        # In this example, the input file is simply a json dict.
        # Adapt for your particular code!
        input_dict = parameters.get_dict()

        # Write input to file
        input_filename = tempfolder.get_abs_path(self._INPUT_FILE_NAME)
        with open(input_filename, 'w') as infile:
            json.dump(input_dict, infile)

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

        codeinfo = CodeInfo()
        # will call ./code.py in.json out.json
        codeinfo.cmdline_params = [
            self._INPUT_FILE_NAME, self._OUTPUT_FILE_NAME
        ]
        codeinfo.code_uuid = code.uuid
        calcinfo.codes_info = [codeinfo]

        return calcinfo
Exemplo n.º 26
0
    def _prepare_for_submission(self, tempfolder, inputdict):
        from aiida.orm.calculation.job.codtools import commandline_params_from_dict
        import shutil

        try:
            cif = inputdict.pop(self.get_linkname('cif'))
        except KeyError:
            raise InputValidationError(
                "no CIF file is specified for this calculation")
        if not isinstance(cif, CifData):
            raise InputValidationError("cif is not of type CifData")

        parameters = inputdict.pop(self.get_linkname('parameters'), None)
        if parameters is None:
            parameters = ParameterData(dict={})
        if not isinstance(parameters, ParameterData):
            raise InputValidationError(
                "parameters is not of type ParameterData")

        code = inputdict.pop(self.get_linkname('code'), None)
        if code is None:
            raise InputValidationError("Code not found in input")

        self._validate_resources(**self.get_resources())

        input_filename = tempfolder.get_abs_path(self._DEFAULT_INPUT_FILE)
        shutil.copy(cif.get_file_abs_path(), input_filename)

        commandline_params = self._default_commandline_params
        commandline_params.extend(
            commandline_params_from_dict(parameters.get_dict()))

        calcinfo = CalcInfo()
        calcinfo.uuid = self.uuid
        # The command line parameters should be generated from 'parameters'
        calcinfo.local_copy_list = []
        calcinfo.remote_copy_list = []
        calcinfo.retrieve_list = [
            self._DEFAULT_OUTPUT_FILE, self._DEFAULT_ERROR_FILE
        ]
        calcinfo.retrieve_singlefile_list = []

        codeinfo = CodeInfo()
        codeinfo.cmdline_params = commandline_params
        codeinfo.stdin_name = self._DEFAULT_INPUT_FILE
        codeinfo.stdout_name = self._DEFAULT_OUTPUT_FILE
        codeinfo.stderr_name = self._DEFAULT_ERROR_FILE
        codeinfo.code_uuid = code.uuid
        calcinfo.codes_info = [codeinfo]

        return calcinfo
Exemplo n.º 27
0
    def validate_parameters(param_data, potential_object):
        if param_data is None:
            raise InputValidationError("parameter data not set")
        validate_against_schema(param_data.get_dict(), "md.schema.json")

        # ensure the potential and paramters are in the same unit systems
        # TODO convert between unit systems (e.g. using https://pint.readthedocs.io)
        punits = param_data.get_dict()["units"]
        if not punits == potential_object.default_units:
            raise InputValidationError(
                "the units of the parameters ({}) and potential ({}) are different"
                .format(punits, potential_object.default_units))

        return True
Exemplo n.º 28
0
    def _render_section(self, output, params, indent=0):
        """
        It takes a dictionary and recurses through.

        For key-value pair it checks whether the value is a dictionary
        and prepends the key with &
        It passes the valued to the same function, increasing the indentation
        If the value is a list, I assume that this is something the user
        wants to store repetitively
        eg:
            dict['KEY'] = ['val1', 'val2']
            ===>
            KEY val1
            KEY val2

            or

            dict['KIND'] = [{'_': 'Ba', 'ELEMENT':'Ba'},
                            {'_': 'Ti', 'ELEMENT':'Ti'},
                            {'_': 'O', 'ELEMENT':'O'}]
            ====>
                  &KIND Ba
                     ELEMENT  Ba
                  &END KIND
                  &KIND Ti
                     ELEMENT  Ti
                  &END KIND
                  &KIND O
                     ELEMENT  O
                  &END KIND
        """

        for key, val in sorted(params.items()):
            if key.upper() != key:
                raise InputValidationError("keyword '%s' not upper case" % key)
            if key.startswith('@') or key.startswith('$'):
                raise InputValidationError("CP2K preprocessor not supported")
            if isinstance(val, dict):
                output.append('%s&%s %s' %
                              (' ' * indent, key, val.pop('_', '')))
                self._render_section(output, val, indent + 3)
                output.append('%s&END %s' % (' ' * indent, key))
            elif isinstance(val, list):
                for listitem in val:
                    self._render_section(output, {key: listitem}, indent)
            elif isinstance(val, bool):
                val_str = '.true.' if val else '.false.'
                output.append('%s%s  %s' % (' ' * indent, key, val_str))
            else:
                output.append('%s%s  %s' % (' ' * indent, key, val))
Exemplo n.º 29
0
    def validate_parameters(param_data, potential_object):
        if param_data is None:
            raise InputValidationError('parameter data not set')
        validate_against_schema(param_data.get_dict(), 'md-multi.schema.json')

        # ensure the potential and parameters are in the same unit systems
        # TODO convert between unit systems (e.g. using https://pint.readthedocs.io)
        punits = param_data.get_dict()['units']
        if not punits == potential_object.default_units:
            raise InputValidationError(
                f'the units of the parameters ({punits}) and potential '
                f'({potential_object.default_units}) are different')

        return True
Exemplo n.º 30
0
def load_node(identifier=None, pk=None, uuid=None, sub_class=None, query_with_dashes=True):
    """
    Load a node by one of its identifiers: pk or uuid. If the type of the identifier is unknown
    simply pass it without a keyword and the loader will attempt to infer the type

    :param identifier: pk (integer) or uuid (string)
    :param pk: pk of a node
    :param uuid: uuid of a node, or the beginning of the uuid
    :param sub_class: an optional tuple of orm classes, that should each be strict sub class of Node,
        to narrow the queryset
    :param bool query_with_dashes: allow to query for a uuid with dashes
    :returns: the node instance
    :raise InputValidationError: if none or more than one of the identifiers are supplied
    :raise TypeError: if the provided identifier has the wrong type
    :raise NotExistent: if no matching Node is found
    :raise MultipleObjectsError: if more than one Node was found
    """
    from aiida.orm.utils.loaders import IdentifierType, NodeEntityLoader

    # Verify that at least and at most one identifier is specified
    inputs_provided = [value is not None for value in (identifier, pk, uuid)].count(True)
    if inputs_provided == 0:
        raise InputValidationError("one of the parameters 'identifier', 'pk' or 'uuid' has to be specified")
    elif inputs_provided > 1:
        raise InputValidationError("only one of parameters 'identifier', 'pk' or 'uuid' has to be specified")

    if pk is not None:

        if not isinstance(pk, int):
            raise TypeError('a pk has to be an integer')

        identifier = pk
        identifier_type = IdentifierType.ID

    elif uuid is not None:

        if not isinstance(uuid, basestring):
            raise TypeError('uuid has to be a string type')

        identifier = uuid
        identifier_type = IdentifierType.UUID
    else:
        identifier = str(identifier)
        identifier_type = None

    if sub_class is not None and not isinstance(sub_class, tuple):
        sub_class = (sub_class,)

    return NodeEntityLoader.load_entity(identifier, identifier_type, sub_class, query_with_dashes)