예제 #1
0
    def _validate_keys(self, input_dict):
        """
        Validates the keys otherwise raise ValidationError. Does basic
        validation from the parent followed by validations for the
        quantum numbers. Raises exceptions should the input_dict fail the
        valiation or if it contains any unsupported keywords.

        :param input_dict: the dictionary of keys to be validated
        :return validated_dict: a validated dictionary
        """
        validated_dict = super()._validate_keys(input_dict)

        # Validate m knowing the value of l
        angular_momentum = validated_dict['angular_momentum']  # l quantum number, must be there
        magnetic_number = validated_dict['magnetic_number']  # m quantum number, must be there
        if angular_momentum >= 0:
            accepted_range = [0, 2 * angular_momentum]
        else:
            accepted_range = [0, -angular_momentum]
        if magnetic_number < min(accepted_range) or magnetic_number > max(accepted_range):
            raise ValidationError(
                'the magnetic number must be in the range [{}, {}]'.format(min(accepted_range), max(accepted_range))
            )

        # Check if it is a known combination
        try:
            self.get_name_from_quantum_numbers(
                validated_dict['angular_momentum'], magnetic_number=validated_dict['magnetic_number']
            )
        except ValidationError:
            raise ValidationError('Invalid angular momentum magnetic number combination')

        return validated_dict
예제 #2
0
    def _parse_xyz_vel(self, inputstring):
        """
        Load velocities from a XYZ file.

        .. note:: The steps and symbols must be set manually before calling this
            import function as a consistency measure. See also comment for
            :py:meth:`._import_xy_pos`
        """

        from aiida.common.exceptions import ValidationError
        from aiida.common.utils import xyz_parser_iterator
        from numpy import array

        numsteps = self.numsteps
        if numsteps == 0:
            raise ValidationError(
                "steps must be set before importing positional data")

        numsites = self.numsites
        if numsites == 0:
            raise ValidationError(
                "symbols must be set before importing positional data")

        velocities = array([[list(velocity) for _, velocity in atoms]
                            for _, _, atoms in xyz_parser_iterator(inputstring)
                            ])

        if velocities.shape != (numsteps, numsites, 3):
            raise ValueError(
                "TrajectoryData.positions must have shape (s,n,3), "
                "with s=number of steps={} and "
                "n=number of symbols={}".format(numsteps, numsites))

        self.set_array('velocities', velocities)
예제 #3
0
    def _mpirun_command_validator(self, mpirun_cmd):
        """
        Validates the mpirun_command variable. MUST be called after properly
        checking for a valid scheduler.
        """
        if not isinstance(mpirun_cmd, (tuple, list)) or not (
                all(isinstance(i, basestring) for i in mpirun_cmd)):
            raise ValidationError("the mpirun_command must be a list of strings")

        try:
            job_resource_keys = self.get_scheduler()._job_resource_class.get_valid_keys()
        except MissingPluginError:
            raise ValidationError("Unable to load the scheduler for this computer")

        subst = {i: 'value' for i in job_resource_keys}
        subst['tot_num_mpiprocs'] = 'value'

        try:
            for arg in mpirun_cmd:
                arg.format(**subst)
        except KeyError as e:
            raise ValidationError("In workdir there is an unknown replacement "
                                  "field '{}'".format(e.message))
        except ValueError as e:
            raise ValidationError("Error in the string: '{}'".format(e.message))
예제 #4
0
def validate_list_of_string_tuples(val, tuple_length):
    """
    Check that:

    1. ``val`` is a list or tuple
    2. each element of the list:

      a. is a list or tuple
      b. is of length equal to the parameter tuple_length
      c. each of the two elements is a string

    Return if valid, raise ValidationError if invalid
    """
    from aiida.common.exceptions import ValidationError

    err_msg = ("the value must be a list (or tuple) "
               "of length-N list (or tuples), whose elements are strings; "
               "N={}".format(tuple_length))
    if not isinstance(val, (list, tuple)):
        raise ValidationError(err_msg)
    for f in val:
        if (not isinstance(f, (list, tuple)) or
                    len(f) != tuple_length or
                not all(isinstance(s, basestring) for s in f)):
            raise ValidationError(err_msg)

    return True
