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 """ 192 self.parent = parent
193
194 - def detach_parent(self):
195 """Remove reference to parent.""" 196 self.parent = None
197
198 - def get_sigatm(self):
199 """Return standard deviation of atomic parameters.""" 200 return self.sigatm_array
201
202 - def get_siguij(self):
203 """Return standard deviations of anisotropic temperature factors.""" 204 return self.siguij_array
205
206 - def get_anisou(self):
207 """Return anisotropic B factor.""" 208 return self.anisou_array
209
210 - def get_parent(self):
211 """Return parent residue.""" 212 return self.parent
213
214 - def get_serial_number(self):
215 return self.serial_number
216
217 - def get_name(self):
218 """Return atom name.""" 219 return self.name
220
221 - def get_id(self):
222 """Return the id of the atom (which is its atom name).""" 223 return self.id
224
225 - def get_full_id(self):
226 """Return the full id of the atom. 227 228 The full id of an atom is the tuple 229 (structure id, model id, chain id, residue id, atom name, altloc). 230 """ 231 return self.parent.get_full_id() + ((self.name, self.altloc),)
232
233 - def get_coord(self):
234 """Return atomic coordinates.""" 235 return self.coord
236
237 - def get_bfactor(self):
238 """Return B factor.""" 239 return self.bfactor
240
241 - def get_occupancy(self):
242 """Return occupancy.""" 243 return self.occupancy
244
245 - def get_fullname(self):
246 """Return the atom name, including leading and trailing spaces.""" 247 return self.fullname
248
249 - def get_altloc(self):
250 """Return alternative location specifier.""" 251 return self.altloc
252
253 - def get_level(self):
254 return self.level
255
256 - def transform(self, rot, tran):
257 """Apply rotation and translation to the atomic coordinates. 258 259 Example: 260 261 >>> rotation=rotmat(pi, Vector(1, 0, 0)) 262 >>> translation=array((0, 0, 1), 'f') 263 >>> atom.transform(rotation, translation) 264 265 @param rot: A right multiplying rotation matrix 266 @type rot: 3x3 Numeric array 267 268 @param tran: the translation vector 269 @type tran: size 3 Numeric array 270 """ 271 self.coord = numpy.dot(self.coord, rot) + tran
272
273 - def get_vector(self):
274 """Return coordinates as Vector. 275 276 @return: coordinates as 3D vector 277 @rtype: Vector 278 """ 279 x, y, z = self.coord 280 return Vector(x, y, z)
281
282 - def copy(self):
283 """Create a copy of the Atom. 284 285 Parent information is lost. 286 """ 287 # Do a shallow copy then explicitly copy what needs to be deeper. 288 shallow = copy.copy(self) 289 shallow.detach_parent() 290 shallow.set_coord(copy.copy(self.get_coord())) 291 shallow.xtra = self.xtra.copy() 292 return shallow
293 294
295 -class DisorderedAtom(DisorderedEntityWrapper):
296 """Contains all Atom objects that represent the same disordered atom. 297 298 One of these atoms is "selected" and all method calls not caught 299 by DisorderedAtom are forwarded to the selected Atom object. In that way, a 300 DisorderedAtom behaves exactly like a normal Atom. By default, the selected 301 Atom object represents the Atom object with the highest occupancy, but a 302 different Atom object can be selected by using the disordered_select(altloc) 303 method. 304 """ 305
306 - def __init__(self, id):
307 """Create DisorderedAtom. 308 309 Arguments: 310 - id - string, atom name 311 312 """ 313 # TODO - make this a private attribute? 314 self.last_occupancy = -999999 315 DisorderedEntityWrapper.__init__(self, id)
316 317 # Special methods 318
319 - def __repr__(self):
320 return "<Disordered Atom %s>" % self.get_id()
321
322 - def disordered_add(self, atom):
323 """Add a disordered atom.""" 324 # Add atom to dict, use altloc as key 325 atom.flag_disorder() 326 # set the residue parent of the added atom 327 residue = self.get_parent() 328 atom.set_parent(residue) 329 altloc = atom.get_altloc() 330 occupancy = atom.get_occupancy() 331 self[altloc] = atom 332 if occupancy > self.last_occupancy: 333 self.last_occupancy = occupancy 334 self.disordered_select(altloc)
335