Package Bio :: Package PDB :: Module Atom
[hide private]
[frames] | no frames]

Source Code for Module Bio.PDB.Atom

  1  # Copyright (C) 2002, Thomas Hamelryck (thamelry@binf.ku.dk) 
  2  # This code is part of the Biopython distribution and governed by its 
  3  # license.  Please see the LICENSE file that should have been included 
  4  # as part of this package. 
  5   
  6  """Atom class, used in Structure objects.""" 
  7   
  8  import numpy 
  9  import warnings 
 10  import copy 
 11   
 12  from Bio.PDB.Entity import DisorderedEntityWrapper 
 13  from Bio.PDB.PDBExceptions import PDBConstructionWarning 
 14  from Bio.PDB.Vector import Vector 
 15  from Bio.Data import IUPACData 
 16   
 17   
18 -class Atom(object):
19 - def __init__(self, name, coord, bfactor, occupancy, altloc, fullname, serial_number, 20 element=None):
21 """Create Atom object. 22 23 The Atom object stores atom name (both with and without spaces), 24 coordinates, B factor, occupancy, alternative location specifier 25 and (optionally) anisotropic B factor and standard deviations of 26 B factor and positions. 27 28 @param name: atom name (eg. "CA"). Note that spaces are normally stripped. 29 @type name: string 30 31 @param coord: atomic coordinates (x,y,z) 32 @type coord: Numeric array (Float0, size 3) 33 34 @param bfactor: isotropic B factor 35 @type bfactor: number 36 37 @param occupancy: occupancy (0.0-1.0) 38 @type occupancy: number 39 40 @param altloc: alternative location specifier for disordered atoms 41 @type altloc: string 42 43 @param fullname: full atom name, including spaces, e.g. " CA ". Normally 44 these spaces are stripped from the atom name. 45 @type fullname: string 46 47 @param element: atom element, e.g. "C" for Carbon, "HG" for mercury, 48 @type element: uppercase string (or None if unknown) 49 """ 50 self.level = "A" 51 # Reference to the residue 52 self.parent = None 53 # the atomic data 54 self.name = name # eg. CA, spaces are removed from atom name 55 self.fullname = fullname # e.g. " CA ", spaces included 56 self.coord = coord 57 self.bfactor = bfactor 58 self.occupancy = occupancy 59 self.altloc = altloc 60 self.full_id = None # (structure id, model id, chain id, residue id, atom id) 61 self.id = name # id of atom is the atom name (e.g. "CA") 62 self.disordered_flag = 0 63 self.anisou_array = None 64 self.siguij_array = None 65 self.sigatm_array = None 66 self.serial_number = serial_number 67 # Dictionary that keeps additional properties 68 self.xtra = {} 69 assert not element or element == element.upper(), element 70 self.element = self._assign_element(element) 71 self.mass = self._assign_atom_mass()
72
73 - def _assign_element(self, element):
74 """Tries to guess element from atom name if not recognised.""" 75 if not element or element.capitalize() not in IUPACData.atom_weights: 76 # Inorganic elements have their name shifted left by one position 77 # (is a convention in PDB, but not part of the standard). 78 # isdigit() check on last two characters to avoid mis-assignment of 79 # hydrogens atoms (GLN HE21 for example) 80 81 if self.fullname[0].isalpha() and not self.fullname[2:].isdigit(): 82 putative_element = self.name.strip() 83 else: 84 # Hs may have digit in [0] 85 if self.name[0].isdigit(): 86 putative_element = self.name[1] 87 else: 88 putative_element = self.name[0] 89 90 if putative_element.capitalize() in IUPACData.atom_weights: 91 msg = "Used element %r for Atom (name=%s) with given element %r" \ 92 % (putative_element, self.name, element) 93 element = putative_element 94 else: 95 msg = "Could not assign element %r for Atom (name=%s) with given element %r" \ 96 % (putative_element, self.name, element) 97 element = "" 98 warnings.warn(msg, PDBConstructionWarning) 99 100 return element
101
102 - def _assign_atom_mass(self):
103 # Needed for Bio/Struct/Geometry.py C.O.M. function 104 if self.element: 105 return IUPACData.atom_weights[self.element.capitalize()] 106 else: 107 return float('NaN')
108 109 # Special methods 110
111 - def __repr__(self):
112 """Print Atom object as <Atom atom_name>.""" 113 return "<Atom %s>" % self.get_id()
114
115 - def __sub__(self, other):
116 """Calculate distance between two atoms. 117 118 Example: 119 >>> distance=atom1-atom2 120 121 @param other: the other atom 122 @type other: L{Atom} 123 """ 124 diff = self.coord - other.coord 125 return numpy.sqrt(numpy.dot(diff, diff))
126 127 # set methods 128
129 - def set_serial_number(self, n):
130 self.serial_number = n
131
132 - def set_bfactor(self, bfactor):
133 self.bfactor = bfactor
134
135 - def set_coord(self, coord):
136 self.coord = coord
137
138 - def set_altloc(self, altloc):
139 self.altloc = altloc
140
141 - def set_occupancy(self, occupancy):
142 self.occupancy = occupancy
143
144 - def set_sigatm(self, sigatm_array):
145 """Set standard deviation of atomic parameters. 146 147 The standard deviation of atomic parameters consists 148 of 3 positional, 1 B factor and 1 occupancy standard 149 deviation. 150 151 @param sigatm_array: standard deviations of atomic parameters. 152 @type sigatm_array: Numeric array (length 5) 153 """ 154 self.sigatm_array = sigatm_array
155
156 - def set_siguij(self, siguij_array):
157 """Set standard deviations of anisotropic temperature factors. 158 159 @param siguij_array: standard deviations of anisotropic temperature factors. 160 @type siguij_array: Numeric array (length 6) 161 """ 162 self.siguij_array = siguij_array
163
164 - def set_anisou(self, anisou_array):
165 """Set anisotropic B factor. 166 167 @param anisou_array: anisotropic B factor. 168 @type anisou_array: Numeric array (length 6) 169 """ 170 self.anisou_array = anisou_array
171 172 # Public methods 173
174 - def flag_disorder(self):
175 """Set the disordered flag to 1. 176 177 The disordered flag indicates whether the atom is disordered or not. 178 """ 179 self.disordered_flag = 1
180
181 - def is_disordered(self):
182 """Return the disordered flag (1 if disordered, 0 otherwise).""" 183 return self.disordered_flag
184
185 - def set_parent(self, parent):
186 """Set the parent residue. 187 188 Arguments: 189 - parent - Residue object 190 """ 191 self.parent = parent
192
193 - def detach_parent(self):
194 """Remove reference to parent.""" 195 self.parent = None
196
197 - def get_sigatm(self):
198 """Return standard deviation of atomic parameters.""" 199 return self.sigatm_array
200
201 - def get_siguij(self):
202 """Return standard deviations of anisotropic temperature factors.""" 203 return self.siguij_array
204
205 - def get_anisou(self):
206 """Return anisotropic B factor.""" 207 return self.anisou_array
208
209 - def get_parent(self):
210 """Return parent residue.""" 211 return self.parent
212
213 - def get_serial_number(self):
214 return self.serial_number
215
216 - def get_name(self):
217 """Return atom name.""" 218 return self.name
219
220 - def get_id(self):
221 """Return the id of the atom (which is its atom name).""" 222 return self.id
223
224 - def get_full_id(self):
225 """Return the full id of the atom. 226 227 The full id of an atom is the tuple 228 (structure id, model id, chain id, residue id, atom name, altloc). 229 """ 230 return self.parent.get_full_id() + ((self.name, self.altloc),)
231
232 - def get_coord(self):
233 """Return atomic coordinates.""" 234 return self.coord
235
236 - def get_bfactor(self):
237 """Return B factor.""" 238 return self.bfactor
239
240 - def get_occupancy(self):
241 """Return occupancy.""" 242 return self.occupancy
243
244 - def get_fullname(self):
245 """Return the atom name, including leading and trailing spaces.""" 246 return self.fullname
247
248 - def get_altloc(self):
249 """Return alternative location specifier.""" 250 return self.altloc
251
252 - def get_level(self):
253 return self.level
254
255 - def transform(self, rot, tran):
256 """Apply rotation and translation to the atomic coordinates. 257 258 Example: 259 >>> rotation=rotmat(pi, Vector(1, 0, 0)) 260 >>> translation=array((0, 0, 1), 'f') 261 >>> atom.transform(rotation, translation) 262 263 @param rot: A right multiplying rotation matrix 264 @type rot: 3x3 Numeric array 265 266 @param tran: the translation vector 267 @type tran: size 3 Numeric array 268 """ 269 self.coord = numpy.dot(self.coord, rot) + tran
270
271 - def get_vector(self):
272 """Return coordinates as Vector. 273 274 @return: coordinates as 3D vector 275 @rtype: Vector 276 """ 277 x, y, z = self.coord 278 return Vector(x, y, z)
279
280 - def copy(self):
281 """Create a copy of the Atom. 282 283 Parent information is lost. 284 """ 285 # Do a shallow copy then explicitly copy what needs to be deeper. 286 shallow = copy.copy(self) 287 shallow.detach_parent() 288 shallow.set_coord(copy.copy(self.get_coord())) 289 shallow.xtra = self.xtra.copy() 290 return shallow
291 292
293 -class DisorderedAtom(DisorderedEntityWrapper):
294 """Contains all Atom objects that represent the same disordered atom. 295 296 One of these atoms is "selected" and all method calls not caught 297 by DisorderedAtom are forwarded to the selected Atom object. In that way, a 298 DisorderedAtom behaves exactly like a normal Atom. By default, the selected 299 Atom object represents the Atom object with the highest occupancy, but a 300 different Atom object can be selected by using the disordered_select(altloc) 301 method. 302 """
303 - def __init__(self, id):
304 """Create DisorderedAtom. 305 306 Arguments: 307 - id - string, atom name 308 """ 309 # TODO - make this a private attribute? 310 self.last_occupancy = -999999 311 DisorderedEntityWrapper.__init__(self, id)
312 313 # Special methods 314
315 - def __repr__(self):
316 return "<Disordered Atom %s>" % self.get_id()
317
318 - def disordered_add(self, atom):
319 """Add a disordered atom.""" 320 # Add atom to dict, use altloc as key 321 atom.flag_disorder() 322 # set the residue parent of the added atom 323 residue = self.get_parent() 324 atom.set_parent(residue) 325 altloc = atom.get_altloc() 326 occupancy = atom.get_occupancy() 327 self[altloc] = atom 328 if occupancy > self.last_occupancy: 329 self.last_occupancy = occupancy 330 self.disordered_select(altloc)
331