예제 #5
0
    def _validate(self, param, is_exact=True):
        """
        Used internally to verify the sanity of exclude, include lists
        """
        from aiida.orm import DataFactory, CalculationFactory

        for i in param:
            if not any([i.startswith('calculation'),
                        i.startswith('code'),
                        i.startswith('data'),
                        i == 'all',
            ]):
                raise ValidationError("Module not recognized, allow prefixes "
                                      " are: calculation, code or data")
        the_param = [i + '.' for i in param]

        factorydict = {'calculation': locals()['CalculationFactory'],
                       'data': locals()['DataFactory']}

        for i in the_param:
            base, module = i.split('.', 1)
            if base == 'code':
                if module:
                    raise ValidationError("Cannot have subclasses for codes")
            elif base == 'all':
                continue
            else:
                if is_exact:
                    try:
                        factorydict[base](module.rstrip('.'))
                    except MissingPluginError:
                        raise ValidationError("Cannot find the class to be excluded")
        return the_param
예제 #6
0
    def validate(self):
        """
        Check if the attributes and files retrieved from the DB are valid.
        Raise a ValidationError if something is wrong.

        Must be able to work even before storing: therefore, use the get_attr and similar methods
        that automatically read either from the DB or from the internal attribute cache.

        For the base class, this is always valid. Subclasses will reimplement this.
        In the subclass, always call the super().validate() method first!
        """
        if not self.get_name().strip():
            raise ValidationError("No name specified")

        self._hostname_validator(self.get_hostname())

        self._description_validator(self.get_description())

        self._enabled_state_validator(self.is_enabled())

        self._transport_type_validator(self.get_transport_type())

        self._scheduler_type_validator(self.get_scheduler_type())

        self._workdir_validator(self.get_workdir())

        try:
            mpirun_cmd = self.get_mpirun_command()
        except DbContentError:
            raise ValidationError("Error in the DB content of the transport_params")

        # To be called AFTER the validation of the scheduler
        self._mpirun_command_validator(mpirun_cmd)
    def _validate_keys(self, input_dict):
        """Validate the keys otherwise raise ValidationError.

        Does basic validation from the parent followed by validations for the
        quantum numbers. Raises exceptions should the input_dict fail the
        valiation or if it contains any unsupported keywords. :param
        input_dict: the dictionary of keys to be validated :return
        validated_dict: a validated dictionary
        """
        validated_dict = super()._validate_keys(input_dict)

        # Validate m knowing the value of l
        total_angular_momentum = validated_dict['total_angular_momentum']  # j quantum number, must be there
        angular_momentum = validated_dict['angular_momentum']  # l quantum number, must be there
        accepted_range = [abs(angular_momentum - 0.5), angular_momentum + 0.5]
        if total_angular_momentum < min(accepted_range) or total_angular_momentum > max(accepted_range):
            raise ValidationError(
                'the total angular momentum must be in the range [{}, {}]'.format(
                    min(accepted_range), max(accepted_range)
                )
            )
        magnetic_number = validated_dict['magnetic_number']  # m quantum number, must be there
        accepted_range = [-total_angular_momentum, total_angular_momentum]
        if magnetic_number < min(accepted_range) or magnetic_number > max(accepted_range):
            raise ValidationError(
                'the magnetic number must be in the range [{}, {}]'.format(min(accepted_range), max(accepted_range))
            )

        return validated_dict
예제 #8
0
def extract_cif(infile, folder, nodes_export_subfolder="nodes",
                aiida_export_subfolder="aiida", silent=False):
    """
    Extract the nodes to be imported from a TCOD CIF file. TCOD CIFs,
    exported by AiiDA, may contain an importable subset of AiiDA database,
    which can be imported. This function prepares SandboxFolder with files
    required for import.

    :param infile: file path
    :param folder: a SandboxFolder, used to extract the file tree
    :param nodes_export_subfolder: name of the subfolder for AiiDA nodes
    :param aiida_export_subfolder: name of the subfolder for AiiDA data
        inside the TCOD CIF internal file tree
    :param silent: suppress debug print
    """
    import os
    import urllib2
    import CifFile
    from aiida.common.exceptions import ValidationError
    from aiida.common.utils import md5_file, sha1_file
    from aiida.tools.dbexporters.tcod import decode_textfield

    values = CifFile.ReadCif(infile)
    values = values[values.keys()[0]] # taking the first datablock in CIF

    for i in range(0,len(values['_tcod_file_id'])-1):
        name = values['_tcod_file_name'][i]
        if not name.startswith(aiida_export_subfolder+os.sep):
            continue
        dest_path = os.path.relpath(name,aiida_export_subfolder)
        if name.endswith(os.sep):
            if not os.path.exists(folder.get_abs_path(dest_path)):
                folder.get_subfolder(folder.get_abs_path(dest_path),create=True)
            continue
        contents = values['_tcod_file_contents'][i]
        if contents == '?' or contents == '.':
            uri = values['_tcod_file_uri'][i]
            if uri is not None and uri != '?' and uri != '.':
                contents = urllib2.urlopen(uri).read()
        encoding = values['_tcod_file_content_encoding'][i]
        if encoding == '.':
            encoding = None
        contents = decode_textfield(contents,encoding)
        if os.path.dirname(dest_path) != '':
            folder.get_subfolder(os.path.dirname(dest_path)+os.sep,create=True)
        with open(folder.get_abs_path(dest_path),'w') as f:
            f.write(contents)
            f.flush()
        md5  = values['_tcod_file_md5sum'][i]
        if md5 is not None:
            if md5_file(folder.get_abs_path(dest_path)) != md5:
                raise ValidationError("MD5 sum for extracted file '{}' is "
                                      "different from given in the CIF "
                                      "file".format(dest_path))
        sha1 = values['_tcod_file_sha1sum'][i]
        if sha1 is not None:
            if sha1_file(folder.get_abs_path(dest_path)) != sha1:
                raise ValidationError("SHA1 sum for extracted file '{}' is "
                                      "different from given in the CIF "
                                      "file".format(dest_path))
