Exemplo n.º 1
0
    def validate_class_type_exclusivity(self, ff_tree):
        """Assert unique bond/angle/dihedral definitions and class lengths."""
        sections = {
            "HarmonicBondForce/Bond": 2,
            "HarmonicAngleForce/Angle": 3,
            "RBTorsionForce/Proper": 4,
        }

        errors = []
        for element, num_atoms in sections.items():
            valid_attribs = set()
            for n in range(1, num_atoms + 1):
                valid_attribs.add("class{}".format(n))
                valid_attribs.add("type{}".format(n))

            for entry in ff_tree.xpath("/ForceField/{}".format(element)):
                attribs = [
                    valid for valid in valid_attribs
                    if entry.attrib.get(valid) is not None
                ]
                if num_atoms != len(attribs):
                    error = ValidationError(
                        'Invalid number of "class" and/or "type" attributes for'
                        " {} at line {}".format(element, entry.sourceline),
                        None,
                        entry.sourceline,
                    )
                    errors.append(error)
                number_endings = Counter([a[-1] for a in attribs])
                if not all(1 == x for x in number_endings.values()):
                    error = ValidationError(
                        'Only one "class" or "type" attribute may be defined'
                        " for each atom in a bonded force. See line {}".format(
                            entry.sourceline),
                        None,
                        entry.sourceline,
                    )
                    errors.append(error)

                referenced_types = []
                for valid in valid_attribs:
                    if valid.startswith("type"):
                        atomtype = entry.attrib.get(valid)
                        if atomtype:
                            referenced_types.append(atomtype)

                for atomtype in referenced_types:
                    if atomtype not in self.atom_type_names:
                        error = ValidationError(
                            "Atom type {} is found in {} at line {} but"
                            " undefined in AtomTypes".format(
                                atomtype,
                                element.split("/")[0],
                                entry.sourceline,
                            ),
                            None,
                            entry.sourceline,
                        )
                        errors.append(error)
        raise_collected(errors)
Exemplo n.º 2
0
    def validate_smarts(self, debug):
        """ Check SMARTS definitions for missing or non-parseable """
        missing_smarts = []
        errors = []
        for entry in self.atom_types:
            smarts_string = entry.attrib.get('def')
            if not smarts_string:
                warn("You have empty smart definition(s)", ValidationWarning)
                continue
            name = entry.attrib['name']
            if smarts_string is None:
                missing_smarts.append(name)
                continue
            # make sure smarts string can be parsed
            try:
                self.smarts_parser.parse(smarts_string)
            except lark.ParseError as ex:
                if " col " in ex.args[0]:
                    column = ex.args[0][ex.args[0].find(" col ") + 5:].strip()
                    column = " at character {} of {}".format(
                        column, smarts_string)
                else:
                    column = ""

                malformed = ValidationError(
                    "Malformed SMARTS string{} on line {}".format(
                        column, entry.sourceline), ex, entry.sourceline)
                errors.append(malformed)
                continue

            # make sure referenced labels exist
            smarts_graph = SMARTSGraph(smarts_string,
                                       parser=self.smarts_parser,
                                       name=name,
                                       overrides=entry.attrib.get('overrides'))
            for atom_expr in nx.get_node_attributes(smarts_graph,
                                                    name='atom').values():
                labels = atom_expr.find_data('has_label')
                for label in labels:
                    atom_type = label.children[0][1:]
                    if atom_type not in self.atom_type_names:
                        undefined = ValidationError(
                            "Reference to undefined atomtype '{}' in SMARTS "
                            "string '{}' at line {}".format(
                                atom_type, entry.attrib['def'],
                                entry.sourceline), None, entry.sourceline)
                        errors.append(undefined)
        raise_collected(errors)
        if missing_smarts and debug:
            warn(
                "The following atom types do not have smarts definitions: {}".
                format(', '.join(missing_smarts)), ValidationWarning)
        if missing_smarts and not debug:
            warn(
                "There are {} atom types that are missing a smarts definition. "
                "To view the missing atom types, re-run with debug=True when "
                "applying the forcefield.".format(len(missing_smarts)),
                ValidationWarning)
