|
38 | 38 | from copy import copy, deepcopy
|
39 | 39 |
|
40 | 40 | from rmgpy.data.base import Database, Entry, LogicNode, LogicOr, ForbiddenStructures,\
|
41 |
| - ForbiddenStructureException, getAllCombinations |
| 41 | + ForbiddenStructureException, getAllCombinations, DatabaseError |
42 | 42 | from rmgpy.reaction import Reaction
|
43 | 43 | from rmgpy.kinetics import Arrhenius, ArrheniusEP, ThirdBody, Lindemann, Troe, \
|
44 | 44 | PDepArrhenius, MultiArrhenius, MultiPDepArrhenius, \
|
@@ -1941,3 +1941,148 @@ def getRateCoefficientUnits(self):
|
1941 | 1941 | return 's^-1'
|
1942 | 1942 | else:
|
1943 | 1943 | raise ValueError('Unable to determine units of rate coefficient for reaction family "{0}".'.format(self.label))
|
| 1944 | + |
| 1945 | + def checkWellFormed(self): |
| 1946 | + """ |
| 1947 | + Returns a tuple of malformed database entries: |
| 1948 | + |
| 1949 | + noGroup is a list of nodes in the rules that has no corresponding group in |
| 1950 | + groups.py |
| 1951 | + |
| 1952 | + noMatchingGroup is a dictionary with entry labels from the rules as a key |
| 1953 | + and entry labels from groups as values. These are groups where rule.py's |
| 1954 | + adj list does not match group.py's. |
| 1955 | + |
| 1956 | + notInTree is a list of groups that do not appear in the tree |
| 1957 | + |
| 1958 | + notSubgroup is a dictionary with group labels as keys and atom indexes |
| 1959 | + as values. Each key is a group where the child's adj list is not a |
| 1960 | + true child of it's parent. The list of indexes corresponds to the |
| 1961 | + child's adj list index, where the atom is not a true child. |
| 1962 | + |
| 1963 | + probablyProduct is a list of groups which do not apepar in the |
| 1964 | + tree, but are probably products (as opposed to reactants) which |
| 1965 | + are created in the database loading. These are not necessarily |
| 1966 | + malformations, but because I'm not certain where they came from, |
| 1967 | + I decided to list them. |
| 1968 | + """ |
| 1969 | + |
| 1970 | + |
| 1971 | + #A function to add to the not in Subgroup dictionary |
| 1972 | + def appendToDict(dictionary, key, value): |
| 1973 | + if key not in dictionary: |
| 1974 | + dictionary[key]=[value] |
| 1975 | + else: |
| 1976 | + dictionary[key].append(value) |
| 1977 | + return dictionary |
| 1978 | + |
| 1979 | + #list of nodes that are not wellFormed |
| 1980 | + noGroup=[] |
| 1981 | + noMatchingGroup={} |
| 1982 | + tempNoMatchingGroup={} |
| 1983 | + notInTree=[] |
| 1984 | + notUnique={} |
| 1985 | + notSubgroup={} |
| 1986 | + probablyProduct=[] |
| 1987 | + |
| 1988 | + # Give correct arguments for each type of database |
| 1989 | +# if isinstance(self, KineticsFamily): |
| 1990 | + library=self.rules.entries |
| 1991 | + groups=self.groups.entries |
| 1992 | + groupsCopy=copy(groups) |
| 1993 | + topNodes=self.getRootTemplate() |
| 1994 | + |
| 1995 | + # Make list of all node names in library |
| 1996 | + libraryNodes=[] |
| 1997 | + for nodes in library: |
| 1998 | + libraryNodes.append(nodes) |
| 1999 | + |
| 2000 | + try: |
| 2001 | + #Each label in rules.py should be be in the form group1;group2;group3 etc |
| 2002 | + #and each group must appear in groups.py |
| 2003 | + for libraryNode in libraryNodes: |
| 2004 | + nodes=libraryNode.split(';') |
| 2005 | + for libraryEntry in library[libraryNode]: |
| 2006 | + for nodeName in nodes: |
| 2007 | + if nodeName not in groups: |
| 2008 | + noGroup.append(nodeName) |
| 2009 | + #If the node is not in the dictionary, we can't do the rest of the check |
| 2010 | + continue |
| 2011 | + #Each adj list in rules.py should match the adj list in group's.py |
| 2012 | + for libraryGroup in libraryEntry.item.reactants: |
| 2013 | + #break if we find a match between two groups |
| 2014 | + if isinstance(groups[nodeName].item, Group) and isinstance(libraryGroup, Group): |
| 2015 | + if groups[nodeName].item.isIsomorphic(libraryGroup): |
| 2016 | + break |
| 2017 | + #break if we find a match between two logic nodes |
| 2018 | + elif isinstance(groups[nodeName].item, LogicOr) and isinstance(libraryGroup, LogicOr): |
| 2019 | + if groups[nodeName].item.matchToLogicOr(libraryGroup): |
| 2020 | + break |
| 2021 | + #Otherwise no match is found, so we add it to the tempNoMatchingGroup |
| 2022 | + else: |
| 2023 | + tempNoMatchingGroup=appendToDict(tempNoMatchingGroup, libraryNode, nodeName) |
| 2024 | + #eliminate duplicates |
| 2025 | + for key, nodeList in tempNoMatchingGroup.iteritems(): |
| 2026 | + noMatchingGroup[key]=list(set(nodeList)) |
| 2027 | + |
| 2028 | + # Each group in groups.py should appear in the tree |
| 2029 | + # This is true when ascending through parents leads to a top node |
| 2030 | + for nodeName in groups: |
| 2031 | + nodeGroup=self.groups.entries[nodeName] |
| 2032 | + nodeGroupItem=nodeGroup.item |
| 2033 | + ascendParent=nodeGroup |
| 2034 | + while ascendParent not in topNodes: |
| 2035 | + child=ascendParent |
| 2036 | + ascendParent=ascendParent.parent |
| 2037 | + if ascendParent is None or child not in ascendParent.children: |
| 2038 | + if child.index==-1: |
| 2039 | + probablyProduct.append(child.label) |
| 2040 | + break |
| 2041 | + else: |
| 2042 | + # If a group is not in a tree, we want to save the uppermost parent, not necessarily the original node |
| 2043 | + notInTree.append(child.label) |
| 2044 | + break |
| 2045 | + |
| 2046 | + #each node should also be unique: |
| 2047 | + del groupsCopy[nodeName] |
| 2048 | + for nodeName2 in groupsCopy: |
| 2049 | + nodeGroup2Item=self.groups.entries[nodeName2].item |
| 2050 | + if isinstance(nodeGroup2Item, Group) and isinstance(nodeGroupItem, Group): |
| 2051 | + if nodeGroupItem.isIdentical(nodeGroup2Item): |
| 2052 | + notUnique=appendToDict(notUnique, nodeName, nodeName2) |
| 2053 | + if isinstance(nodeGroup2Item, LogicOr) and isinstance(nodeGroupItem, LogicOr): |
| 2054 | + if nodeGroupItem.matchToLogicOr(nodeGroup2Item): |
| 2055 | + notUnique=appendToDict(notUnique, nodeName, nodeName2) |
| 2056 | + |
| 2057 | + #For a correct child-parent relationship, each atom in the parent should have a corresponding child atom in the child. |
| 2058 | + nodeParent=nodeGroup.parent |
| 2059 | + #Atoms may be in a different order initially. Need to sort both child and parent first |
| 2060 | + #Don't need to do check for topNodes |
| 2061 | + if nodeParent is not None: |
| 2062 | + if isinstance(nodeParent.item, LogicOr): |
| 2063 | + if not nodeGroup.label in nodeParent.item.components: |
| 2064 | + #-1 index means the child is not in the LogicOr |
| 2065 | + notSubgroup[nodeName]=nodeParent.label |
| 2066 | + continue |
| 2067 | + else: |
| 2068 | + #if the parent is a LogicOr, we want to keep ascending until we get to a group or hit a discontinuity (could be |
| 2069 | + #malformed tree or just ascending past the top node) |
| 2070 | + while isinstance(nodeParent.item, LogicOr): |
| 2071 | + nodeParent=nodeParent.parent |
| 2072 | + if nodeParent == None: break |
| 2073 | + if nodeParent == None: continue |
| 2074 | +# nodeParent.item.sortAtoms() |
| 2075 | + elif isinstance(nodeGroup.item, LogicOr): |
| 2076 | + print nodeGroup, ' is an intermediate LogicOr. See if it can be replaced with a adj list.' |
| 2077 | + continue |
| 2078 | + #If both the parent and child are graphs, we can use the function isSubgroupIsomorphic if it is actually a child |
| 2079 | + if not nodeGroup.item.isSubgraphIsomorphic(nodeParent.item): |
| 2080 | + notSubgroup[nodeName]=nodeParent.label |
| 2081 | + except DatabaseError, e: |
| 2082 | + logging.error(str(e)) |
| 2083 | + |
| 2084 | + #eliminate duplicates |
| 2085 | + noGroup=list(set(noGroup)) |
| 2086 | + notInTree=list(set(notInTree)) |
| 2087 | + |
| 2088 | + return (noGroup, noMatchingGroup, notInTree, notUnique, notSubgroup, probablyProduct) |
0 commit comments