def validate_n(value):
    """Validate the value of the number of radial nodes."""
    if not isinstance(value, int):
        raise ValidationError('number of radial nodes (n) must be integer')

    if value < 0 or value > 2:
        raise ValidationError('number of radial nodes (n) must be between 0 and 2')

    return value
def validate_l(value):
    """Validate the value of the angular momentum."""
    if not isinstance(value, int):
        raise ValidationError('angular momentum (l) must be integer')

    if value < 0 or value > 3:
        raise ValidationError('angular momentum (l) must be between 0 and 3')

    return value
예제 #11
0
    def _validate_keys(self, input_dict):
        """
        Checks all the input_dict and tries to validate them, to ensure
        that they have been properly set raises Exceptions indicating any
        problems that should arise during the validation

        :param input_dict: a dictionary of inputs
        :return: input_dict: the original dictionary with all validated kyes
                 now removed
        :return: validated_dict: a dictionary containing all the input keys
                 which have now been validated.
        """

        validated_dict = {}
        if '_orbital_type' in input_dict:
            raise ValidationError('You cannot manually set the _orbital_type')
        entry_point = get_entry_point_from_class(self.__class__.__module__,
                                                 self.__class__.__name__)[1]
        if entry_point is None:
            raise ValidationError(
                'Unable to detect entry point for current class {}, maybe you did not register an entry point for it?'
                .format(self.__class__))

        validated_dict['_orbital_type'] = entry_point.name

        for name, validator in self._base_fields_required:
            try:
                value = input_dict.pop(name)
            except KeyError:
                raise ValidationError(
                    "Missing required parameter '{}'".format(name))
            # This might raise ValidationError
            try:
                value = validator(value)
            except ValidationError as exc:
                raise exc.__class__("Error validating '{}': {}".format(
                    name, str(exc)))
            validated_dict[name] = value

        for name, validator, default_value in self._base_fields_optional:
            try:
                value = input_dict.pop(name)
            except KeyError:
                value = default_value
            # This might raise ValidationError
            try:
                value = validator(value)
            except ValidationError as exc:
                raise exc.__class__("Error validating '{}': {}".format(
                    name, str(exc)))
            validated_dict[name] = value

        if input_dict:
            raise ValidationError('Unknown keys: {}'.format(
                list(input_dict.keys())))
        return validated_dict
예제 #12
0
    def _validate(self):
        super(StructSettingsData, self)._validate()

        fname = self._ops_filename
        if fname not in self.get_folder_list():
            raise ValidationError("operations not set")

        try:
            validate_with_dict(self.data, self._data_schema)
        except SchemeError as err:
            raise ValidationError(err)
예제 #13
0
def validate_l(value):
    """
    Validate the value of the angular momentum
    """
    if not isinstance(value, six.integer_types):
        raise ValidationError('angular momentum (l) must be integer')

    if value < -5 or value > 3:
        raise ValidationError('angular momentum (l) must be between -5 and 3')

    return value