Exemplo n.º 3
0
    def validate_class_type_exclusivity(self, ff_tree):
        sections = {
            'HarmonicBondForce/Bond': 2,
            'HarmonicAngleForce/Angle': 3,
            'RBTorsionForce/Proper': 4
        }

        errors = []
        for element, num_atoms in sections.items():
            valid_attribs = set()
            for n in range(1, num_atoms + 1):
                valid_attribs.add('class{}'.format(n))
                valid_attribs.add('type{}'.format(n))

            for entry in ff_tree.xpath('/ForceField/{}'.format(element)):
                attribs = [
                    valid for valid in valid_attribs
                    if entry.attrib.get(valid) is not None
                ]
                if num_atoms != len(attribs):
                    error = ValidationError(
                        'Invalid number of "class" and/or "type" attributes for'
                        ' {} at line {}'.format(element, entry.sourceline),
                        None, entry.sourceline)
                    errors.append(error)
                number_endings = Counter([a[-1] for a in attribs])
                if not all(1 == x for x in number_endings.values()):
                    error = ValidationError(
                        'Only one "class" or "type" attribute may be defined'
                        ' for each atom in a bonded force. See line {}'.format(
                            entry.sourceline), None, entry.sourceline)
                    errors.append(error)

                referenced_types = []
                for valid in valid_attribs:
                    if valid.startswith('type'):
                        atomtype = entry.attrib.get(valid)
                        if atomtype:
                            referenced_types.append(atomtype)

                for atomtype in referenced_types:
                    if atomtype not in self.atom_type_names:
                        error = ValidationError(
                            'Atom type {} is found in {} at line {} but'
                            ' undefined in AtomTypes'.format(
                                atomtype,
                                element.split('/')[0], entry.sourceline), None,
                            entry.sourceline)
                        errors.append(error)
        raise_collected(errors)
Exemplo n.º 4
0
 def validate_overrides(self):
     errors = []
     for entry in self.atom_types:
         overrides = entry.attrib.get('overrides')
         if not overrides:
             continue
         overridden_types = [at.strip() for at in overrides.split(',') if at]
         for atom_type in overridden_types:
             if atom_type not in self.atom_type_names:
                 undefined = ValidationError(
                     "Reference to undefined atomtype '{}' in 'overrides' "
                     "'{}' at line {}".format(atom_type, entry.attrib['overrides'], entry.sourceline),
                     None, entry.sourceline)
                 errors.append(undefined)
     raise_collected(errors)
Exemplo n.º 5
0
 def validate_overrides(self):
     errors = []
     for entry in self.atom_types:
         overrides = entry.attrib.get('overrides')
         if not overrides:
             continue
         overridden_types = [at.strip() for at in overrides.split(',') if at]
         for atom_type in overridden_types:
             if atom_type not in self.atom_type_names:
                 undefined = ValidationError(
                     "Reference to undefined atomtype '{}' in 'overrides' "
                     "'{}' at line {}".format(atom_type, entry.attrib['overrides'], entry.sourceline),
                     None, entry.sourceline)
                 errors.append(undefined)
     raise_collected(errors)
Exemplo n.º 6
0
    def validate_smarts(self, debug):
        missing_smarts = []
        errors = []
        for entry in self.atom_types:
            smarts_string = entry.attrib.get('def')
            name = entry.attrib['name']
            if smarts_string is None:
                missing_smarts.append(name)
                continue
            # make sure smarts string can be parsed
            try:
                self.smarts_parser.parse(smarts_string)
            except lark.ParseError as ex:
                if " col " in ex.args[0]:
                    column = ex.args[0][ex.args[0].find(" col ") + 5:].strip()
                    column = " at character {} of {}".format(column, smarts_string)
                else:
                    column = ""

                malformed = ValidationError(
                    "Malformed SMARTS string{} on line {}".format(column, entry.sourceline),
                    ex, entry.sourceline)
                errors.append(malformed)
                continue

            # make sure referenced labels exist
            smarts_graph = SMARTSGraph(smarts_string, parser=self.smarts_parser,
                                       name=name, overrides=entry.attrib.get('overrides'))
            for atom_expr in nx.get_node_attributes(smarts_graph, name='atom').values():
                labels = atom_expr.find_data('has_label')
                for label in labels:
                    atom_type = label.children[0][1:]
                    if atom_type not in self.atom_type_names:
                        undefined = ValidationError(
                            "Reference to undefined atomtype '{}' in SMARTS "
                            "string '{}' at line {}".format(atom_type, entry.attrib['def'], entry.sourceline),
                            None, entry.sourceline)
                        errors.append(undefined)
        raise_collected(errors)
        if missing_smarts and debug:
            warn("The following atom types do not have smarts definitions: {}".format(
                ', '.join(missing_smarts)), ValidationWarning)
        if missing_smarts and not debug:
       	    warn("There are {} atom types that are missing a smarts definition. "
                     "To view the missing atom types, re-run with debug=True when "
                     "applying the forcefield.".format(len(missing_smarts)), ValidationWarning)
