-
Notifications
You must be signed in to change notification settings - Fork 8
/
oniomatoms.py
186 lines (170 loc) · 6.4 KB
/
oniomatoms.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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
import numpy as np
from AaronTools.atoms import Atom
from AaronTools.const import ATOM_TYPES, CONNECTIVITY, EIJ, ELEMENTS, MASS, RADII, RIJ
class OniomAtom(Atom):
def __init__(self, element="", coords=[], flag=False, name="", tags=None, layer=None, atomtype=None, charge=None, link_info=None, res = "", atom=None):
super().__init__(element="", coords=[], flag=False, name="", tags=None)
atomtype = str(atomtype).strip()
if layer:
layer = str(layer).strip().upper()
if atom != None and isinstance(atom, Atom):
self.element = atom.element
self.coords = atom.coords
self.flag = atom.flag
self.name = atom.name
self.tags = atom.tags
if hasattr(atom, "layer") and not layer:
self.layer = atom.layer
else:
self.layer = layer
if hasattr(atom, "charge") and not charge:
self.charge = atom.charge
else:
self.charge = float(charge)
if hasattr(atom, "atomtype") and not atomtype:
self.atomtype = atom.atomtype
else:
self.atomtype = atomtype
if hasattr(atom, "link_info") and link_info == None:
self.link_info = atom.link_info
elif not hasattr(atom, "link_info") and link_info == None:
self.link_info = dict()
else:
self.link_info = link_info
if coords:
self.coords = np.array(coords, dtype=float)
if name:
self.name = str(name).strip()
if tags:
self.add_tag(tags)
if atom.connected == []:
self.connected = set([])
else:
self.connected = atom.connected # change the connected atoms to OniomAtom type
if atom.constraint == []:
self.constraint == set([])
else:
self.contraint = atom.constraint
if atom._rank == None:
self._rank = None
else:
self._rank = atom._rank
if hasattr(atom, "res") and not res:
self.res = atom.res
else:
self.res = res
element = str(element).strip().capitalize()
if element == "" and atom == None:
self.element = element
elif element in ELEMENTS:
self.element = element
elif element == "" and atom != None:
pass
else:
raise ValueError("Unknown element detected:", element)
if atom == None:
self.coords = np.array(coords, dtype=float)
self.flag = bool(flag)
self.name = str(name).strip()
if hasattr(tags, "__iter__") and not isinstance(tags, str) and atom == None:
self.tags.update(tags)
elif tags is not None:
self.tags.update([tags])
if link_info == None:
self.link_info = dict()
else:
self.link_info = link_info
self.connected = set([])
self.constraint = set([])
self._rank = None
self.res = res
#charge=str(charge).strip()
if charge == "" or charge == None:
pass
else:
self.charge = float(str(charge).strip())
self.layer=layer
self.atomtype=atomtype
def __repr__(self):
s = ""
s += "{:>3s} ".format(self.element)
for c in self.coords:
s += "{: 13.8f} ".format(c)
s += " {: 2d} ".format(-1 if self.flag else 0)
s += "{}".format(self.name)
s += " {}".format(self.layer)
try:
s += " {}".format(self.atomtype)
except AttributeError:
pass
try:
s += " {}".format(self.charge)
except AttributeError:
pass
try:
s += " {}".format(self.tags)
except AttributeError:
pass
return s
def __gt__(self, other):
""" sorts by the layer the atom is in, with atoms in High layer considered greater than those in Medium and Low"""
if not isinstance(other, OniomAtom):
raise TypeError("cannot compare atoms of different type")
if self.layer == "H" and other.layer != "H":
return True
elif self.layer == "M" and other.layer not in ("H", "M"):
return True
else:
return False
class ChargeSum:
def __init__(self):
pass
@classmethod
def get(cls, atomlist):
"""sums charges in list of atoms of OniomAtom type."""
totalcharge=[]
if isinstance(atomlist, (list, tuple, np.ndarray)):
for atom in atomlist:
if isinstance(atom, OniomAtom):
totalcharge=np.append(totalcharge, atom.charge)
else:
raise TypeError("each atom in list must be an OniomAtom")
return np.sum(totalcharge)
else:
raise TypeError("function only accepts a list, tuple, or array of atoms")
class OniomSanity:
def __init__(self):
pass
@classmethod
def check_charges(cls, atomlist, targetcharge, threshold=""):
"""returns True if sum of charges is equal to expected value within threshold"""
if threshold == "":
threshold=float(10**(-1))
else:
threshold=float(threshold)
targetcharge = float(targetcharge)
return abs(ChargeSum.get(atomlist)-targetcharge) < threshold
@classmethod
def check_types(cls,atomlist):
"""returns True if atomtypes in atomlist are all in reference"""
counter = 0
for atom in atomlist:
if hasattr(atom,"atomtype"):
counter+=1
if atom.atomtype in ATOM_TYPES:
continue
else:
return False
return counter == len(atomlist)
@classmethod
def check_layers(cls, atomlist):
"""returns True if layers are defined correctly as either H, L, or M"""
counter=0
for atom in atomlist:
if hasattr(atom,"layer"):
counter+=1
if atom.layer in ("H", "M", "L"):
continue
else:
return False
return counter==len(atomlist)