예제 #14
0
    def _remote_abs_path_validator(self, remote_abs_path):
        """
        Validates the remote_abs_path.
        """
        from aiida.common.exceptions import ValidationError
        import os.path

        if not os.path.isabs(remote_abs_path):
            raise ValidationError("This is not a valid absolute path")
        if not os.path.split(remote_abs_path)[1]:
            raise ValidationError("This is a folder, not an executable")
예제 #15
0
    def _validate(self):
        super(SymmetryData, self)._validate()

        fname = self._ops_filename
        if fname not in self.get_folder_list():
            raise ValidationError("operations not set")

        try:
            jsonschema.validate(self.data, self.data_schema)
        except SchemeError as err:
            raise ValidationError(err)
예제 #16
0
    def _label_validator(self, label):
        """
        Validates the label.
        """
        from aiida.common.exceptions import ValidationError

        if not label.strip():
            raise ValidationError("No label specified")

        if "@" in label:
            raise ValidationError("Can not use '@' in label")
예제 #17
0
def validate_spin(value):
    """
    Validate the value of the spin
    """
    if not isinstance(value, int):
        raise ValidationError('spin must be integer')

    if value < -1 or value > 1:
        raise ValidationError('spin must be among -1, 1 or 0 (undefined)')

    return value
def validate_j(value):
    """Validate the value of the total angular momentum."""
    if not isinstance(value, (int, float)):
        raise ValidationError('total angular momentum (j) must be float')

    if not value % 0.5 == 0.0:
        raise ValidationError('total angular momentum (j) must be a half integer')

    if value < 0.5 or value > 3.5:
        raise ValidationError('total angular momentum (j) must be between 0.5 and 3.5')

    return value
예제 #19
0
    def _validate(self):
        from aiida.common.exceptions import ValidationError

        super(RemoteData, self)._validate()

        try:
            self.get_remote_path()
        except AttributeError:
            raise ValidationError("attribute 'remote_path' not set.")

        computer = self.get_computer()
        if computer is None:
            raise ValidationError("Remote computer not set.")
예제 #20
0
파일: base.py 프로젝트: zhonger/aiida-core
    def _validate(self):
        from aiida.common.exceptions import ValidationError

        super()._validate()

        try:
            self.get_remote_path()
        except AttributeError as exception:
            raise ValidationError("attribute 'remote_path' not set.") from exception

        computer = self.computer
        if computer is None:
            raise ValidationError('Remote computer not set.')
예제 #21
0
    def _validate(self):
        super(KindData, self)._validate()

        try:
            jsonschema.validate(self.data, self.data_schema)
        except SchemeError as err:
            raise ValidationError(err)

        kinds = self.data["kind_names"]
        for key, value in self.data.items():
            if len(value) != len(kinds):
                raise ValidationError(
                    "'{}' array not the same length as 'kind_names'"
                    "".format(key))
예제 #22
0
 def array_list_checker(array_list, array_name, orb_length):
     """
     Does basic checks over everything in the array_list. Makes sure that
     all the arrays are np.ndarray floats, that the length is same as
     required_length, raises exception using array_name if there is
     a failure
     """
     if not all([isinstance(_, np.ndarray) for _ in array_list]):
         raise ValidationError(
             "{} was not composed "
             "entirely of ndarrays".format(array_name))
     if len(array_list) != orb_length:
         raise ValidationError("{} did not have the same length as the "
                               "list of orbitals".format(array_name))
예제 #23
0
    def _validate(self):
        """
        Validates MD5 hash of CIF file.
        """
        from aiida.common.exceptions import ValidationError

        super(CifData, self)._validate()

        try:
            attr_md5 = self.get_attribute('md5')
        except AttributeError:
            raise ValidationError("attribute 'md5' not set.")
        md5 = self.generate_md5()
        if attr_md5 != md5:
            raise ValidationError("Attribute 'md5' says '{}' but '{}' was parsed instead.".format(attr_md5, md5))
예제 #24
0
    def _validate(self):
        from aiida.common.exceptions import ValidationError

        super(SinglefileData, self)._validate()

        try:
            filename = self.filename
        except AttributeError:
            raise ValidationError("attribute 'filename' not set.")

        if [filename] != self.get_folder_list():
            raise ValidationError("The list of files in the folder does not "
                                  "match the 'filename' attribute. "
                                  "_filename='{}', content: {}".format(
                                      filename, self.get_folder_list()))
