-
Notifications
You must be signed in to change notification settings - Fork 2
/
clash.py
executable file
·103 lines (96 loc) · 4.57 KB
/
clash.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#!/usr/bin/env python2.7
#Ryan G. Coleman, Brian K. Shoichet Lab
#reads in file containing clash definitions.
import string, sys
from geometry_basic import distL2Squared3
from collections import defaultdict
class Clash(object):
'''holds parameters that determine what a clashed conformation contains.
rules have the format ('min|max', bond, cmp, "X", "Y", dist) which is:
min|max - whether the constraint is a minimum or maximum
bond - how many bonds are between the atoms.
cmp - how to use the bond distance. -1 means there must be less than that many
0 means there must be exactly that many and
1 means there must be more than that many bonds between the atoms
X - atom type X, * means all
Y - atom type Y, * means all
dist - float that is the distance constraint'''
#old rules, necessary for mix'n'match, but not for simple hydroxyl rotations
# rulesDefault = [("max", 1, 0, "*", "*", 2.2),
# ("min", 3, 1, "O", "O", 2.0),
# ("min", 3, 1, "*", "*", 1.50),
# ("min", 1, 0, "O", "O", 2.0),
# ("min", 1, 0, "*", "*", 0.95)]
# rulesDefault = [("min", 2, 1, "*", "*", 1.70)]
rulesDefault = [("min", 2, 1, "H", "H", 1.70)] #only H-H!!
def __init__(self, parameterFileName=None):
'''constructs from defaults or reads from file'''
if parameterFileName is not None:
parameterFile = open(parameterFileName, 'r')
self.rules = []
try:
for line in parameterFile:
tokens = string.split(line)
self.rules.append((tokens[0], int(tokens[1]), int(tokens[2]), \
tokens[3], tokens[4], float(tokens[5]), float(tokens[5])**2.))
except StopIteration:
pass #EOF
else: #no parameter file, use defaults
self.rules = []
for defaultRule in self.rulesDefault:
ruleWithSquared = list(defaultRule)
ruleWithSquared.append(defaultRule[5]**2.)
self.rules.append(tuple(ruleWithSquared))
def printParameters(self):
'''prints to standard out the parameters used in a readable format'''
for rule in self.rules:
for part in rule[0:6]: #don't print out the distance squared term
print part,
print "" #force newline
def decide(self, mol2data, xyzData):
'''mol2data is the mol2.Mol2 object. xyzData is a list of coords.
use self.rules to return True (clashed) or False (not clashed).'''
dists = defaultdict(list) #format is atomNum -> (otherNum, dist, bondDist)
#all dists in list are euclidean distance squared
atomNums = range(len(xyzData))
atomNums.sort()
for atomNumOne in atomNums:
for atomNumTwo in atomNums:
if atomNumTwo > atomNumOne:
thisDist = distL2Squared3(xyzData[atomNumOne], xyzData[atomNumTwo])
bondDist = mol2data.bondsBetweenActual(atomNumOne, atomNumTwo)
dists[atomNumOne].append((atomNumTwo, thisDist, bondDist))
dists[atomNumTwo].append((atomNumOne, thisDist, bondDist))
for rule in self.rules:
#match atom types first
for atomNum in atomNums:
if rule[3] == "*" or \
0 == string.find(mol2data.atomType[atomNum], rule[3]):
for dist in dists[atomNum]: #for every distance
if rule[4] == "*" or \
0 == string.find(mol2data.atomType[dist[0]], rule[4]):
brokeRule = False
if rule[0] == "max": #is a max distance constraint
if dist[1] > rule[6]: #broke the rule
brokeRule = True
elif rule[0] == "min": #is a min distance constraint
if dist[1] < rule[6]: #broke the rule
brokeRule = True
if brokeRule: #check to make sure actually broken
if not cmp(dist[2], rule[1]) == rule[2]: #this basically amounts
#to checking to see if the right number of bonds lie between
#the atoms in question.
brokeRule = False
if brokeRule: #rule has been broken so there is a clash
#print rule, atomNum, dist #debug the rules broken
return True #can quit after first broken rule
#if everything passed, return False indicating no clashes
return False
if -1 != string.find(sys.argv[0], "clash.py"):
#if program is called from the command line, assume user wants a copy of the
#default parameter file written to standard out. this is the only command use.
#usually this will be imported and run from somewhere else.
if len(sys.argv) > 1:
Clash(sys.argv[1]).printParameters()
else:
Clash().printParameters()