Пример #1
0
    def get_reaction_template(self, reaction):
        """
        For a given `reaction` with properly-labeled :class:`Molecule` objects
        as the reactants, determine the most specific nodes in the tree that
        describe the reaction.
        """

        # Get forward reaction template and remove any duplicates
        forward_template = self.top[:]

        temporary = []
        symmetric_tree = False
        for entry in forward_template:
            if entry not in temporary:
                temporary.append(entry)
            else:
                # duplicate node found at top of tree
                # eg. R_recombination: ['Y_rad', 'Y_rad']
                if len(forward_template) != 2:
                    raise DatabaseError('Can currently only do symmetric trees with nothing else in them')
                symmetric_tree = True
        forward_template = temporary

        # Descend reactant trees as far as possible
        template = []
        special_cases = ['peroxyl_disproportionation', 'bimolec_hydroperoxide_decomposition']
        if (len(forward_template) == 1 and len(reaction.reactants) > len(forward_template) and
                self.label.lower().split('/')[0] not in special_cases):
            entry = forward_template[0]
            group = entry.item

            r = None
            for react in reaction.reactants:
                if isinstance(react, Species):
                    react = react.molecule[0]
                if r:
                    r = r.merge(react)
                else:
                    r = deepcopy(react)

            atoms = r.get_all_labeled_atoms()

            matched_node = self.descend_tree(r, atoms, root=entry, strict=True)

            if matched_node is not None:
                template.append(matched_node)

        else:
            for entry in forward_template:
                # entry is a top-level node that should be matched
                group = entry.item

                # Identify the atom labels in a group if it is not a logical node
                atom_list = []
                if not isinstance(entry.item, LogicNode):
                    atom_list = group.get_all_labeled_atoms()

                for reactant in reaction.reactants:
                    if isinstance(reactant, Species):
                        reactant = reactant.molecule[0]
                    # Match labeled atoms
                    # Check that this reactant has each of the atom labels in this group.
                    # If it is a LogicNode, the atom_list is empty and
                    # it will proceed directly to the descend_tree step.
                    if not all([reactant.contains_labeled_atom(label) for label in atom_list]):
                        continue  # don't try to match this structure - the atoms aren't there!
                    # Match structures
                    atoms = reactant.get_all_labeled_atoms()
                    # Descend the tree, making sure to match atomlabels exactly using strict = True
                    matched_node = self.descend_tree(reactant, atoms, root=entry, strict=True)
                    if matched_node is not None:
                        template.append(matched_node)
                    # else:
                    #    logging.warning("Couldn't find match for {0} in {1}".format(entry,atom_list))
                    #    logging.warning(reactant.to_adjacency_list())

            # Get fresh templates (with duplicate nodes back in)
            forward_template = self.top[:]
            if (self.label.lower().startswith('peroxyl_disproportionation') or
                    self.label.lower().startswith('bimolec_hydroperoxide_decomposition')):
                forward_template.append(forward_template[0])

        # Check that we were able to match the template.
        # template is a list of the actual matched nodes
        # forward_template is a list of the top level nodes that should be matched
        if len(template) != len(forward_template):
            msg = 'Unable to find matching template for reaction {0} in reaction family {1}.'.format(str(reaction),
                                                                                                     str(self))
            msg += 'Trying to match {0} but matched {1}'.format(str(forward_template), str(template))
            raise UndeterminableKineticsError(reaction, message=msg)

        return template
Пример #2
0
    def getReactionTemplate(self, reaction):
        """
        For a given `reaction` with properly-labeled :class:`Molecule` objects
        as the reactants, determine the most specific nodes in the tree that
        describe the reaction.
        """

        # Get forward reaction template and remove any duplicates
        forwardTemplate = self.top[:]

        temporary = []
        symmetricTree = False
        for entry in forwardTemplate:
            if entry not in temporary:
                temporary.append(entry)
            else:
                # duplicate node found at top of tree
                # eg. R_recombination: ['Y_rad', 'Y_rad']
                assert len(
                    forwardTemplate
                ) == 2, 'Can currently only do symmetric trees with nothing else in them'
                symmetricTree = True
        forwardTemplate = temporary

        # Descend reactant trees as far as possible
        template = []
        for entry in forwardTemplate:
            # entry is a top-level node that should be matched
            group = entry.item

            # Identify the atom labels in a group if it is not a logical node
            atomList = []
            if not isinstance(entry.item, LogicNode):
                atomList = group.getLabeledAtoms()

            for reactant in reaction.reactants:
                if isinstance(reactant, Species):
                    reactant = reactant.molecule[0]
                # Match labeled atoms
                # Check that this reactant has each of the atom labels in this group.  If it is a LogicNode, the atomList is empty and
                # it will proceed directly to the descendTree step.
                if not all([
                        reactant.containsLabeledAtom(label)
                        for label in atomList
                ]):
                    continue  # don't try to match this structure - the atoms aren't there!
                # Match structures
                atoms = reactant.getLabeledAtoms()
                # Descend the tree, making sure to match atomlabels exactly using strict = True
                matched_node = self.descendTree(reactant,
                                                atoms,
                                                root=entry,
                                                strict=True)
                if matched_node is not None:
                    template.append(matched_node)
                #else:
                #    logging.warning("Couldn't find match for {0} in {1}".format(entry,atomList))
                #    logging.warning(reactant.toAdjacencyList())

        # Get fresh templates (with duplicate nodes back in)
        forwardTemplate = self.top[:]
        if self.label.lower().startswith('r_recombination'):
            forwardTemplate.append(forwardTemplate[0])

        # Check that we were able to match the template.
        # template is a list of the actual matched nodes
        # forwardTemplate is a list of the top level nodes that should be matched
        if len(template) != len(forwardTemplate):
            msg = 'Unable to find matching template for reaction {0} in reaction family {1}.'.format(
                str(reaction), str(self))
            msg += 'Trying to match {0} but matched {1}'.format(
                str(forwardTemplate), str(template))
            logging.debug('len(template): {0}'.format(len(template)))
            logging.debug('len(forwardTemplate): {0}'.format(
                len(forwardTemplate)))
            logging.debug('reactants:')
            for reactant in reaction.reactants:
                if isinstance(reactant, Species):
                    for mol in reactant.molecule:
                        logging.debug(mol.toAdjacencyList())
                else:
                    logging.debug(reactant.toAdjacencyList())
            logging.debug('products:')
            for product in reaction.products:
                if isinstance(product, Species):
                    for mol in product.molecule:
                        logging.debug(mol.toAdjacencyList())
                else:
                    logging.debug(product.toAdjacencyList())
            raise UndeterminableKineticsError(reaction, message=msg)

        return template