예제 #25
0
파일: utils.py 프로젝트: csadorf/aiida-core
def validate_key(key):
    """
    Validate the key string to check if it is valid (e.g., if it does not
    contain the separator symbol.).

    :return: None if the key is valid
    :raise ValidationError: if the key is not valid
    """
    if not isinstance(key, basestring):
        raise ValidationError("The key must be a string.")
    if not key:
        raise ValidationError("The key cannot be an empty string.")
    if _sep in key:
        raise ValidationError("The separator symbol '{}' cannot be present "
                              "in the key of this field.".format(_sep))
예제 #26
0
    def _parse_xyz_pos(self, inputstring):
        """
        Load positions from a XYZ file.

        .. note:: The steps and symbols must be set manually before calling this
            import function as a consistency measure. Even though the symbols
            and steps could be extracted from the XYZ file, the data present in
            the XYZ file may or may not be correct and the same logic would have
            to be present in the XYZ-velocities function. It was therefore
            decided not to implement it at all but require it to be set
            explicitly.

        .. usage::

            from aiida.orm.data.array.trajectory import TrajectoryData

            t = TrajectoryData()
            # get sites and number of timesteps
            t.set_array('steps', arange(ntimesteps))
            t.set_array('symbols', array([site.kind for site in s.sites]))
            t.importfile('some-calc/AIIDA-PROJECT-pos-1.xyz', 'xyz_pos')
        """

        from aiida.common.exceptions import ValidationError
        from aiida.common.utils import xyz_parser_iterator
        from numpy import array

        numsteps = self.numsteps
        if numsteps == 0:
            raise ValidationError(
                "steps must be set before importing positional data")

        numsites = self.numsites
        if numsites == 0:
            raise ValidationError(
                "symbols must be set before importing positional data")

        positions = array([[list(position) for _, position in atoms]
                           for _, _, atoms in xyz_parser_iterator(inputstring)
                           ])

        if positions.shape != (numsteps, numsites, 3):
            raise ValueError(
                "TrajectoryData.positions must have shape (s,n,3), "
                "with s=number of steps={} and "
                "n=number of symbols={}".format(numsteps, numsites))

        self.set_array('positions', positions)
예제 #27
0
def should_call_default_mpiprocs_per_machine(ctx):  # pylint: disable=invalid-name
    """
    Return True if the scheduler can accept 'default_mpiprocs_per_machine',
    False otherwise.

    If there is a problem in determining the scheduler, return True to
    avoid exceptions.
    """
    from aiida.common.exceptions import ValidationError

    scheduler_ep = ctx.params['scheduler']
    if scheduler_ep is not None:
        try:
            scheduler_cls = scheduler_ep.load()
        except ImportError:
            raise ImportError(f"Unable to load the '{scheduler_ep.name}' scheduler")
    else:
        raise ValidationError(
            'The should_call_... function should always be run (and prompted) AFTER asking for a scheduler'
        )

    job_resource_cls = scheduler_cls.job_resource_class
    if job_resource_cls is None:
        # Odd situation...
        return False

    return job_resource_cls.accepts_default_mpiprocs_per_machine()
예제 #28
0
 def set_group_name(self, gname):
     """
     Set the name of the group to be created
     """
     if not isinstance(gname, basestring):
         raise ValidationError("group name must be a string")
     self.group_name = gname
예제 #29
0
    def store(self, with_transaction=True, use_cache=None):
        """
        Store a new node in the DB, also saving its repository directory
        and attributes, and reparsing the file so that the md5 and the element
        are correctly reset.

        After being called attributes cannot be
        changed anymore! Instead, extras can be changed only AFTER calling
        this store() function.

        :note: After successful storage, those links that are in the cache, and
            for which also the parent node is already stored, will be
            automatically stored. The others will remain unstored.

        :parameter with_transaction: if False, no transaction is used. This
          is meant to be used ONLY if the outer calling function has already
          a transaction open!
        """
        from aiida.common.exceptions import ValidationError

        basis_abspath = self.get_file_abs_path()
        if not basis_abspath:
            raise ValidationError("No valid Basis Set was passed!")

        metadata, content = parse_basis(basis_abspath)
        md5sum = md5_from_string(content)

        for key, val in flatten_dict(metadata).items():
            self._set_attr(key, val)
        self._set_attr('md5', md5sum)

        return super(BasisSetData,
                     self).store(with_transaction=with_transaction,
                                 use_cache=use_cache)
예제 #30
0
 def _enabled_state_validator(cls, enabled_state):
     """
     Validates the hostname.
     """
     if not isinstance(enabled_state, bool):
         raise ValidationError("Invalid value '{}' for the enabled state, must "
                               "be a boolean".format(str(enabled_state)))