Skip to content

Commit a312060

Browse files
committed
Merge pull request #223 from GreenGroup/universalDatabase
Universal database tests all seem to be working. Still need the databaseTester.py script to be removed, once all its features have been turned into unit tests.
2 parents 1bdcdc0 + b093ca7 commit a312060

7 files changed

Lines changed: 368 additions & 68 deletions

File tree

.travis.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ before_install:
99
# - sudo apt-get install python-rdkit librdkit-dev librdkit1 rdkit-data
1010
- sudo apt-get install -qq python-numpy python-scipy python-matplotlib
1111
- cd ..
12-
- git clone https://github.com/GreenGroup/RMG-database.git
12+
# the following line should not have "--branch universalDatabase" when it is on the master branch
13+
- git clone https://github.com/GreenGroup/RMG-database.git --branch universalDatabase
1314
- git clone https://github.com/GreenGroup/PyDAS.git
1415
- git clone https://github.com/GreenGroup/PyDQED.git
1516
# RDKit, based on https://github.com/rdkit/rdkit/blob/master/.travis.yml

databaseTester.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""
2+
This scripts runs tests on the database
3+
"""
4+
import os.path
5+
import logging
6+
7+
from rmgpy import settings
8+
from rmgpy.data.rmg import RMGDatabase
9+
10+
def checkFamilies(FullDatabase):
11+
databaseLog=logging.getLogger('databaseLog')
12+
familyStatus={}
13+
for family in FullDatabase.kinetics.families:
14+
databaseLog.error('\nChecking ' + family + "...")
15+
print 'Checking ' + family + "..."
16+
familyStatus[family]=FullDatabase.kinetics.families[family].checkWellFormed()
17+
18+
if __name__ == '__main__':
19+
# Set up paths for database and logger
20+
databaseDirectory = settings['database.directory'] # RMG-database/input
21+
logPath = os.path.join(databaseDirectory, '..', 'database.log')
22+
#clear logger if it exists
23+
if os.path.exists(logPath):
24+
with open(logPath, 'w'):
25+
pass
26+
databaseLog=logging.getLogger('databaseLog')
27+
fh=logging.FileHandler(logPath)
28+
fh.setLevel(logging.DEBUG)
29+
databaseLog.addHandler(fh)
30+
databaseLog.propagate=False #prevents these logging messages to being sent to ancestors (so that it doesn't print on console)
31+
# logging.basicConfig(filename=logpath, level=logging.ERROR)
32+
33+
FullDatabase=RMGDatabase()
34+
FullDatabase.load(databaseDirectory, kineticsFamilies='all')
35+
checkFamilies(FullDatabase)
36+

rmgpy/data/base.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -906,6 +906,49 @@ def checkWellFormed(self):
906906
notInTree=list(set(notInTree))
907907

908908
return (noGroup, noMatchingGroup, notInTree, notSubgroup, probablyProduct)
909+
910+
def matchNodeToNode(self, node, nodeOther):
911+
"""
912+
Return `True` if `node` and `nodeOther` are identical. Otherwise, return `False`.
913+
Both `node` and `nodeOther` must be Entry types with items containing Group or LogicNode types.
914+
"""
915+
if isinstance(node.item, Group) and isinstance(nodeOther.item, Group):
916+
return self.matchNodeToStructure(node,nodeOther.item, atoms=nodeOther.item.getLabeledAtoms()) and self.matchNodeToStructure(nodeOther,node.item,atoms=node.item.getLabeledAtoms())
917+
elif isinstance(node.item,LogicOr) and isinstance(nodeOther.item,LogicOr):
918+
return node.item.matchToLogicOr(nodeOther.item)
919+
else:
920+
# Assume nonmatching
921+
return False
922+
923+
def matchNodeToChild(self, parentNode, childNode):
924+
"""
925+
Return `True` if `parentNode` is a parent of `childNode`. Otherwise, return `False`.
926+
Both `parentNode` and `childNode` must be Entry types with items containing Group or LogicNode types.
927+
If `parentNode` and `childNode` are identical, the function will also return `False`.
928+
"""
929+
930+
if isinstance(parentNode.item, Group) and isinstance(childNode.item, Group):
931+
if self.matchNodeToStructure(parentNode,childNode.item, atoms=childNode.item.getLabeledAtoms()) is True:
932+
if self.matchNodeToStructure(childNode,parentNode.item, atoms=parentNode.item.getLabeledAtoms()) is False:
933+
return True
934+
return False
935+
936+
elif isinstance(parentNode.item,LogicOr) and isinstance(childNode.item,Group):
937+
if self.matchNodeToStructure(parentNode,childNode.item, atoms=childNode.item.getLabeledAtoms()) is True:
938+
return True
939+
else:
940+
return False
941+
elif isinstance(parentNode.item,LogicOr) and isinstance(childNode.item,LogicOr):
942+
if parentNode.item.matchToLogicOr(childNode.item):
943+
# the two LogicOrs are identical
944+
return False
945+
else:
946+
for group in parentNode.item.components:
947+
if group not in childNode.item.components:
948+
return False
949+
return True
950+
else:
951+
return False
909952

910953
def matchNodeToStructure(self, node, structure, atoms):
911954
"""
@@ -917,6 +960,15 @@ def matchNodeToStructure(self, node, structure, atoms):
917960
include extra labels, and so we only require that every labeled atom in
918961
the functional group represented by `node` has an equivalent labeled
919962
atom in `structure`.
963+
964+
Matching to structure is more strict than to node. All labels in structure must
965+
be found in node. However the reverse is not true.
966+
967+
Usage: node = either an Entry or a key in the self.entries dictionary which has
968+
a Group or LogicNode as its Entry.item
969+
structure = a Group or a Molecule
970+
atoms = dictionary of {label: atom} in the structure. A possible dictionary
971+
is the one produced by structure.getLabeledAtoms()
920972
"""
921973
if isinstance(node, str): node = self.entries[node]
922974
group = node.item

rmgpy/data/baseTest.py

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
4+
import os
5+
import unittest
6+
from external.wip import work_in_progress
7+
8+
from rmgpy import settings
9+
from rmgpy.data.base import Entry, Database
10+
from rmgpy.molecule import Group, Molecule
11+
12+
################################################################################
13+
14+
class TestBaseDatabase(unittest.TestCase):
15+
"""
16+
Contains unit tests for the base class of rmgpy.data.
17+
"""
18+
19+
20+
def setUp(self):
21+
"""
22+
A function run before each unit test in this class.
23+
"""
24+
# Set up a dummy database
25+
self.database = Database()
26+
27+
28+
def testMatchNodeToStructure(self):
29+
"""
30+
Test that the MatchNodeToStructure family works properly.
31+
"""
32+
entry1 = Entry(
33+
item = Group().fromAdjacencyList(
34+
"""
35+
1 *3 C 1 {2,D} {3,S}
36+
2 C 0 {1,D}
37+
3 *5 Cd 0 {1,S} {4,D}
38+
4 C 0 {3,D}
39+
""")
40+
)
41+
42+
entry2 = Entry(
43+
item= Group().fromAdjacencyList(
44+
"""
45+
1 *3 C 1 {2,D} {3,S}
46+
2 *5 C 0 {1,D}
47+
3 Cd 0 {1,S} {4,D}
48+
4 C 0 {3,D}
49+
""")
50+
)
51+
52+
entry3 = Entry(
53+
item = Group().fromAdjacencyList(
54+
"""
55+
1 *3 C 1 {2,D} {3,S}
56+
2 C 0 {1,D}
57+
3 Cd 0 {1,S} {4,D}
58+
4 C 0 {3,D}
59+
""")
60+
)
61+
# The group should match to itself
62+
self.assertTrue(self.database.matchNodeToStructure(entry1,entry1.item,atoms=entry1.item.getLabeledAtoms()))
63+
64+
# These groups should not match each other
65+
self.assertFalse(self.database.matchNodeToStructure(entry1,entry2.item,atoms=entry2.item.getLabeledAtoms()))
66+
67+
# entry1 contains more labels than entry3, therefore cannot be matched by entry3
68+
self.assertFalse(self.database.matchNodeToStructure(entry3,entry1.item,atoms=entry1.item.getLabeledAtoms()))
69+
70+
# entry3 contains fewer labels than entry1, therefore it can be matched
71+
self.assertTrue(self.database.matchNodeToStructure(entry1,entry3.item,atoms=entry3.item.getLabeledAtoms()))
72+
73+
def testMatchNodeToNode(self):
74+
"""
75+
Test that nodes can match other nodes.
76+
"""
77+
entry1 = Entry(
78+
item = Group().fromAdjacencyList(
79+
"""
80+
1 *1 R!H 1
81+
""")
82+
)
83+
84+
entry2 = Entry(
85+
item= Group().fromAdjacencyList(
86+
"""
87+
1 *1 Cb 1
88+
""")
89+
)
90+
self.assertTrue(self.database.matchNodeToNode(entry1,entry1))
91+
self.assertFalse(self.database.matchNodeToNode(entry1,entry2))
92+
################################################################################
93+
94+
if __name__ == '__main__':
95+
unittest.main(testRunner=unittest.TextTestRunner(verbosity=2))
96+

0 commit comments

Comments
 (0)