Exemplo n.º 7
0
    def validate_class_type_exclusivity(self, ff_tree):
        sections = {'HarmonicBondForce/Bond': 2,
                    'HarmonicAngleForce/Angle': 3,
                    'RBTorsionForce/Proper': 4}

        errors = []
        for element, num_atoms in sections.items():
            valid_attribs = set()
            for n in range(1, num_atoms + 1):
                valid_attribs.add('class{}'.format(n))
                valid_attribs.add('type{}'.format(n))

            for entry in ff_tree.xpath('/ForceField/{}'.format(element)):
                attribs = [valid for valid in valid_attribs
                           if entry.attrib.get(valid) is not None]
                if num_atoms != len(attribs):
                    error = ValidationError(
                        'Invalid number of "class" and/or "type" attributes for'
                        ' {} at line {}'.format(element, entry.sourceline),
                        None, entry.sourceline)
                    errors.append(error)
                number_endings = Counter([a[-1] for a in attribs])
                if not all(1 == x for x in number_endings.values()):
                    error = ValidationError(
                        'Only one "class" or "type" attribute may be defined'
                        ' for each atom in a bonded force. See line {}'.format(entry.sourceline),
                        None, entry.sourceline)
                    errors.append(error)

                referenced_types = []
                for valid in valid_attribs:
                    if valid.startswith('type'):
                        atomtype = entry.attrib.get(valid)
                        if atomtype:
                            referenced_types.append(atomtype)

                for atomtype in referenced_types:
                    if atomtype not in self.atom_type_names:
                        error = ValidationError(
                            'Atom type {} is found in {} at line {} but'
                            ' undefined in AtomTypes'.format(atomtype, element.split('/')[0], entry.sourceline),
                            None, entry.sourceline)
                        errors.append(error)
        raise_collected(errors)
Exemplo n.º 8
0
    def validate_smarts(self):
        missing_smarts = []
        errors = []
        for entry in self.atom_types:
            smarts_string = entry.attrib.get('def')
            name = entry.attrib['name']
            if smarts_string is None:
                missing_smarts.append(name)
                continue
            # make sure smarts string can be parsed
            try:
                self.smarts_parser.parse(smarts_string)
            except ParseError as ex:
                if " col " in ex.args[0]:
                    column = ex.args[0][ex.args[0].find(" col ") + 5:].strip()
                    column = " at character {} of {}".format(column, smarts_string)
                else:
                    column = ""

                malformed = ValidationError(
                    "Malformed SMARTS string{} on line {}".format(column, entry.sourceline),
                    ex, entry.sourceline)
                errors.append(malformed)
                continue

            # make sure referenced labels exist
            smarts_graph = SMARTSGraph(smarts_string, parser=self.smarts_parser,
                                       name=name, overrides=entry.attrib.get('overrides'))
            for atom_expr in nx.get_node_attributes(smarts_graph, 'atom').values():
                labels = atom_expr.select('has_label')
                for label in labels:
                    atom_type = label.tail[0][1:]
                    if atom_type not in self.atom_type_names:
                        undefined = ValidationError(
                            "Reference to undefined atomtype '{}' in SMARTS "
                            "string '{}' at line {}".format(atom_type, entry.attrib['def'], entry.sourceline),
                            None, entry.sourceline)
                        errors.append(undefined)
        raise_collected(errors)
        if missing_smarts:
            warn("The following atom types do not have smarts definitions: {}".format(
                ', '.join(missing_smarts)), ValidationWarning)
Exemplo n.º 9
0
 def validate_overrides(self):
     """Assert all overrides are defined elsewhere in force field."""
     errors = []
     for entry in self.atom_types:
         overrides = entry.attrib.get("overrides")
         if not overrides:
             continue
         overridden_types = [
             at.strip() for at in overrides.split(",") if at
         ]
         for atom_type in overridden_types:
             if atom_type not in self.atom_type_names:
                 undefined = ValidationError(
                     "Reference to undefined atomtype '{}' in 'overrides' "
                     "'{}' at line {}".format(
                         atom_type,
                         entry.attrib["overrides"],
                         entry.sourceline,
                     ),
                     None,
                     entry.sourceline,
                 )
                 errors.append(undefined)
     raise_collected(errors)