Package mmLib :: Module Structure
[hide private]
[frames] | no frames]

Source Code for Module mmLib.Structure

   1  ## Copyright 2002-2010 by PyMMLib Development Group (see AUTHORS file) 
   2  ## This code is part of the PyMMLib distribution and governed by 
   3  ## its license.  Please see the LICENSE file that should have been 
   4  ## included as part of this package. 
   5  """Classes for representing biological macromolecules. 
   6  """ 
   7  import copy 
   8  import math 
   9  import string 
  10  import itertools 
  11   
  12  try: 
  13      import numpy 
  14      try: 
  15          from numpy.oldnumeric import linear_algebra as linalg 
  16      except ImportError: 
  17          from numpy.linalg import old as linalg 
  18  except ImportError: 
  19      import NumericCompat as numpy 
  20      from NumericCompat import linalg 
  21   
  22  import ConsoleOutput 
  23  import Constants 
  24  import GeometryDict 
  25  import AtomMath 
  26  import Library 
  27  import UnitCell 
  28  import Sequence 
  29  import mmCIFDB 
  30   
  31   
32 -class StructureError(Exception):
33 """Base class of errors raised by Structure objects. 34 """ 35 pass
36
37 -class ModelOverwrite(StructureError):
38 """Raised by Structure.add_model() when a Model added to a Structure 39 has the same model_id of a Model already in the Structure. 40 """ 41 pass
42
43 -class ChainOverwrite(StructureError):
44 """Raised by Structure.add_chain() or by Model.add_chain() when a 45 Chain added to a Structure has the same chain_id of a Chain already 46 in the Structure. 47 """ 48 pass
49
50 -class FragmentOverwrite(StructureError):
51 """Raised by Chain.add_fragment() when a Fragment added to a Chain 52 has the same fragment_id as a Fragment already in the Chain. 53 """ 54 pass
55
56 -class AtomOverwrite(StructureError):
57 """Raised by Structure.add_atom() or Fragment.add_atom() when an Atom 58 added to a Structure or Fragment has the same chain_id, fragment_id, 59 name, and alt_loc as an Atom already in the Structure or Fragment. 60 """
61 - def __init__(self, text):
62 StructureError.__init__(self) 63 self.text = text
64 - def __str__(self):
65 return self.text
66
67 -class Structure(object):
68 """The Structure object is the parent container object for the entire 69 macromolecular data structure. It contains a list of the Chain objects 70 in the structure hierarchy, and contains these additional data 71 objects: 72 73 cifdb(mmLib.mmCIFDB) A mmCIF database with additional structure data. 74 75 unit_cell(mmLib.UnitCell) Unit cell/Spacegroup for the structure. 76 77 default_alt_loc(string) The default alternate location identifier used 78 when iterating or retreiving Atom objects in the structure. 79 """
80 - def __init__(self, **args):
81 self.structure_id = args.get("structure_id") or "XXXX" 82 self.header = None 83 self.title = None 84 self.experimental_method = None 85 self.cifdb = args.get("cifdb") or mmCIFDB.mmCIFDB("XXXX") 86 87 self.unit_cell = args.get("unit_cell") or UnitCell.UnitCell() 88 89 self.default_alt_loc = "A" 90 self.default_model = None 91 self.model_list = [] 92 self.model_dict = {}
93
94 - def __str__(self):
95 return "Struct(%s)" % (self.structure_id)
96
97 - def __deepcopy__(self, memo):
98 structure = Structure( 99 cifdb = copy.deepcopy(self.cifdb, memo), 100 unit_cell = copy.deepcopy(self.unit_cell, memo)) 101 102 for model in self.model_list: 103 structure.add_model(copy.deepcopy(model, memo), True) 104 105 return structure
106
107 - def __len__(self):
108 """Returns the number of stored Chain objects. 109 """ 110 try: 111 return len(self.default_model) 112 except TypeError: 113 return 0
114
115 - def __getitem__(self, chain_idx):
116 """Same as get_chain, but raises KeyError if the requested chain_id 117 is not found. 118 """ 119 try: 120 return self.default_model[chain_idx] 121 except TypeError: 122 raise KeyError, chain_idx
123
124 - def __iter__(self):
125 """Iterates the Chain objects in the Structure. 126 """ 127 if self.default_model: 128 return iter(self.default_model.chain_list) 129 return iter(list())
130
131 - def __contains__(self, model_chain_idx):
132 """Returns True if item is a Model in the Structure, or a 133 Chain or chain_id in the default Model. 134 """ 135 if isinstance(model_chain_idx, Model): 136 return self.model_list.__contains__(model_chain_idx) 137 elif isinstance(model_chain_idx, Chain) or \ 138 isinstance(model_chain_idx, str): 139 try: 140 return self.default_model.__contains__(model_chain_idx) 141 except AttributeError: 142 raise KeyError, model_chain_idx 143 raise TypeError, model_chain_idx
144
145 - def index(self, model_chain):
146 """If item is a Model, returns the index of the Model in the 147 Structure, or if the item is a Chain, returns the index of the 148 Chain in the default Model. 149 """ 150 if isinstance(model_chain, Model): 151 return self.model_list.index(model_chain) 152 elif isinstance(model_chain, Chain): 153 try: 154 return self.default_model.index(model_chain) 155 except AttributeError: 156 raise ValueError, model_chain 157 raise TypeError, model_chain
158
159 - def sort(self):
160 """Sorts all Models and Chains in the Structure according to standard 161 model_id, chain_id, and fragment_id sorting rules. 162 """ 163 self.model_list.sort() 164 for model in self.model_list: 165 model.sort()
166
167 - def add_model(self, model, delay_sort=True):
168 """Adds a Model to a Structure. Raises the ModelOverwrite exception 169 if the model_id of the Model matches the model_id of a Model 170 already in the Structure. If there are no Models in the Structure, 171 the Model is used as the default Model. 172 """ 173 assert isinstance(model, Model) 174 175 if self.model_dict.has_key(model.model_id): 176 raise ModelOverwrite() 177 178 ## set default model if not set 179 if self.default_model is None: 180 self.default_model = model 181 182 self.model_list.append(model) 183 self.model_dict[model.model_id] = model 184 185 model.structure = self 186 187 if not delay_sort: 188 self.model_list.sort()
189
190 - def remove_model(self, model):
191 """Removes a child Model object. If the Model object is the default 192 Model, then choose the Model with the lowest model_id as the 193 new default Model, or None if there are no more Models. 194 """ 195 assert isinstance(model, Model) 196 197 self.model_list.remove(model) 198 del self.model_dict[model.model_id] 199 model.structure = None 200 201 ## if the default model is being removed, choose a new default model 202 ## if possible 203 if model == self.default_model: 204 if len(self.model_list) > 0: 205 self.default_model = self.model_list[0] 206 else: 207 self.default_model = None
208
209 - def get_model(self, model_id):
210 """Return the Model object with the argument model_id, or None if 211 not found. 212 """ 213 if self.model_dict.has_key(model_id): 214 return self.model_dict[model_id] 215 return None
216
217 - def get_default_model(self):
218 """Returns the default Model object. 219 """ 220 return self.default_model
221
222 - def set_default_model(self, model_id):
223 """Sets the default Model for the Structure to model_id. Returns 224 False if a Model with the proper model_id does 225 not exist in the Structure. 226 """ 227 try: 228 self.default_model = self.model_dict[model_id] 229 except KeyError: 230 return False 231 return False
232
233 - def set_model(self, model_id):
234 """DEP: Use set_default_model() 235 Sets the default Model for the Structure to model_id. Returns 236 False if a Model with the proper model_id does 237 not exist in the Structure. 238 """ 239 self.set_default_model(model_id)
240
241 - def iter_models(self):
242 """Iterates over all Model objects. 243 """ 244 return iter(self.model_list)
245
246 - def count_models(self):
247 """Counts all Model objects in the Structure. 248 """ 249 return len(self.model_list)
250
251 - def add_chain(self, chain, delay_sort = True):
252 """Adds a Chain object to the Structure. Creates necessary parent 253 Model if necessary. 254 """ 255 assert isinstance(chain, Chain) 256 257 try: 258 model = self.model_dict[chain.model_id] 259 except KeyError: 260 model = Model(model_id = chain.model_id) 261 self.add_model(model, delay_sort) 262 263 model.add_chain(chain, delay_sort)
264
265 - def remove_chain(self, chain):
266 """Removes a Chain object. 267 """ 268 assert isinstance(chain, Chain) 269 self.model_dict[chain.model_id].remove_chain(chain)
270
271 - def get_chain(self, chain_id):
272 """Returns the Chain object matching the chain_id character. 273 """ 274 if self.default_model is None: 275 return None 276 if self.default_model.chain_dict.has_key(chain_id): 277 return self.default_model.chain_dict[chain_id] 278 return None
279
280 - def count_chains(self):
281 """Counts all Chain objects in the default Model. 282 """ 283 if self.default_model: 284 return self.default_model.count_chains() 285 return 0
286
287 - def iter_chains(self):
288 """Iterates over all Chain objects in the default Model, in 289 alphabetical order according to their chain_id. 290 """ 291 if self.default_model: 292 return iter(self.default_model.chain_list) 293 return iter(list())
294
295 - def iter_all_chains(self):
296 """Iterates over all Chain objects in all Model objects. 297 """ 298 for model in self.model_list: 299 for chain in model.chain_list: 300 yield chain
301
302 - def add_fragment(self, fragment, delay_sort=True):
303 """Adds a Fragment object. 304 """ 305 assert isinstance(fragment, Fragment) 306 307 try: 308 model = self.model_dict[fragment.model_id] 309 except KeyError: 310 model = Model(model_id=fragment.model_id) 311 self.add_model(model, delay_sort) 312 313 model.add_fragment(fragment)
314
315 - def remove_fragment(self, fragment):
316 """Removes a Fragment object. 317 """ 318 assert isinstance(fragment, Fragment) 319 self.model_dict[fragment.model_id].remove_fragment(fragment)
320
321 - def count_fragments(self):
322 """Counts all Fragment objects in the default Model. 323 """ 324 n = 0 325 for chain in self.iter_chains(): 326 n += chain.count_fragments() 327 return n
328
329 - def iter_fragments(self):
330 """Iterates over all Fragment objects in the default Model. 331 The iteration is performed in order according the the parent 332 Chain's chain_id, and the Fragment's position within the chain. 333 """ 334 if self.default_model is None: 335 raise StopIteration 336 337 for chain in self.default_model.chain_list: 338 for frag in chain.fragment_list: 339 yield frag
340
341 - def iter_all_fragments(self):
342 """Iterates over all Fragment objects in all Models. 343 The iteration is performed in order according the the parent 344 Chain's chain_id, and the Fragment's position within the chain. 345 """ 346 for model in self.model_list: 347 for chain in model.chain_list: 348 for frag in chain.fragment_list: 349 yield frag
350
351 - def has_amino_acids(self):
352 """Returns True if there are AminoAcidResidue objects in the 353 default Model of the Structure. 354 """ 355 for frag in self.iter_amino_acids(): 356 return True 357 return False
358
359 - def count_amino_acids(self):
360 """Counts all AminoAcidResidue objects in the default Model. 361 """ 362 n = 0 363 for chain in self.iter_chains(): 364 n += chain.count_amino_acids() 365 return n
366
367 - def iter_amino_acids(self):
368 """Same as iter_fragments() but only iterates over Fragments of the 369 subclass AminoAcidResidue. 370 """ 371 for chain in self.iter_chains(): 372 for frag in chain.iter_amino_acids(): 373 yield frag
374
375 - def iter_all_amino_acids(self):
376 """Iterates over all AminoAcidResidue objects in all Models. 377 """ 378 for model in self.model_list: 379 for chain in model.chain_list: 380 for frag in chain.iter_amino_acids(): 381 yield frag
382
383 - def has_nucleic_acids(self):
384 """Returns True if the Structure contains NucleicAcidResiudes in the 385 default Model. 386 """ 387 for frag in self.iter_nucleic_acids(): 388 return True 389 return False
390
391 - def count_nucleic_acids(self):
392 """Counts all NucleicAcidResidue objects in the default Model. 393 """ 394 n = 0 395 for chain in self.iter_chains(): 396 n += chain.count_nucleic_acids() 397 return n
398
399 - def iter_nucleic_acids(self):
400 """Same as iter_fragments() but only iterates over Fragments of the 401 subclass NucleicAcidResidue. 402 """ 403 for chain in self.iter_chains(): 404 for frag in chain.iter_nucleic_acids(): 405 yield frag
406
407 - def iter_all_nucleic_acids(self):
408 """Iterates over all NucleicAcidResidue objects in all Models. 409 """ 410 for model in self.model_list: 411 for chain in model.chain_list: 412 for frag in chain.iter_nucleic_acids(): 413 yield frag
414
415 - def has_standard_residues(self):
416 """Returns True if the Structure contains amino or nucleic acids 417 in the default Model. 418 """ 419 for frag in self.iter_standard_residues(): 420 return True 421 return False
422
423 - def count_standard_residues(self):
424 """Counts the number of standard residues in the default Model. 425 """ 426 n = 0 427 for na in self.iter_standard_residues(): 428 n += 1 429 return n
430
431 - def iter_standard_residues(self):
432 """Iterates over standard residues in the default Model. 433 """ 434 fpred = lambda f: f.is_standard_residue() 435 return itertools.ifilter(fpred, self.iter_fragments())
436
437 - def has_non_standard_residues(self):
438 """Returns True if there are non-standard residues in the default 439 Model. 440 """ 441 for frag in self.iter_non_standard_residues(): 442 return True 443 return False
444
446 """Counts all non-standard residues in the default Model. 447 """ 448 n = 0 449 for frag in self.iter_non_standard_residues(): 450 n += 1 451 return n
452
453 - def iter_non_standard_residues(self):
454 """Iterates over non-standard residues in the default Model. 455 Non-standard residues are any Fragments which are not an amino or 456 nucleic acid. 457 """ 458 fpred = lambda f: f.is_standard_residue() 459 return itertools.ifilterfalse(fpred, self.iter_fragments())
460
461 - def has_waters(self):
462 """Returns True if there are waters in the default Model. 463 """ 464 for frag in self.iter_waters(): 465 return True 466 return False
467
468 - def count_waters(self):
469 """Counts all waters in the default Model. 470 """ 471 n = 0 472 for frag in self.iter_waters(): 473 n += 1 474 return n
475
476 - def iter_waters(self):
477 """Iterate over all waters in the default Model. 478 """ 479 fpred = lambda f: f.is_water() 480 return itertools.ifilter(fpred, self.iter_fragments())
481
482 - def add_atom(self, atom, delay_sort = False):
483 """Adds an Atom object to the Structure. If a collision occurs, an 484 error is raised. 485 """ 486 assert isinstance(atom, Atom) 487 488 ## add new model if necesary 489 try: 490 model = self.model_dict[atom.model_id] 491 except KeyError: 492 model = Model(model_id = atom.model_id) 493 self.add_model(model, delay_sort) 494 495 ## optimized add_atom() 496 chain_id = atom.chain_id 497 fragment_id = atom.fragment_id 498 499 if model.chain_dict.has_key(chain_id): 500 chain = model.chain_dict[chain_id] 501 502 if chain.fragment_dict.has_key(fragment_id): 503 fragment = chain.fragment_dict[fragment_id] 504 505 if fragment.res_name == atom.res_name: 506 fragment.add_atom(atom) 507 else: 508 raise FragmentOverwrite() 509 else: 510 chain.add_atom(atom, delay_sort) 511 else: 512 model.add_atom(atom, delay_sort)
513
514 - def remove_atom(self, atom):
515 """Removes an Atom. 516 """ 517 assert isinstance(atom, Atom) 518 self.model_dict[atom.model_id].remove_atom(atom)
519
520 - def iter_atoms(self):
521 """Iterates over all Atom objects in the default Model, using the 522 default alt_loc. The iteration is preformed in order according to 523 the Chain and Fragment ordering rules the Atom object is a part of. 524 """ 525 if self.default_model is None: 526 raise StopIteration 527 528 for chain in self.default_model.chain_list: 529 for frag in chain.fragment_list: 530 for atm in frag.atom_list: 531 yield atm
532
533 - def count_atoms(self):
534 """Counts all Atom objects in the default Model using the 535 default alt_loc. 536 """ 537 n = 0 538 for chain in self.iter_chains(): 539 n += chain.count_atoms() 540 return n
541
542 - def iter_all_atoms(self):
543 """Iterates over all Atom objects in the Structure. The iteration is 544 performed according to common PDB ordering rules, over all Models and 545 all alternate conformations. 546 """ 547 for model in self.iter_models(): 548 for atm in model.iter_all_atoms(): 549 yield atm
550
551 - def count_all_atoms(self):
552 """Counts all atoms in the default Model using the default alt_loc. 553 """ 554 n = 0 555 for model in self.iter_models(): 556 n += model.count_all_atoms() 557 return n
558
559 - def get_equivalent_atom(self, atom):
560 """Returns the atom with the same fragment_id and name as the 561 argument atom, or None if it is not found. 562 """ 563 try: 564 return self.model_dict[atom.model_id].chain_dict[atom.chain_id].fragment_dict[atom.fragment_id].atom_dict[atom.name] 565 except KeyError: 566 return None
567
568 - def iter_bonds(self):
569 """Iterates over all Bond objects. The iteration is preformed by 570 iterating over all Atom objects in the same order as iter_atoms(), 571 then iterating over each Atom's Bond objects. 572 """ 573 visited = {} 574 for atm in self.iter_atoms(): 575 for bond in atm.iter_bonds(): 576 if visited.has_key(bond): 577 continue 578 yield bond 579 visited[bond] = True
580
581 - def count_bonds(self):
582 """Counts all Bond objects using the default Model and default 583 alt_loc. 584 """ 585 n = 0 586 for bond in self.iter_bonds(): 587 n += 1 588 return n
589
590 - def alt_loc_list(self):
591 """Return the unique list of Atom alternate location IDs found in 592 the Structure. 593 """ 594 al_list = [] 595 for atm in self.iter_all_atoms(): 596 if atm.alt_loc != "" and atm.alt_loc not in al_list: 597 al_list.append(atm.alt_loc) 598 return al_list
599
600 - def add_alpha_helix(self, alpha_helix):
601 """Adds an AlphaHelix to the default Model object. 602 """ 603 assert self.default_model is not None 604 self.default_model.add_alpha_helix(alpha_helix)
605
606 - def iter_alpha_helicies(self):
607 """Iterates over all child AlphaHelix objects in the default 608 Model. 609 """ 610 if self.default_model: 611 return self.default_model.iter_alpha_helicies() 612 return iter(list())
613
614 - def add_beta_sheet(self, beta_sheet):
615 """Adds a BetaSheet to the default Model object. 616 """ 617 assert self.default_model is not None 618 self.default_model.add_beta_sheet(beta_sheet)
619
620 - def iter_beta_sheets(self):
621 """Iterate over all beta sheets in the Structure. 622 """ 623 if self.default_model: 624 return self.default_model.iter_beta_sheets() 625 return iter(list())
626
627 - def add_site(self, site):
628 """Adds a Site object to the default Model. 629 """ 630 assert self.default_model is not None 631 self.default_model.add_site(site)
632
633 - def iter_sites(self):
634 """Iterate over all active/important sites defined in the Structure. 635 """ 636 if self.default_model: 637 return self.default_model.iter_sites() 638 return iter(list())
639
640 - def get_structure(self):
641 """Returns self. 642 """ 643 return self
644
645 - def get_default_alt_loc(self):
646 """Returns the default alt_loc string. 647 """ 648 return self.default_alt_loc
649
650 - def set_default_alt_loc(self, alt_loc):
651 """Sets the default alt_loc for the Stucture. 652 """ 653 assert isinstance(alt_loc, str) 654 655 self.default_alt_loc = alt_loc 656 for frag in self.iter_all_fragments(): 657 frag.set_default_alt_loc(alt_loc)
658
660 """Builds a Structure's bonds by atomic distance distance using 661 the covalent radii in element.cif. A bond is built if the the 662 distance between them is less than or equal to the sum of their 663 covalent radii + 0.54A. 664 """ 665 for model in self.iter_models(): 666 xyzdict = GeometryDict.XYZDict(2.0) 667 668 for atm in model.iter_all_atoms(): 669 if atm.position is not None: 670 xyzdict.add(atm.position, atm) 671 672 for (p1,atm1),(p2,atm2),dist in xyzdict.iter_contact_distance(2.5): 673 674 if (atm1.alt_loc == "" or atm2.alt_loc == "") or (atm1.alt_loc == atm2.alt_loc): 675 676 ## calculate the expected bond distance by adding the 677 ## covalent radii + 0.54A 678 edesc1 = Library.library_get_element_desc(atm1.element) 679 edesc2 = Library.library_get_element_desc(atm2.element) 680 681 ## this will usually occur if an atom name does not match 682 ## the one found in the associated monomer library 683 if edesc1 is None or edesc2 is None: 684 continue 685 686 bond_dist = edesc1.covalent_radius + edesc2.covalent_radius + 0.54 687 688 ## this will usually occur if the bond distance between 689 ## between two atoms does not match the description in 690 ## in the monomer library 691 if dist > bond_dist: 692 continue 693 694 if atm1.get_bond(atm2) is None: 695 atm1.create_bond(atom = atm2, standard_res_bond = False)
696
697 - def add_bonds_from_library(self):
698 """Builds bonds for all Fragments in the Structure from bond tables 699 for monomers retrieved from the Library implementation of the 700 Structure. 701 """ 702 for frag in self.iter_all_fragments(): 703 frag.create_bonds()
704 705
706 -class Model(object):
707 """Multiple models support. 708 """
709 - def __init__(self, model_id=1, **args):
710 assert isinstance(model_id, int) 711 712 self.structure = None 713 714 self.model_id = model_id 715 self.chain_dict = {} 716 self.chain_list = [] 717 718 self.alpha_helix_list = [] 719 self.beta_sheet_list = [] 720 self.site_list = []
721
722 - def __str__(self):
723 return "Model(model_id=%d)" % (self.model_id)
724
725 - def __deepcopy__(self, memo):
726 model = Model(model_id = self.model_id) 727 for chain in self.chain_list: 728 model.add_chain(copy.deepcopy(chain, memo), True) 729 return model
730
731 - def __lt__(self, other):
732 assert isinstance(other, Model) 733 return int(self.model_id) < int(other.model_id)
734
735 - def __le__(self, other):
736 assert isinstance(other, Model) 737 return int(self.model_id) <= int(other.model_id)
738
739 - def __gt__(self, other):
740 assert isinstance(other, Model) 741 return int(self.model_id) > int(other.model_id)
742
743 - def __ge__(self, other):
744 assert isinstance(other, Model) 745 return int(self.model_id) >= int(other.model_id)
746
747 - def __len__(self):
748 """Returns the number of stored Chain objects. 749 """ 750 return len(self.chain_list)
751
752 - def __getitem__(self, chain_idx):
753 """Same as get_chain, but raises KeyError if the requested chain_id 754 is not found. 755 """ 756 if isinstance(chain_idx, str): 757 return self.chain_dict[chain_idx] 758 elif isinstance(chain_idx, int): 759 return self.chain_list[chain_idx] 760 raise TypeError, chain_idx
761
762 - def __iter__(self):
763 """Iterates the Chain objects in the Model. 764 """ 765 return iter(self.chain_list)
766
767 - def __contains__(self, chain_idx):
768 """Returns True if the argument Chain or chain_id is in the Model. 769 """ 770 if isinstance(chain_idx, Chain): 771 return self.chain_list.__contains__(chain_idx) 772 elif isinstance(chain_idx, str): 773 return self.chain_dict.__contains__(chain_idx) 774 raise TypeError, chain_idx
775
776 - def index(self, chain):
777 """Returns the numeric index of the Chain object in the Model. 778 """ 779 assert isinstance(chain, Chain) 780 return self.chain_list.index(chain)
781
782 - def sort(self):
783 """Sorts all Chains in the Model by their chain_id. 784 """ 785 self.chain_list.sort() 786 for chain in self.chain_list: 787 chain.sort()
788
789 - def add_chain(self, chain, delay_sort=False):
790 """Adds a Chain to the Model. 791 """ 792 assert isinstance(chain, Chain) 793 794 if self.chain_dict.has_key(chain.chain_id): 795 raise ChainOverwrite() 796 797 self.chain_list.append(chain) 798 self.chain_dict[chain.chain_id] = chain 799 chain.model = self 800 801 if not delay_sort: 802 self.chain_list.sort()
803
804 - def remove_chain(self, chain):
805 """Removes the Chain from the Model. 806 """ 807 assert isinstance(chain, Chain) 808 self.chain_list.remove(chain) 809 del self.chain_dict[chain.chain_id] 810 chain.model = None
811
812 - def get_chain(self, chain_id):
813 """Returns the Chain object matching the chain_id character. 814 """ 815 if self.chain_dict.has_key(chain_id): 816 return self.chain_dict[chain_id] 817 return None
818
819 - def iter_chains(self):
820 """Iterates over all Chain objects in alphabetical order according 821 to their chain_id. 822 """ 823 return iter(self.chain_list)
824
825 - def count_chains(self):
826 """Counts all Chain objects. 827 """ 828 return len(self.chain_list)
829
830 - def add_fragment(self, fragment, delay_sort = False):
831 """Adds a Fragment instance 832 """ 833 assert isinstance(fragment, Fragment) 834 assert fragment.model_id == self.model_id 835 836 ## add new chain if necessary 837 try: 838 chain = self.chain_dict[fragment.chain_id] 839 except KeyError: 840 chain = Chain( 841 model_id = fragment.model_id, 842 chain_id = fragment.chain_id) 843 self.add_chain(chain, delay_sort) 844 845 chain.add_fragment(fragment, delay_sort)
846
847 - def remove_fragment(self, fragment):
848 """Removes a Fragment object. 849 """ 850 assert isinstance(fragment, Fragment) 851 self.chain_dict[fragment.chain_id].remove_fragment(fragment)
852
853 - def count_fragments(self):
854 """Counts all Fragment objects. 855 """ 856 n = 0 857 for chain in self.iter_chains(): 858 n += chain.count_fragments() 859 return n
860
861 - def iter_fragments(self):
862 """Iterates over all Fragment objects. The iteration is performed 863 in order according the the parent Chain's chain_id, and the 864 Fragment's position within the chain. 865 """ 866 for chain in self.chain_list: 867 for frag in chain.fragment_list: 868 yield frag
869
870 - def has_amino_acids(self):
871 for frag in self.iter_amino_acids(): 872 return True 873 return False
874
875 - def count_amino_acids(self):
876 n = 0 877 for chain in self.iter_chains(): 878 n += chain.count_amino_acids() 879 return n
880
881 - def iter_amino_acids(self):
882 for chain in self.iter_chains(): 883 for frag in chain.iter_amino_acids(): 884 yield frag
885
886 - def has_nucleic_acids(self):
887 for frag in self.iter_nucleic_acids(): 888 return True 889 return False
890
891 - def count_nucleic_acids(self):
892 n = 0 893 for chain in self.iter_chains(): 894 n += chain.count_nucleic_acids() 895 return n
896
897 - def iter_nucleic_acids(self):
898 for chain in self.iter_chains(): 899 for frag in chain.iter_nucleic_acids(): 900 yield frag
901
902 - def has_standard_residues(self):
903 for frag in self.iter_standard_residues(): 904 return True 905 return False
906
907 - def count_standard_residues(self):
908 n = 0 909 for na in self.iter_standard_residues(): 910 n += 1 911 return n
912
913 - def iter_standard_residues(self):
914 fpred = lambda f: f.is_standard_residue() 915 return itertools.ifilter(fpred, self.iter_fragments())
916
918 n = 0 919 for frag in self.iter_non_standard_residues(): 920 n += 1 921 return n
922
923 - def has_non_standard_residues(self):
924 for frag in self.iter_non_standard_residues(): 925 return True 926 return False
927
928 - def iter_non_standard_residues(self):
929 fpred = lambda f: f.is_standard_residue() 930 return itertools.ifilterfalse(fpred, self.iter_fragments())
931
932 - def has_waters(self):
933 for frag in self.iter_waters(): 934 return True 935 return False
936
937 - def count_waters(self):
938 n = 0 939 for frag in self.iter_waters(): 940 n += 1 941 return n
942
943 - def iter_waters(self):
944 fpred = lambda f: f.is_water() 945 return itertools.ifilter(fpred, self.iter_fragments())
946
947 - def add_atom(self, atom, delay_sort=False):
948 assert isinstance(atom, Atom) 949 assert atom.model_id == self.model_id 950 951 ## add new chain if necessary 952 try: 953 chain = self.chain_dict[atom.chain_id] 954 except KeyError: 955 chain = Chain( 956 model_id = atom.model_id, 957 chain_id = atom.chain_id) 958 self.add_chain(chain, delay_sort) 959 960 ## add the atom to the chain 961 chain.add_atom(atom, delay_sort)
962
963 - def remove_atom(self, atom):
964 """Removes an Atom object. 965 """ 966 assert isinstance(atom, Atom) 967 assert atom.model_id == self.model_id 968 self.chain_dict[atom.chain_id].remove_atom(atom)
969
970 - def iter_atoms(self):
971 """Iterates over all Atom objects according to the Structure 972 defaults. 973 """ 974 for chain in self.chain_list: 975 for frag in chain.fragment_list: 976 for atm in frag.atom_list: 977 yield atm
978
979 - def count_atoms(self):
980 """Counts all Atom objects in according to the Structure defaults. 981 """ 982 n = 0 983 for chain in self.iter_chains(): 984 n += chain.count_atoms() 985 return n
986
987 - def iter_all_atoms(self):
988 """Iterates over all Atom objects including all atoms in multiple 989 conformations. 990 """ 991 for chain in self.iter_chains(): 992 for atm in chain.iter_all_atoms(): 993 yield atm
994
995 - def count_all_atoms(self):
996 """Counts all Atom objects including all atoms in multiple 997 conformations. 998 """ 999 n = 0 1000 for chain in self.iter_chains(): 1001 n += chain.count_all_atoms() 1002 return n
1003
1004 - def get_equivalent_atom(self, atom):
1005 """Returns the atom with the same fragment_id and name as the 1006 argument atom, or None if it is not found. 1007 """ 1008 try: 1009 return self.chain_dict[atom.chain_id].fragment_dict[atom.fragment_id].atom_dict[atom.name] 1010 except KeyError: 1011 return None
1012
1013 - def add_alpha_helix(self, alpha_helix):
1014 """Adds an AlphaHelix object to the Model. 1015 """ 1016 assert isinstance(alpha_helix, AlphaHelix) 1017 self.alpha_helix_list.append(alpha_helix) 1018 alpha_helix.model = self
1019
1020 - def remove_alpha_helix(self, alpha_helix):
1021 """Removes an AlphaHelix object from the Model. 1022 """ 1023 assert isinstance(alpha_helix, AlphaHelix) 1024 self.alpha_helix_list.remove(alpha_helix) 1025 alpha_helix.model = None
1026
1027 - def iter_alpha_helicies(self):
1028 """Iterates over all AlphaHelix objects in the Model. 1029 """ 1030 return iter(self.alpha_helix_list)
1031
1032 - def add_beta_sheet(self, beta_sheet):
1033 """Adds a BetaSheet object to the Model. 1034 """ 1035 assert isinstance(beta_sheet, BetaSheet) 1036 self.beta_sheet_list.append(beta_sheet) 1037 beta_sheet.model = self
1038
1039 - def remove_beta_sheet(self, beta_sheet):
1040 """Removes a BetaSheet object from the Model. 1041 """ 1042 assert isinstance(beta_sheet, BetaSheet) 1043 self.beta_sheet_list.remove(beta_sheet) 1044 beta_sheet.model = None
1045
1046 - def iter_beta_sheets(self):
1047 """Iterate over all child BetaSheet objects in the Model. 1048 """ 1049 return iter(self.beta_sheet_list)
1050
1051 - def add_site(self, site):
1052 """Adds a Site (of interest) object to the Model. 1053 """ 1054 assert isinstance(site, Site) 1055 self.site_list.append(site) 1056 site.model = self
1057
1058 - def remove_site(self, site):
1059 """Removes a Site (of interest) object from the Model. 1060 """ 1061 assert isinstance(site, Site) 1062 self.site_list.append(site) 1063 site.model = None
1064
1065 - def iter_sites(self):
1066 """Iterate over all active/important sites defined in the Structure. 1067 """ 1068 return iter(self.site_list)
1069
1070 - def get_structure(self):
1071 """Returns the parent Structure. 1072 """ 1073 return self.structure
1074
1075 - def iter_bonds(self):
1076 """Iterates over all Bond objects. The iteration is preformed by 1077 iterating over all Atom objects in the same order as iter_atoms(), 1078 then iterating over each Atom's Bond objects. 1079 """ 1080 visited = {} 1081 for atm in self.iter_atoms(): 1082 for bond in atm.iter_bonds(): 1083 if visited.has_key(bond): 1084 continue 1085 yield bond 1086 visited[bond] = True
1087
1088 - def count_bonds(self):
1089 """Counts all Bond objects. 1090 """ 1091 n = 0 1092 for bond in self.iter_bonds(): 1093 n += 1 1094 return n
1095
1096 - def set_model_id(self, model_id):
1097 """Sets the model_id of all contained objects. 1098 """ 1099 assert isinstance(model_id, int) 1100 1101 if self.structure is not None: 1102 chk_model = self.structure.get_model(model_id) 1103 if chk_model is not None or chk_model != self: 1104 raise ModelOverwrite() 1105 1106 self.model_id = model_id 1107 1108 for chain in self.iter_chains(): 1109 chain.set_model_id(model_id) 1110 1111 if self.structure is not None: 1112 self.structure.model_list.sort()
1113 1114
1115 -class Segment(object):
1116 """Segment objects are a container for Fragment objects, but are 1117 disassociated with the Structure object hierarch. Chain objects are 1118 a subclass of Segment objects which are part of the Structure hierarchy. 1119 """
1120 - def __init__(self, 1121 model_id = 1, 1122 chain_id = "", 1123 **args):
1124 1125 assert isinstance(model_id, int) 1126 assert isinstance(chain_id, str) 1127 1128 self.model = None 1129 self.chain = None 1130 1131 self.model_id = model_id 1132 self.chain_id = chain_id 1133 1134 ## fragments are contained in the list and also cached in a 1135 ## dictionary for fast random-access lookup 1136 self.fragment_list = [] 1137 self.fragment_dict = {} 1138 1139 ## sequence associated with the segment 1140 self.sequence = Sequence.Sequence()
1141
1142 - def __str__(self):
1143 try: 1144 return "Segment(%d:%s, %s...%s)" % ( 1145 self.model_id, self.chain_id, self.fragment_list[0], self.fragment_list[-1]) 1146 except IndexError: 1147 return "Segment(%d:%s)" % (self.model_id, self.chain_id)
1148
1149 - def __deepcopy__(self, memo):
1150 """Implements copy module protocol for deepcopy() operation. 1151 """ 1152 segment = Segment(model_id = self.model_id, chain_id = self.chain_id) 1153 1154 for fragment in self.fragment_list: 1155 segment.add_fragment(copy.deepcopy(fragment, memo), True) 1156 1157 return segment
1158
1159 - def __lt__(self, other):
1160 """Less than operator based on the chain_id. 1161 """ 1162 assert isinstance(other, Segment) 1163 return self.chain_id < other.chain_id
1164
1165 - def __le__(self, other):
1166 """Less than or equal operator based on chain_id. 1167 """ 1168 assert isinstance(other, Segment) 1169 return self.chain_id <= other.chain_id
1170
1171 - def __gt__(self, other):
1172 """Greator than operator based on chain_id. 1173 """ 1174 assert isinstance(other, Segment) 1175 return self.chain_id > other.chain_id
1176
1177 - def __ge__(self, other):
1178 """Greator than or equal to operator based on chain_id. 1179 """ 1180 assert isinstance(other, Segment) 1181 return self.chain_id >= other.chain_id
1182
1183 - def __len__(self):
1184 """Return the number of Fragments in the Segment. 1185 """ 1186 return len(self.fragment_list)
1187
1188 - def __getitem__(self, fragment_idx):
1189 """Retrieve a Fragment within the Segment. This can take an integer 1190 index of the Fragment's position within the segment, the fragment_id 1191 string of the Fragment to retrieve, or a slice of the Segment to 1192 return a new Segment object containing the sliced subset of Fragments. 1193 If the slice values are fragment_id strings, then the Segment which 1194 is returned includes those Fragments. If the slice values are 1195 integers, then normal list slicing rules apply. 1196 """ 1197 if isinstance(fragment_idx, int): 1198 return self.fragment_list[fragment_idx] 1199 1200 elif isinstance(fragment_idx, str): 1201 return self.fragment_dict[fragment_idx] 1202 1203 elif isinstance(fragment_idx, slice): 1204 ## determine if the slice is on list indexes or on fragment_id 1205 ## strings 1206 start = fragment_idx.start 1207 stop = fragment_idx.stop 1208 1209 ## check for index (list) slicing 1210 if (start is None and stop is None) or \ 1211 (start is None and isinstance(stop, int)) or \ 1212 (stop is None and isinstance(start, int)) or \ 1213 (isinstance(start, int) and isinstance(stop, int)): 1214 1215 segment = self.construct_segment() 1216 for frag in self.fragment_list[start:stop]: 1217 segment.add_fragment(frag, True) 1218 return segment 1219 1220 ## check for fragment_id slicing 1221 if (start is None and isinstance(stop, str)) or \ 1222 (stop is None and isinstance(start, str)) or \ 1223 (isinstance(start, str) and isinstance(stop, str)): 1224 1225 return self.construct_sub_segment(start, stop) 1226 1227 raise TypeError, fragment_idx
1228
1229 - def __iter__(self):
1230 """Iterate all Fragments contained in the Segment. 1231 """ 1232 return iter(self.fragment_list)
1233
1234 - def __contains__(self, fragment_idx):
1235 """Checks for Fragment objects, or the fragment_id string. 1236 """ 1237 if isinstance(fragment_idx, Fragment): 1238 return self.fragment_list.__contains__(fragment_idx) 1239 elif isinstance(fragment_idx, str): 1240 return self.fragment_dict.__contains__(fragment_idx) 1241 raise TypeError, fragment_idx
1242
1243 - def index(self, fragment):
1244 """Return the 0-based index of the fragment in the segment list. 1245 """ 1246 return self.fragment_list.index(fragment)
1247
1248 - def sort(self):
1249 """Sort the Fragments in the Segment into proper order. 1250 """ 1251 self.fragment_list.sort()
1252
1253 - def construct_segment(self):
1254 """Constructs a new Segment object so that it has a valid .chain 1255 reference. 1256 """ 1257 segment = Segment( 1258 model_id = self.model_id, 1259 chain_id = self.chain_id) 1260 1261 segment.chain = self.chain 1262 segment.model = self.model 1263 1264 return segment
1265
1266 - def construct_sub_segment(self, start_frag_id, stop_frag_id):
1267 """Construct and return a sub-Segment between start_frag_id and 1268 stop_frag_id. If start_frag_id is None, then the slice is taken from 1269 the beginning of this Segment, and if stop_frag_id is None it is taken 1270 to the end of this Segment. 1271 """ 1272 fragiter = iter_fragments(iter(self.fragment_list), start_frag_id, stop_frag_id) 1273 segment = self.construct_segment() 1274 for frag in fragiter: 1275 segment.add_fragment(frag, True) 1276 return segment
1277
1278 - def add_fragment(self, fragment, delay_sort = False):
1279 """Adds a Fragment instance to the Segment. If delay_sort is True, 1280 then the fragment is not inserted in the proper position within the 1281 segment. 1282 """ 1283 assert isinstance(fragment, Fragment) 1284 assert fragment.chain_id == self.chain_id 1285 1286 if self.fragment_dict.has_key(fragment.fragment_id): 1287 raise FragmentOverwrite() 1288 1289 self.fragment_list.append(fragment) 1290 self.fragment_dict[fragment.fragment_id] = fragment 1291 1292 if not delay_sort: 1293 self.fragment_list.sort()
1294
1295 - def remove_fragment(self, fragment):
1296 """Removes a Fragment object from the Segment. 1297 """ 1298 assert isinstance(fragment, Fragment) 1299 self.fragment_list.remove(fragment) 1300 del self.fragment_dict[fragment.fragment_id]
1301
1302 - def get_fragment(self, fragment_id):
1303 """Returns the PDB fragment uniquely identified by its fragment_id. 1304 """ 1305 if self.fragment_dict.has_key(fragment_id): 1306 return self.fragment_dict[fragment_id] 1307 return None
1308
1309 - def iter_fragments(self, frag_id_begin = None, frag_id_end = None):
1310 """Iterates over all Fragment objects. The iteration is performed in 1311 order according to the Fragment's position within the Segment object. 1312 """ 1313 return iter_fragments(iter(self.fragment_list), frag_id_begin, frag_id_end)
1314
1315 - def count_fragments(self):
1316 """Return the number of Fragment objects. 1317 """ 1318 return len(self.fragment_list)
1319
1320 - def has_amino_acids(self):
1321 for frag in self.fragment_list: 1322 if frag.is_amino_acid(): 1323 return True 1324 return False
1325
1326 - def count_amino_acids(self):
1327 n = 0 1328 for frag in self.fragment_list: 1329 if frag.is_amino_acid(): 1330 n += 1 1331 return n
1332
1333 - def iter_amino_acids(self):
1334 fpred = lambda f: f.is_amino_acid() 1335 return itertools.ifilter(fpred, self.fragment_list)
1336
1337 - def has_nucleic_acids(self):
1338 for frag in self.fragment_list: 1339 if frag.is_nucleic_acid(): 1340 return True 1341 return False
1342
1343 - def count_nucleic_acids(self):
1344 n = 0 1345 for frag in self.fragment_list: 1346 if frag.is_nucleic_acid(): 1347 n += 1 1348 return n
1349
1350 - def iter_nucleic_acids(self):
1351 fpred = lambda f: f.is_nucleic_acid() 1352 return itertools.ifilter(fpred, self.fragment_list)
1353
1354 - def has_standard_residues(self):
1355 for frag in self.fragment_list: 1356 if frag.is_standard_residue(): 1357 return True 1358 return False
1359
1360 - def count_standard_residues(self):
1361 n = 0 1362 for frag in self.fragment_list: 1363 if frag.is_standard_residue(): 1364 n += 1 1365 return n
1366
1367 - def iter_standard_residues(self):
1368 fpred = lambda f: f.is_standard_residue() 1369 return itertools.ifilter(fpred, self.fragment_list)
1370
1371 - def has_non_standard_residues(self):
1372 for frag in self.fragment_list: 1373 if not frag.is_standard_residue(): 1374 return True 1375 return False
1376
1378 n = 0 1379 for frag in self.fragment_list: 1380 if not frag.is_standard_residue(): 1381 n += 1 1382 return n
1383
1384 - def iter_non_standard_residues(self):
1385 fpred = lambda f: f.is_standard_residue() 1386 return itertools.ifilterfalse(fpred, self.fragment_list)
1387
1388 - def has_waters(self):
1389 for frag in self.fragment_list: 1390 if frag.is_water(): 1391 return True 1392 return False
1393
1394 - def count_waters(self):
1395 n = 0 1396 for frag in self.fragment_list: 1397 if frag.is_water(): 1398 n += 1 1399 return n
1400
1401 - def iter_waters(self):
1402 fpred = lambda f: f.is_water() 1403 return itertools.ifilter(fpred, self.fragment_list)
1404
1405 - def add_atom(self, atom, delay_sort = False):
1406 """Adds an Atom. 1407 """ 1408 assert isinstance(atom, Atom) 1409 assert atom.model_id == self.model_id 1410 assert atom.chain_id == self.chain_id 1411 1412 ## add new fragment if necessary 1413 if not self.fragment_dict.has_key(atom.fragment_id): 1414 1415 if Library.library_is_amino_acid(atom.res_name): 1416 fragment = AminoAcidResidue( 1417 model_id = atom.model_id, 1418 chain_id = atom.chain_id, 1419 fragment_id = atom.fragment_id, 1420 res_name = atom.res_name) 1421 1422 elif Library.library_is_nucleic_acid(atom.res_name): 1423 fragment = NucleicAcidResidue( 1424 model_id = atom.model_id, 1425 chain_id = atom.chain_id, 1426 fragment_id = atom.fragment_id, 1427 res_name = atom.res_name) 1428 else: 1429 fragment = Fragment( 1430 model_id = atom.model_id, 1431 chain_id = atom.chain_id, 1432 fragment_id = atom.fragment_id, 1433 res_name = atom.res_name) 1434 1435 self.add_fragment(fragment, delay_sort) 1436 1437 else: 1438 fragment = self.fragment_dict[atom.fragment_id] 1439 if fragment.res_name != atom.res_name: 1440 raise FragmentOverwrite() 1441 1442 fragment.add_atom(atom)
1443
1444 - def remove_atom(self, atom):
1445 """Removes an Atom object. 1446 """ 1447 assert isinstance(atom, Atom) 1448 self.fragment_dict[atom.fragment_id].remove_atom(atom)
1449
1450 - def iter_atoms(self):
1451 """Iterates over all Atom objects within the Segment using the 1452 default conformation set in the parent Structure. 1453 """ 1454 for frag in self.fragment_list: 1455 for atm in frag.atom_list: 1456 yield atm
1457
1458 - def count_atoms(self):
1459 n = 0 1460 for frag in self.iter_fragments(): 1461 n += frag.count_atoms() 1462 return n
1463
1464 - def iter_all_atoms(self):
1465 """Performs an in-order iteration of all atoms in the Segment, 1466 including alternate conformations. 1467 """ 1468 for frag in self.fragment_list: 1469 for atm in frag.iter_all_atoms(): 1470 yield atm
1471
1472 - def count_all_atoms(self):
1473 n = 0 1474 for frag in self.iter_fragments(): 1475 n += frag.count_all_atoms() 1476 return n
1477
1478 - def get_equivalent_atom(self, atom):
1479 """Returns the atom with the same fragment_id and name as the 1480 argument atom, or None if it is not found. 1481 """ 1482 try: 1483 return self.fragment_dict[atom.fragment_id].atom_dict[atom.name] 1484 except KeyError: 1485 return None
1486
1487 - def iter_bonds(self):
1488 """Iterates over all Bond objects attached to Atom objects within the 1489 Segment. 1490 """ 1491 visited = {} 1492 for atm in self.iter_atoms(): 1493 for bond in atm.iter_bonds(): 1494 if visited.has_key(bond): 1495 continue 1496 yield bond 1497 visited[bond] = True
1498
1499 - def get_chain(self):
1500 """Returns the Chain object this Segment is part of. 1501 """ 1502 return self.chain
1503
1504 - def get_model(self):
1505 """Returns the parent Model object. 1506 """ 1507 return self.model
1508
1509 - def get_structure(self):
1510 """Returns the parent Structure object. 1511 """ 1512 return self.model.structure
1513
1514 - def set_model_id(self, model_id):
1515 """Sets the model_id of all contained objects. 1516 """ 1517 assert isinstance(model_id, int) 1518 self.model_id = model_id 1519 1520 for frag in self.iter_fragments(): 1521 frag.set_model_id(model_id)
1522
1523 - def set_chain_id(self, chain_id):
1524 """Sets the model_id of all contained objects. 1525 """ 1526 assert isinstance(chain_id, str) 1527 self.chain_id = chain_id 1528 1529 for frag in self.iter_fragments(): 1530 frag.set_chain_id(chain_id)
1531
1532 - def is_homolog(self, segment2):
1533 """Returns True if there are no disagreements in the sequences of 1534 this segment and segment2. 1535 """ 1536 hdict = {} 1537 1538 for fragment in self.fragment_list: 1539 hdict[fragment.fragment_id] = fragment.res_name 1540 1541 for fragment in segment2.fragment_list: 1542 if hdict.get(fragment.fragment_id, fragment.res_name) != fragment.res_name: 1543 return False 1544 1545 return True
1546
1547 -class Chain(Segment):
1548 """Chain objects contain an ordered list of Fragment objects. 1549 """
1550 - def __init__(self, 1551 model_id = 1, 1552 chain_id = "", 1553 **args):
1554 1555 args["model_id"] = model_id 1556 args["chain_id"] = chain_id 1557 Segment.__init__(self, **args) 1558 self.model = None
1559
1560 - def __str__(self):
1561 try: 1562 return "Chain(%d:%s, %s...%s)" % ( 1563 self.model_id, self.chain_id, self.fragment_list[0], self.fragment_list[-1]) 1564 except IndexError: 1565 return "Chain(%d:%s)" % (self.model_id, self.chain_id)
1566
1567 - def __deepcopy__(self, memo):
1568 """Implements the copy module deepcopy() protocol. 1569 """ 1570 chain = Chain(model_id = self.model_id, 1571 chain_id = self.chain_id) 1572 for fragment in self.fragment_list: 1573 chain.add_fragment(copy.deepcopy(fragment, memo), True) 1574 return chain
1575
1576 - def construct_segment(self):
1577 """Constructs a new Segment object so that it has a valid .chain 1578 reference. 1579 """ 1580 segment = Segment( 1581 model_id = self.model_id, 1582 chain_id = self.chain_id) 1583 1584 segment.chain = self 1585 segment.model = self.model 1586 1587 return segment
1588
1589 - def set_sequence(self, sequence_list):
1590 """The sequence_list is a list of 3-letter residue name codes which 1591 define the polymer sequence for the chain. Setting the sequence 1592 attempts to map the sequence codes to Fragment objects. 1593 """ 1594 self.sequence_fragment_list = [] 1595 for res_name in sequence_list: 1596 self.sequence_fragment_list.append((res_name, None))
1597
1598 - def remove_sequence(self):
1599 """Removes the current sequence mapping. 1600 """ 1601 self.sequence_fragment_list = []
1602
1603 - def iter_sequence(self):
1604 """Iterates over all 3-letter residue codes for the polymer sequence. 1605 """ 1606 for res_name, fragment in self.sequence_fragment_list: 1607 yield res_name
1608
1609 - def construct_sequence_list(self):
1610 """Constructs and returns a list with the 3-letter residue codes 1611 for the polymer sequence. 1612 """ 1613 return list(self.iter_sequence())
1614
1615 - def get_fragment_sequence_index(self, seq_index):
1616 return self.sequence_fragment_list[seq_index][1]
1617
1618 - def add_fragment(self, fragment, delay_sort=False):
1619 """Adds a Fragment instance to the Chain. If delay_sort is True, 1620 then the fragment is not inserted in the proper position within the 1621 chain. 1622 """ 1623 Segment.add_fragment(self, fragment, delay_sort) 1624 fragment.chain = self
1625
1626 - def remove_fragment(self, fragment):
1627 """Remove the Fragment from the Chain. 1628 """ 1629 Segment.remove_fragment(self, fragment) 1630 fragment.chain = None
1631
1632 - def set_chain_id(self, chain_id):
1633 """Sets a new ID for the Chain, updating the chain_id 1634 for all objects in the Structure hierarchy. 1635 """ 1636 ## check for conflicting chain_id in the structure 1637 if self.model is not None: 1638 chk_chain = self.model.get_chain(chain_id) 1639 if chk_chain is not None or chk_chain != self: 1640 raise ChainOverwrite() 1641 1642 Segment.set_chain_id(self, chain_id) 1643 1644 ## resort the parent structure 1645 if self.model is not None: 1646 self.model.chain_list.sort()
1647 1648
1649 -class Fragment(object):
1650 """Fragment objects are a basic unit for organizing small groups of Atoms. 1651 Amino acid residues are fragments, as well as nucleic acids and other 1652 small molecules. In terms of a PDB file, they are all the atoms from a 1653 unique residue in a chain. 1654 1655 Fragments have the following attributes: 1656 1657 Fragment.res_name - the fragment/residue name 1658 Fragment.res_seq - the sequence id of the fragment/residue 1659 Fragment.chain_id - the ID of the chain containing this fragment 1660 """
1661 - def __init__(self, 1662 model_id = 1, 1663 chain_id = "", 1664 fragment_id = "", 1665 res_name = "", 1666 **args):
1667 1668 assert isinstance(model_id, int) 1669 assert isinstance(res_name, str) 1670 assert isinstance(fragment_id, str) 1671 assert isinstance(chain_id, str) 1672 1673 self.chain = None 1674 1675 self.model_id = model_id 1676 self.chain_id = chain_id 1677 self.fragment_id = fragment_id 1678 self.res_name = res_name 1679 1680 self.default_alt_loc = "A" 1681 1682 ## Atom objects stored in the original order as they were added to 1683 ## the Fragment. 1684 self.atom_order_list = [] 1685 1686 ## dictionary of atom name->Altloc objects 1687 self.alt_loc_dict = {} 1688 1689 ## Atom object list/dict setup according to the current 1690 ## default_alt_loc 1691 self.atom_list = [] 1692 self.atom_dict = {}
1693
1694 - def __str__(self):
1695 return "Frag(%s,%s,%s)" % ( 1696 self.res_name, 1697 self.fragment_id, 1698 self.chain_id)
1699
1700 - def __deepcopy__(self, memo):
1701 fragment = Fragment( 1702 model_id = self.model_id, 1703 chain_id = self.chain_id, 1704 fragment_id = self.fragment_id, 1705 res_name = self.res_name) 1706 1707 for atom in self.iter_all_atoms(): 1708 fragment.add_atom(copy.deepcopy(atom, memo)) 1709 1710 return fragment
1711
1712 - def __lt__(self, other):
1713 assert isinstance(other, Fragment) 1714 return fragment_id_lt(self.fragment_id, other.fragment_id)
1715
1716 - def __le__(self, other):
1717 assert isinstance(other, Fragment) 1718 return fragment_id_le(self.fragment_id, other.fragment_id)
1719
1720 - def __gt__(self, other):
1721 assert isinstance(other, Fragment) 1722 return fragment_id_gt(self.fragment_id, other.fragment_id)
1723
1724 - def __ge__(self, other):
1725 assert isinstance(other, Fragment) 1726 return fragment_id_ge(self.fragment_id, other.fragment_id)
1727
1728 - def __len__(self):
1729 return len(self.atom_list)
1730
1731 - def __getitem__(self, name_idx):
1732 """Lookup an atom contained in a fragment by its name, or by its index 1733 within the fragment's private atom_list. If the atom is not found, 1734 an exception is raised. The type of exception depends on the argument 1735 type. If the argument was an integer, then an IndexError is raised. 1736 If the argument was a string, then a KeyError is raised. 1737 """ 1738 if isinstance(name_idx, str): 1739 return self.atom_dict[name_idx] 1740 elif isinstance(name_idx, int): 1741 return self.atom_list[name_idx] 1742 raise TypeError, name_idx
1743
1744 - def __iter__(self):
1745 """Iterates the atoms within the fragment. If the fragment contains 1746 atoms in alternate conformations, only the atoms with the structure's 1747 default_alt_loc are iterated. 1748 """ 1749 return iter(self.atom_list)
1750
1751 - def __contains__(self, atom_idx):
1752 """Return True if the Atom object is contained in the fragment. 1753 """ 1754 if isinstance(atom_idx, Atom): 1755 return self.atom_list.__contains__(atom_idx) 1756 elif isinstance(atom_idx, str): 1757 return self.atom_dict.__contains__(atom_idx) 1758 raise TypeError, atom_idx
1759
1760 - def index(self, atom):
1761 """Returns the sequential index of the atom. 1762 """ 1763 return self.atom_list.index(atom)
1764
1765 - def set_default_alt_loc(self, alt_loc):
1766 """Sets the default alt_loc of the Fragment. 1767 """ 1768 self.default_alt_loc = alt_loc 1769 1770 ishift = 0 1771 for i, atm in enumerate(self.atom_order_list): 1772 if isinstance(atm, Atom): 1773 ## case 1: atom has no alt_locs 1774 try: 1775 self.atom_list[i-ishift] = atm 1776 except IndexError: 1777 self.atom_list.append(atm) 1778 self.atom_dict[atm.name] = atm 1779 1780 else: 1781 try: 1782 atmx = atm[alt_loc] 1783 except KeyError: 1784 ## case 2: atom has alt_loc partners, but not one 1785 ## for this given alt_loc 1786 try: 1787 del self.atom_list[i-ishift] 1788 except IndexError: 1789 pass 1790 for atmx in atm.itervalues(): 1791 try: 1792 del self.atom_dict[atmx.name] 1793 except KeyError: 1794 pass 1795 break 1796 ishift += 1 1797 else: 1798 ## case 3: atom has alt_loc partners, and one for 1799 ## this alt_loc too 1800 try: 1801 self.atom_list[i-ishift] = atmx 1802 except IndexError: 1803 self.atom_list.append(atmx) 1804 self.atom_dict[atmx.name] = atmx
1805
1806 - def add_atom(self, atom):
1807 """Adds an atom to the fragment, and sets the atom's atom.fragment 1808 attribute to the fragment. 1809 """ 1810 assert isinstance(atom, Atom) 1811 assert atom.chain_id == self.chain_id 1812 assert atom.fragment_id == self.fragment_id 1813 assert atom.res_name == self.res_name 1814 1815 name = atom.name 1816 alt_loc = atom.alt_loc 1817 1818 if alt_loc == "": 1819 if not self.alt_loc_dict.has_key(name): 1820 ## CASE: 1821 ## add atom without alt_loc partners to the fragment 1822 ## procedure: 1823 ## check if an atom with the same name is already in the 1824 ## fragment, and raise an AtomOverwrite exception if 1825 ## it is, otherwise, add the atom to the fragment 1826 1827 if not self.atom_dict.has_key(name): 1828 self.atom_order_list.append(atom) 1829 self.atom_list.append(atom) 1830 self.atom_dict[name] = atom 1831 1832 else: 1833 ## CASE: 1834 ## multiple atoms with the same name, without 1835 ## alt_loc labels, but they are really alt_loc 1836 ## partners 1837 atomA = self.atom_dict[name] 1838 assert atomA != atom 1839 1840 msg = "atom name clash %s, " % (str(atomA)) 1841 msg += "automatically assigning ALTLOC labels" 1842 ConsoleOutput.warning(msg) 1843 1844 iA = self.atom_order_list.index(atomA) 1845 1846 self.alt_loc_dict[name] = altloc = Altloc() 1847 self.atom_order_list[iA] = altloc 1848 1849 altloc.add_atom(atomA) 1850 altloc.add_atom(atom) 1851 self.set_default_alt_loc(self.default_alt_loc) 1852 1853 else: 1854 ## CASE: 1855 ## adding atom without alt_loc, but partner atoms 1856 ## are already in the fragment with alt_loc 1857 ## procedure: 1858 ## set the atom.alt_loc to the next reasonable alt_loc 1859 ## and add it to the fragment 1860 altloc = self.alt_loc_dict[name] 1861 altloc.add_atom(atom) 1862 self.set_default_alt_loc(self.default_alt_loc) 1863 1864 else: ## alt_loc!="" 1865 1866 ## CASE: 1867 ## add an atom with alt_loc partners to the 1868 ## fragment for the first time 1869 ## procedure: 1870 ## *check for atoms without alt_locs already in the 1871 ## fragment, and 1872 ## *create new Altloc, and place it in the 1873 ## alt_loc_dict under the atom name 1874 ## *add the atom to the atom_order_list to preserve 1875 ## sequential order of added atoms 1876 ## *place atom in the atom_list and atom_dict 1877 1878 if not self.alt_loc_dict.has_key(name): 1879 1880 if not self.atom_dict.has_key(name): 1881 ## CASE: 1882 ## add an atom with alt_loc partners to the 1883 ## fragment for the first time 1884 self.alt_loc_dict[name] = altloc = Altloc() 1885 altloc.add_atom(atom) 1886 1887 self.atom_order_list.append(altloc) 1888 1889 self.atom_list.append(atom) 1890 self.atom_dict[name] = atom 1891 1892 else: 1893 ## CASE: 1894 ## add atom with alt_loc, but there is already a 1895 ## atom in the fragment with a null alt_loc which 1896 ## needs to be given a valid alt_loc and placed 1897 ## in the Altloc container before adding the new 1898 ## atom 1899 atomA = self.atom_dict[name] 1900 iA = self.atom_order_list.index(atomA) 1901 1902 self.alt_loc_dict[name] = altloc = Altloc() 1903 self.atom_order_list[iA] = altloc 1904 1905 altloc.add_atom(atomA) 1906 altloc.add_atom(atom) 1907 1908 else: 1909 ## CASE: 1910 ## add an atom with alt_loc partners to the 1911 ## fragment when there are already alt_loc 1912 ## partner atoms in the fragment 1913 altloc = self.alt_loc_dict[name] 1914 altloc.add_atom(atom) 1915 1916 self.set_default_alt_loc(self.default_alt_loc) 1917 1918 atom.fragment = self
1919
1920 - def remove_atom(self, atom):
1921 """Removes the Atom instance from the Fragment. 1922 """ 1923 assert atom.fragment == self 1924 1925 if self.alt_loc_dict.has_key(atom.name): 1926 altloc = self.alt_loc_dict[atom.name] 1927 if altloc.has_key(atom.alt_loc): 1928 altloc.remove_atom(atom) 1929 if len(altloc) == 0: 1930 del self.alt_loc_dict[atom.name] 1931 self.atom_order_list.remove(altloc) 1932 if atom in self.atom_list: 1933 self.atom_list.remove(atom) 1934 del self.atom_dict[atom.name] 1935 else: 1936 self.atom_order_list.remove(atom) 1937 self.atom_list.remove(atom) 1938 del self.atom_dict[atom.name] 1939 1940 atom.fragment = None
1941
1942 - def get_atom(self, name, alt_loc = None):
1943 """Returns the matching Atom instance contained in the Fragment. 1944 Returns None if a match is not found. If alt_loc is not given, 1945 then the default alt_loc is used. 1946 """ 1947 if alt_loc: 1948 if self.alt_loc_dict.has_key(name): 1949 altloc = self.alt_loc_dict[name] 1950 if altloc.has_key(alt_loc): 1951 return altloc[alt_loc] 1952 return None 1953 else: 1954 if not self.atom_dict.has_key(name): 1955 return None 1956 return self.atom_dict[name]
1957
1958 - def get_equivalent_atom(self, atom):
1959 """Returns the atom with the same fragment_id and name as the 1960 argument atom, or None if it is not found. 1961 """ 1962 try: 1963 return self.atom_dict[atom.name] 1964 except KeyError: 1965 return None
1966
1967 - def iter_atoms(self):
1968 """Iterates over all Atom objects contained in the Fragment matching 1969 the current model and default alt_loc. 1970 """ 1971 return iter(self.atom_list)
1972
1973 - def count_atoms(self):
1974 """Counts Atom objects. 1975 """ 1976 return len(self.atom_list)
1977
1978 - def iter_all_atoms(self):
1979 """Iterates of all Atoms in the Fragment including Altlocs. 1980 """ 1981 for atm in self.atom_order_list: 1982 if isinstance(atm, Atom): 1983 yield atm 1984 else: 1985 for atmx in atm: 1986 yield atmx
1987
1988 - def count_all_atoms(self):
1989 """Counts all Atom objects including Atoms in alternate conformations. 1990 """ 1991 n = 0 1992 for atm in self.atom_order_list: 1993 if isinstance(atm, Atom): 1994 n += 1 1995 else: 1996 n += len(atm) 1997 return n
1998
1999 - def iter_bonds(self):
2000 """Iterates over all Bond objects. The iteration is preformed by 2001 iterating over all Atom objects in the same order as iter_atoms(), 2002 then iterating over each Atom's Bond objects.""" 2003 visited = {} 2004 for atm in self.iter_atoms(): 2005 for bond in atm.iter_bonds(): 2006 if not visited.has_key(bond): 2007 yield bond 2008 visited[bond] = True
2009
2010 - def get_offset_fragment(self, offset):
2011 """Returns the fragment in the same chain at integer offset from 2012 self. Returns None if no fragment is found. 2013 """ 2014 assert isinstance(offset, int) 2015 2016 i = self.chain.index(self) + offset 2017 if i < 0: 2018 return None 2019 try: 2020 return self.chain[i] 2021 except IndexError: 2022 return None
2023
2024 - def get_model(self):
2025 """Returns the parent Chain object. 2026 """ 2027 return self.chain.model
2028
2029 - def get_chain(self):
2030 """Returns the parent Chain object. 2031 """ 2032 return self.chain
2033
2034 - def get_structure(self):
2035 """Returns the parent Structure object. 2036 """ 2037 return self.chain.model.structure
2038
2039 - def create_bonds(self):
2040 """Constructs bonds within a fragment. Bond definitions are retrieved 2041 from the monomer library. 2042 """ 2043 mdesc = Library.library_get_monomer_desc(self.res_name) 2044 if mdesc is None: 2045 return 2046 2047 def find_atom(name): 2048 try: 2049 return self[name] 2050 except KeyError: 2051 return self[mdesc.alt_atom_dict[name]]
2052 for bond in mdesc.bond_list: 2053 try: 2054 atm1 = find_atom(bond["atom1"]) 2055 atm2 = find_atom(bond["atom2"]) 2056 except KeyError: 2057 continue 2058 else: 2059 atm1.create_bonds(atom = atm2, standard_res_bond = True)
2060
2061 - def is_standard_residue(self):
2062 """Returns True if the Fragment/Residue object is one of the 2063 PDB defined standard residues. PDB standard residues are amino 2064 and nucleic acid residues. 2065 """ 2066 return False
2067
2068 - def is_amino_acid(self):
2069 """Returns True if the Fragment is an Amino Acid residue. 2070 """ 2071 return False
2072
2073 - def is_nucleic_acid(self):
2074 """Returns True if the Fragment is a Nucleic Acid residue. 2075 """ 2076 return False
2077
2078 - def is_water(self):
2079 """Returns True if the Fragment is a water molecule, returns False 2080 otherwise. 2081 """ 2082 return Library.library_is_water(self.res_name)
2083
2084 - def set_model_id(self, model_id):
2085 """Sets the model_id of the Fragment and all contained Atom 2086 objects. 2087 """ 2088 assert isinstance(model_id, int) 2089 self.model_id = model_id 2090 2091 for atm in self.iter_atoms(): 2092 atm.set_model_id(model_id)
2093
2094 - def set_chain_id(self, chain_id):
2095 """Sets the chain_id of the Fragment and all contained Atom objects. 2096 """ 2097 assert isinstance(chain_id, str) 2098 self.chain_id = chain_id 2099 2100 for atm in self.iter_atoms(): 2101 atm.set_chain_id(chain_id)
2102
2103 - def set_fragment_id(self, fragment_id):
2104 """Sets the fragment_id of the Fragment and all contained Atom 2105 objects. 2106 """ 2107 assert isinstance(fragment_id, str) 2108 2109 if self.chain is not None: 2110 chk_frag = self.chain.get_fragment(fragment_id) 2111 if chk_frag is not None or chk_frag != self: 2112 raise FragmentOverwrite() 2113 2114 self.fragment_id = fragment_id 2115 2116 for atm in self.iter_atoms(): 2117 atm.set_fragment_id(fragment_id) 2118 2119 if self.chain is not None: 2120 self.chain.sort()
2121
2122 - def set_res_name(self, res_name):
2123 """Sets the res_name of the Fragment and all contained Atom 2124 objects. 2125 """ 2126 assert isinstance(res_name, str) 2127 self.res_name = res_name 2128 2129 for atm in self.iter_atoms(): 2130 atm.set_res_name(res_name)
2131 2132
2133 -class Residue(Fragment):
2134 """A subclass of Fragment representing one residue in a polymer chain. 2135 """
2136 - def __str__(self):
2137 return "Res(%s,%s,%s)" % (self.res_name, 2138 self.fragment_id, 2139 self.chain_id)
2140
2141 - def get_offset_residue(self, offset):
2142 """Returns the residue along the chain at the given integer offset 2143 from self. Returns None if there is no residue at that offset, or 2144 if the fragment found is not the same type of residue as self. 2145 """ 2146 assert isinstance(offset, int) 2147 frag = Fragment.get_offset_fragment(self, offset) 2148 if type(self) == type(frag): 2149 return frag 2150 return None
2151
2152 - def create_bonds(self):
2153 """Constructs bonds within a fragment. Bond definitions are retrieved 2154 from the monomer library. This version also constructs the bonds 2155 between adjacent residues. 2156 """ 2157 Fragment.create_bonds(self) 2158 return 2159 2160 ## XXX: fixme 2161 next_res = self.get_offset_residue(1) 2162 if next_res is None: 2163 return 2164 2165 mdesc1 = Library.library_get_monomer_desc(self.res_name) 2166 mdesc2 = Library.library_get_monomer_desc(next_res.res_name) 2167 2168 if mdesc1 is None or mdesc2 is None: 2169 return 2170 2171 for (name1, name2) in mdesc1.get_polymer_bond_list(self, next_res): 2172 try: 2173 atm1 = self[name1] 2174 atm2 = next_res[name2] 2175 except KeyError: 2176 continue 2177 else: 2178 atm1.create_bonds(atom = atm2, standard_res_bond = True)
2179 2180
2181 -class AminoAcidResidue(Residue):
2182 """A subclass of Residue representing one amino acid residue in a 2183 polypeptide chain. 2184 """
2185 - def __deepcopy__(self, memo):
2186 fragment = AminoAcidResidue( 2187 model_id = self.model_id, 2188 res_name = self.res_name, 2189 fragment_id = self.fragment_id, 2190 chain_id = self.chain_id) 2191 2192 for atom in self.iter_all_atoms(): 2193 fragment.add_atom(copy.deepcopy(atom, memo)) 2194 2195 return fragment
2196
2197 - def is_standard_residue(self):
2198 """Returns True if the Fragment/Residue object is one of the 2199 PDB defined standard residues. PDB standard residues are amino 2200 and nucleic acid residues. 2201 """ 2202 return True
2203
2204 - def is_amino_acid(self):
2205 """Returns True if the Fragment is an Amino Acid residue. 2206 """ 2207 return True
2208
2209 - def is_water(self):
2210 """Returns True if the Fragment is a water molecule, returns False 2211 otherwise. 2212 """ 2213 return False
2214
2215 - def calc_mainchain_bond_length(self):
2216 """Calculates the main chain bond lengths: (N-CA, CA-C, C-O, CA-CB, 2217 CA-(next)N). The result is returned as a 5-tuple in that order. Bond 2218 lengths involving missing atoms are returned as None in the tuple. 2219 """ 2220 aN = self.get_atom('N') 2221 aCA = self.get_atom('CA') 2222 aC = self.get_atom('C') 2223 aO = self.get_atom('O') 2224 aCB = self.get_atom('CB') 2225 2226 try: 2227 naN = self.get_offset_residue(1).get_atom('N') 2228 except AttributeError: 2229 naN = None 2230 2231 N_CA = AtomMath.calc_distance(aN, aCA) 2232 CA_C = AtomMath.calc_distance(aCA, aC) 2233 C_O = AtomMath.calc_distance(aC, aO) 2234 C_nN = AtomMath.calc_distance(aC, naN) 2235 CA_CB = AtomMath.calc_distance(aCA, aCB) 2236 return (N_CA, CA_C, C_O, CA_CB, C_nN)
2237
2238 - def calc_mainchain_bond_angle(self):
2239 """Calculates main chain bond angles (N-CA-C, N-CA-CB, CB-CA-C, 2240 CA-C-O, CA-C-(next)N, C-(next residue)N-(next residue)CA) and 2241 returns the result as a 6-tuple in that order. Angles involving 2242 missing atoms are returned as None in the tuple. 2243 """ 2244 aN = self.get_atom('N') 2245 aCA = self.get_atom('CA') 2246 aC = self.get_atom('C') 2247 aO = self.get_atom('O') 2248 aCB = self.get_atom('CB') 2249 2250 naN = None 2251 naCA = None 2252 next_res = self.get_offset_residue(1) 2253 if next_res: 2254 naN = next_res.get_atom('N') 2255 naCA = next_res.get_atom('CA') 2256 2257 N_CA_C = AtomMath.calc_angle(aN, aCA, aC) 2258 CA_C_O = AtomMath.calc_angle(aCA, aC, aO) 2259 N_CA_CB = AtomMath.calc_angle(aN, aCA, aCB) 2260 CB_CA_C = AtomMath.calc_angle(aCB, aCA, aC) 2261 CA_C_nN = AtomMath.calc_angle(aCA, aC, naN) 2262 C_nN_nCA = AtomMath.calc_angle(aC, naN, naCA) 2263 2264 return (N_CA_C, N_CA_CB, CB_CA_C, CA_C_O, CA_C_nN, C_nN_nCA)
2265
2266 - def calc_torsion_psi(self):
2267 """Calculates the Psi torsion angle of the amino acid. Raises a 2268 CTerminal exception if called on a C-terminal residue which does 2269 not have a Psi torsion angle. 2270 """ 2271 next_res = self.get_offset_residue(1) 2272 if next_res is None: 2273 return None 2274 2275 aN = self.get_atom('N') 2276 aCA = self.get_atom('CA') 2277 aC = self.get_atom('C') 2278 naN = next_res.get_atom('N') 2279 return AtomMath.calc_torsion_angle(aN, aCA, aC, naN)
2280
2281 - def calc_torsion_phi(self):
2282 """Calculates the Phi torsion angle of the amino acid. Raises a 2283 NTerminal exception if called on an N-terminal residue which does 2284 not have a Phi torsion angle. 2285 """ 2286 prev_res = self.get_offset_residue(-1) 2287 if prev_res is None: 2288 return None 2289 2290 paC = prev_res.get_atom('C') 2291 aN = self.get_atom('N') 2292 aCA = self.get_atom('CA') 2293 aC = self.get_atom('C') 2294 return AtomMath.calc_torsion_angle(paC, aN, aCA, aC)
2295
2296 - def calc_torsion_omega(self):
2297 """Calculates the Omega torsion angle of the amino acid. Raises a 2298 CTerminal exception if called on a C-terminal residue which does 2299 not have an Omega torsion angle. 2300 """ 2301 next_res = self.get_offset_residue(1) 2302 if next_res is None: 2303 return None 2304 2305 aCA = self.get_atom('CA') 2306 aC = self.get_atom('C') 2307 naN = next_res.get_atom('N') 2308 naCA = next_res.get_atom('CA') 2309 return AtomMath.calc_torsion_angle(aCA, aC, naN, naCA)
2310
2311 - def is_cis(self):
2312 """Returns True if this is a CIS amino acid, otherwise returns False. 2313 It uses calc_torsion_omega, and if there are missing atoms this method 2314 will return None. 2315 """ 2316 prev_res = self.get_offset_residue(-1) 2317 if prev_res is None: 2318 return None 2319 2320 prev_omega = prev_res.calc_torsion_omega() 2321 if prev_omega is None: 2322 return None 2323 2324 if abs(prev_omega) <= (math.pi/2.0): 2325 return True 2326 2327 return False
2328
2329 - def calc_torsion(self, torsion_angle_name):
2330 """Calculates the given torsion angle for the monomer. The torsion 2331 angles are defined by name in monomers.cif. 2332 """ 2333 mdesc = Library.library_get_monomer_desc(self.res_name) 2334 try: 2335 (atom1_name, 2336 atom2_name, 2337 atom3_name, 2338 atom4_name) = mdesc.torsion_angle_dict[torsion_angle_name] 2339 except KeyError: 2340 return None 2341 2342 atom1 = self.get_atom(atom1_name) 2343 atom2 = self.get_atom(atom2_name) 2344 atom3 = self.get_atom(atom3_name) 2345 atom4 = self.get_atom(atom4_name) 2346 2347 return AtomMath.calc_torsion_angle(atom1, atom2, atom3, atom4)
2348
2349 - def calc_torsion_chi1(self):
2350 return self.calc_torsion("chi1")
2351
2352 - def calc_torsion_chi2(self):
2353 return self.calc_torsion("chi2")
2354
2355 - def calc_torsion_chi3(self):
2356 return self.calc_torsion("chi3")
2357
2358 - def calc_torsion_chi4(self):
2359 return self.calc_torsion("chi4")
2360
2361 - def calc_torsion_chi(self):
2362 """Calculates CHI side-chain torsion angles according to the 2363 amino acid specific definitions in the AminoAcids library. 2364 Returns the 4-tuple (CHI1, CHI2, CHI3, CHI4). Angles involving 2365 missing atoms, or angles which do not exist for the amino acid 2366 are returned as None in the tuple. 2367 """ 2368 return (self.calc_torsion("chi1"), 2369 self.calc_torsion("chi2"), 2370 self.calc_torsion("chi3"), 2371 self.calc_torsion("chi4"))
2372
2373 - def calc_pucker_torsion(self):
2374 """Calculates the Pucker torsion of a ring system. Returns None 2375 for Amino Acids which do not have Pucker torsion angles. 2376 """ 2377 return self.calc_torsion("pucker")
2378 2379
2380 -class NucleicAcidResidue(Residue):
2381 """A subclass of Residue representing one nuclic acid in a strand of 2382 DNA or RNA. 2383 """
2384 - def __deepcopy__(self, memo):
2385 fragment = NucleicAcidResidue( 2386 model_id = self.model_id, 2387 res_name = self.res_name, 2388 fragment_id = self.fragment_id, 2389 chain_id = self.chain_id) 2390 2391 for atom in self.iter_all_atoms(): 2392 fragment.add_atom(copy.deepcopy(atom, memo)) 2393 2394 return fragment
2395
2396 - def is_standard_residue(self):
2397 """Returns True if the Fragment/Residue object is one of the 2398 PDB defined standard residues. PDB standard residues are amino 2399 and nucleic acid residues. 2400 """ 2401 return True
2402
2403 - def is_nucleic_acid(self):
2404 """Returns True if the Fragment is a Nucleic Acid residue. 2405 """ 2406 return True
2407
2408 - def is_water(self):
2409 """Returns True if the Fragment is a water molecule, returns False 2410 otherwise. 2411 """ 2412 return False
2413 2414
2415 -class Altloc(dict):
2416 """Container holding the same atom, but for different conformations and 2417 occupancies. 2418 """
2419 - def __deepcopy__(self, memo):
2420 altloc = Altloc() 2421 for atom in self.itervalues(): 2422 altloc.add_atom(copy.deepcopy(atom, memo)) 2423 return altloc
2424
2425 - def __iter__(self):
2426 """Iterates over all Altloc representations of this Atom. 2427 """ 2428 alt_locs = self.keys() 2429 alt_locs.sort() 2430 for alt_loc in alt_locs: 2431 yield self[alt_loc]
2432
2433 - def add_atom(self, atom):
2434 """Adds an atom to the Altloc. 2435 """ 2436 if self.has_key(atom.alt_loc) or atom.alt_loc == "": 2437 atom.alt_loc = self.calc_next_alt_loc_id(atom) 2438 2439 self[atom.alt_loc] = atom 2440 atom.altloc = self
2441
2442 - def remove_atom(self, atom):
2443 """Removes the atom from this Altloc container. 2444 """ 2445 assert atom.altloc == self 2446 del self[atom.alt_loc] 2447 atom.altloc = None
2448
2449 - def calc_next_alt_loc_id(self, atom):
2450 """Returns the next vacant alt_loc letter to be used for a key. 2451 This is part of a half-ass algorithm to deal with disordered 2452 input Atoms with improper alt_loc tagging. 2453 """ 2454 if len(self) == 0: 2455 return "A" 2456 for alt_loc in string.uppercase: 2457 if not self.has_key(alt_loc): 2458 return alt_loc 2459 2460 raise AtomOverwrite("exhausted availible alt_loc labels for "+str(atom))
2461 2462
2463 -class Atom(object):
2464 """Class representing a single atom. Atoms have the following default 2465 attributes. If an attribute has the value None, then the attribute was 2466 never set. If the attribute has a default, then it is required. 2467 2468 Atom[alt_loc] - Atom objects in alternate locations can be accessed 2469 by using Python's dictionary syntax with the alt_loc 2470 character 2471 iter(Atom) - iterates over all alt_loc versions of the Atom 2472 Atom.name - label of the atom 2473 Atom.alt_loc - alternate location indicater for the atom 2474 Atom.res_name - the name of the resiude/fragment this atom is part of 2475 Atom.res_seq - the residue/fragment sequence number 2476 Atom.icode - the insertion code for the residue/fragment 2477 Atom.chain_id - the chain ID of the chain containing this atom 2478 Atom.element - symbol for the element 2479 Atom.position - a numpy.array[3] (Numeric Python) 2480 Atom.occupancy - [1.0 - 0.0] float 2481 Atom.temp_factor - float represting B-style temp factor 2482 Atom.column6768 - string value. Can be used for anything in columns 67+68 2483 Atom.U - a 6-tuple of the anisotropic values 2484 Atom.charge - charge on the atom 2485 Atom.label_entity_id - 2486 entity id corresponding to entity_poly_seq.entity_id 2487 Atom.label_asym_id - 2488 asym id corresponding to struct_conf.beg_label_asym_id 2489 Atom.label_seq_id - 2490 sequence id corresponding to entity_poly_seq_num 2491 and struct_conn.ptnr?_label_seq_id 2492 """
2493 - def __init__( 2494 self, 2495 name = "", 2496 alt_loc = "", 2497 res_name = "", 2498 fragment_id = "", 2499 chain_id = "", 2500 model_id = 1, 2501 element = "", 2502 position = None, 2503 x = None, 2504 y = None, 2505 z = None, 2506 sig_position = None, 2507 sig_x = None, 2508 sig_y = None, 2509 sig_z = None, 2510 temp_factor = None, 2511 column6768 = None, 2512 sig_temp_factor = None, 2513 occupancy = None, 2514 sig_occupancy = None, 2515 charge = None, 2516 label_entity_id = None, 2517 label_asym_id = None, 2518 label_seq_id = None, 2519 2520 U = None, 2521 u11 = None, u22 = None, u33 = None, 2522 u12 = None, u13 = None, u23 = None, 2523 2524 sig_U = None, 2525 sig_u11 = None, sig_u22 = None, sig_u33 = None, 2526 sig_u12 = None, sig_u13 = None, sig_u23 = None, 2527 2528 **args):
2529 2530 assert isinstance(name, str) 2531 assert isinstance(model_id, int) 2532 assert isinstance(alt_loc, str) 2533 assert isinstance(res_name, str) 2534 assert isinstance(fragment_id, str) 2535 assert isinstance(chain_id, str) 2536 2537 self.fragment = None 2538 self.altloc = None 2539 2540 self.name = name 2541 self.alt_loc = alt_loc 2542 self.res_name = res_name 2543 self.fragment_id = fragment_id 2544 self.chain_id = chain_id 2545 self.asym_id = chain_id 2546 self.model_id = model_id 2547 self.element = element 2548 self.temp_factor = temp_factor 2549 self.column6768 = column6768 2550 self.sig_temp_factor = sig_temp_factor 2551 self.occupancy = occupancy 2552 self.sig_occupancy = sig_occupancy 2553 self.charge = charge 2554 self.label_entity_id = label_entity_id 2555 self.label_asym_id = label_asym_id 2556 self.label_seq_id = label_seq_id 2557 2558 ## position 2559 if position is not None: 2560 self.position = position 2561 elif x is not None and y is not None and z is not None: 2562 self.position = numpy.array([x, y, z], float) 2563 else: 2564 self.position = None 2565 2566 ## sig_position 2567 if sig_position is not None: 2568 self.sig_position = sig_position 2569 elif sig_x is not None and sig_y is not None and sig_z is not None: 2570 self.sig_position = numpy.array([sig_x, sig_y, sig_z], float) 2571 else: 2572 self.sig_position = None 2573 2574 if U is not None: 2575 self.U = U 2576 elif u11 is not None: 2577 self.U = numpy.array( 2578 [ [u11, u12, u13], 2579 [u12, u22, u23], 2580 [u13, u23, u33] ], float) 2581 else: 2582 self.U = None 2583 2584 if sig_U is not None: 2585 self.sig_U = sig_U 2586 elif sig_u11 is not None: 2587 self.sig_U = numpy.array( 2588 [ [sig_u11, sig_u12, sig_u13], 2589 [sig_u12, sig_u22, sig_u23], 2590 [sig_u13, sig_u23, sig_u33] ], float) 2591 else: 2592 self.sig_U = None 2593 2594 self.bond_list = []
2595
2596 - def __str__(self):
2597 return "Atom(n=%s alt=%s res=%s chn=%s frag=%s mdl=%d)" % ( 2598 self.name, self.alt_loc, self.res_name, 2599 self.chain_id, self.fragment_id, self.model_id) 2600 2601 return "Atom(%4s%2s%4s%2s%4s%2d)" % ( 2602 self.name, self.alt_loc, self.res_name, 2603 self.chain_id, self.fragment_id, self.model_id)
2604
2605 - def __deepcopy__(self, memo):
2606 atom_cpy = Atom( 2607 name = self.name, 2608 alt_loc = self.alt_loc, 2609 res_name = self.res_name, 2610 fragment_id = self.fragment_id, 2611 chain_id = self.chain_id, 2612 model_id = copy.copy(self.model_id), 2613 element = self.element, 2614 position = copy.deepcopy(self.position), 2615 sig_position = copy.deepcopy(self.sig_position), 2616 temp_factor = copy.copy(self.temp_factor), 2617 column6768 = copy.copy(self.column6768), 2618 sig_temp_factor = copy.copy(self.sig_temp_factor), 2619 occupancy = copy.copy(self.occupancy), 2620 sig_occupancy = copy.copy(self.sig_occupancy), 2621 charge = copy.copy(self.charge), 2622 U = copy.deepcopy(self.U), 2623 sig_U = copy.deepcopy(self.sig_U), 2624 label_entity_id = self.label_entity_id, 2625 label_asym_id = self.label_asym_id, 2626 label_seq_id = self.label_seq_id) 2627 2628 for bond in self.bond_list: 2629 partner = bond.get_partner(self) 2630 if memo.has_key(id(partner)): 2631 partner_cpy = memo[id(partner)] 2632 bond_cpy = copy.deepcopy(bond, memo) 2633 2634 if bond.atom1 == self: 2635 bond_cpy.atom1 = atom_cpy 2636 bond_cpy.atom2 = partner_cpy 2637 else: 2638 bond_cpy.atom1 = partner_cpy 2639 bond_cpy.atom2 = atom_cpy 2640 2641 atom_cpy.bond_list.append(bond_cpy) 2642 partner_cpy.bond_list.append(bond_cpy) 2643 2644 return atom_cpy
2645
2646 - def __lt__(self, other):
2647 assert isinstance(other, Atom) 2648 2649 if self.chain_id < other.chain_id: 2650 return True 2651 if self.chain_id > other.chain_id: 2652 return False 2653 2654 if fragment_id_lt(self.fragment_id, other.fragment_id): 2655 return True 2656 if fragment_id_gt(self.fragment_id, other.fragment_id): 2657 return False 2658 2659 if self.name < other.name: 2660 return True 2661 if self.name > other.name: 2662 return False 2663 2664 if self.alt_loc == "" and other.alt_loc != "": 2665 return False 2666 if self.alt_loc != "" and other.alt_loc == "": 2667 return True 2668 2669 return self.name < other.name
2670
2671 - def __le__(self, other):
2672 assert isinstance(other, Atom) 2673 2674 if self.chain_id < other.chain_id: 2675 return True 2676 if self.chain_id > other.chain_id: 2677 return False 2678 2679 if fragment_id_lt(self.fragment_id, other.fragment_id): 2680 return True 2681 if fragment_id_gt(self.fragment_id, other.fragment_id): 2682 return False 2683 2684 if self.name < other.name: 2685 return True 2686 if self.name > other.name: 2687 return False 2688 2689 if self.alt_loc == "" and other.alt_loc != "": 2690 return False 2691 if self.alt_loc != "" and other.alt_loc == "": 2692 return True 2693 2694 return self.name <= other.name
2695
2696 - def __gt__(self, other):
2697 assert isinstance(other, Atom) 2698 2699 if self.chain_id > other.chain_id: 2700 return True 2701 if self.chain_id < other.chain_id: 2702 return False 2703 2704 if fragment_id_gt(self.fragment_id, other.fragment_id): 2705 return True 2706 if fragment_id_lt(self.fragment_id, other.fragment_id): 2707 return False 2708 2709 if self.name > other.name: 2710 return True 2711 if self.name < other.name: 2712 return False 2713 2714 if self.alt_loc == "" and other.alt_loc != "": 2715 return True 2716 if self.alt_loc != "" and other.alt_loc == "": 2717 return False 2718 2719 return self.name > other.name
2720
2721 - def __ge__(self, other):
2722 assert isinstance(other, Atom) 2723 2724 if self.chain_id > other.chain_id: 2725 return True 2726 if self.chain_id < other.chain_id: 2727 return False 2728 2729 if fragment_id_gt(self.fragment_id, other.fragment_id): 2730 return True 2731 if fragment_id_lt(self.fragment_id, other.fragment_id): 2732 return False 2733 2734 if self.name > other.name: 2735 return True 2736 if self.name < other.name: 2737 return False 2738 2739 if self.alt_loc == "" and other.alt_loc != "": 2740 return True 2741 if self.alt_loc != "" and other.alt_loc == "": 2742 return False 2743 2744 return self.name >= other.name
2745
2746 - def __len__(self):
2747 """Returns the number of alternate conformations of this atom. 2748 """ 2749 if self.altloc: 2750 return len(self.altloc) 2751 return 0
2752
2753 - def __getitem__(self, alt_loc):
2754 """This is an alternative to calling get_alt_loc, but a KeyError 2755 exception is raised if the alt_loc Atom is not found. 2756 """ 2757 assert isinstance(alt_loc, str) 2758 2759 if self.altloc is None: 2760 if self.alt_loc == alt_loc: 2761 return self 2762 raise KeyError, alt_loc 2763 2764 else: 2765 return self.altloc[alt_loc]
2766
2767 - def __iter__(self):
2768 """Iterates over all Altloc representations of this Atom. 2769 """ 2770 if self.altloc is None: 2771 yield self 2772 2773 else: 2774 alt_locs = self.altloc.keys() 2775 alt_locs.sort() 2776 for alt_loc in alt_locs: 2777 yield self.altloc[alt_loc]
2778
2779 - def __contains__(self, atom_alt_loc):
2780 """Returns True if the argument matches an alternate conformation of 2781 the Atom. The argument can be an alt_loc label, or an Atom object. 2782 """ 2783 if isinstance(atom_alt_loc, Atom): 2784 if self.altloc is None: 2785 return atom_alt_loc == self 2786 else: 2787 return self.altloc[atom_alt_loc.alt_loc] == atom_alt_loc 2788 2789 elif isinstance(atom_alt_loc, str): 2790 if self.altloc is None: 2791 return atom_alt_loc == self.alt_loc 2792 else: 2793 return self.altloc.__contains__(atom_alt_loc) 2794 2795 return False
2796
2797 - def remove_alt_loc(self, atom):
2798 """Removes the argument Atom from the Altloc. 2799 """ 2800 try: 2801 self.fragment.remove_atom(atom) 2802 except AttributeError: 2803 if self.altloc is not None and self.altloc.has_key(atom.alt_loc): 2804 del self.altloc[atom.alt_loc]
2805
2806 - def get_alt_loc(self, alt_loc):
2807 """Returns the Atom object matching the alt_loc argument. 2808 """ 2809 try: 2810 return self[alt_loc] 2811 except KeyError: 2812 return None
2813
2814 - def iter_alt_loc(self):
2815 """Iterate over all alt_loc versions of this atom in the 2816 alphabetical order of the alt_loc labels, within the current model. 2817 """ 2818 return iter(self)
2819
2820 - def create_bond(self, 2821 atom = None, 2822 bond_type = None, 2823 atom1_symop = None, 2824 atom2_symop = None, 2825 standard_res_bond = False):
2826 2827 """Creates a bond between this atom and the argumentatom. The 2828 argument bond_type is a string, atom1_symop and atom2_symop are 2829 symmetry operations to be applied to self and the argument atom 2830 before distance calculations, and standard_res_bond is a flag 2831 used to indicate this bond is a standard bond. 2832 """ 2833 assert isinstance(atom, Atom) 2834 assert ((self.alt_loc == atom.alt_loc) or 2835 (self.alt_loc == "" and atom.alt_loc != "") or 2836 (self.alt_loc != "" and atom.alt_loc == "")) 2837 2838 bond = Bond(atom1 = self, 2839 atom2 = atom, 2840 bond_type = bond_type, 2841 atom1_symop = atom1_symop, 2842 atom2_symop = atom2_symop, 2843 standard_res_bond = standard_res_bond) 2844 2845 self.bond_list.append(bond) 2846 atom.bond_list.append(bond)
2847
2848 - def create_bonds(self, 2849 atom = None, 2850 bond_type = None, 2851 atom1_symop = None, 2852 atom2_symop = None, 2853 standard_res_bond = False):
2854 """Like create_bonds, but it bonds all alternate locations of this 2855 atom. 2856 """ 2857 assert isinstance(atom, Atom) 2858 2859 if self.altloc is None: 2860 if atom.altloc is None: 2861 ## case 1: self has no alt_loc, atom no alt_loc 2862 self.create_bond( 2863 atom = atom, 2864 bond_type = bond_type, 2865 atom1_symop = atom1_symop, 2866 atom2_symop = atom2_symop, 2867 standard_res_bond = standard_res_bond) 2868 else: 2869 ## case 2: self.has no alt_loc, atom has alt_loc 2870 for atmx in atom.altloc.itervalues(): 2871 self.create_bond( 2872 atom = atmx, 2873 bond_type = bond_type, 2874 atom1_symop = atom1_symop, 2875 atom2_symop = atom2_symop, 2876 standard_res_bond = standard_res_bond) 2877 2878 2879 else: 2880 if atom.altloc is None: 2881 ## case 3: self has alt_loc, atom has no alt_loc 2882 for (alt_loc, atmx) in self.altloc.iteritems(): 2883 atmx.create_bond( 2884 atom = atom, 2885 bond_type = bond_type, 2886 atom1_symop = atom1_symop, 2887 atom2_symop = atom2_symop, 2888 standard_res_bond = standard_res_bond) 2889 2890 else: 2891 ## case 4: self has alt_loc, atom has alt_loc 2892 for (alt_loc, atmx) in self.altloc.iteritems(): 2893 if atom.altloc.has_key(alt_loc): 2894 atmx.create_bond( 2895 atom = atom.altloc[alt_loc], 2896 bond_type = bond_type, 2897 atom1_symop = atom1_symop, 2898 atom2_symop = atom2_symop, 2899 standard_res_bond = standard_res_bond)
2900
2901 - def get_bond(self, atom):
2902 """Returns the Bond connecting self with the argument atom. 2903 """ 2904 assert isinstance(atom, Atom) 2905 assert atom != self 2906 2907 for bond in self.bond_list: 2908 if atom == bond.atom1 or atom == bond.atom2: 2909 return bond 2910 return None
2911
2912 - def iter_bonds(self):
2913 """Iterates over all the Bond edges connected to self. 2914 """ 2915 for bond in self.bond_list: 2916 yield bond
2917
2918 - def iter_bonded_atoms(self):
2919 """Iterates over all the Atoms bonded to self. 2920 """ 2921 for bond in self.iter_bonds(): 2922 partner = bond.get_partner(self) 2923 assert partner is not None 2924 yield partner
2925
2926 - def get_bonded_atom(self, name_list):
2927 """From atom, follow the bonding path specified by a sequence of atom 2928 names given in name_list and return the last atom instance in the 2929 list. Returns None if any atom in the bonding path cannot be found. 2930 """ 2931 current_atom = self 2932 for name in name_list: 2933 moveto_atom = None 2934 for atom in current_atom.iter_bonded_atoms(): 2935 if atom.name == name: 2936 moveto_atom = atom 2937 break 2938 if moveto_atom is None: 2939 return None 2940 current_atom = moveto_atom 2941 return current_atom
2942
2943 - def get_fragment(self):
2944 """Returns the parent Fragment object. 2945 """ 2946 return self.fragment
2947
2948 - def get_chain(self):
2949 """Returns the parent Chain object. 2950 """ 2951 return self.fragment.chain
2952
2953 - def get_model(self):
2954 """Returns the parent Model object. 2955 """ 2956 return self.fragment.chain.model
2957
2958 - def get_structure(self):
2959 """Returns the parent Structure object. 2960 """ 2961 return self.fragment.chain.model.structure
2962
2963 - def set_U(self, u11, u22, u33, u12, u13, u23):
2964 """Sets the symmetric U tensor from the six unique values. 2965 """ 2966 self.U = numpy.array([[u11, u12, u13], 2967 [u12, u22, u23], 2968 [u13, u23, u33]], float)
2969
2970 - def set_sig_U(self, u11, u22, u33, u12, u13, u23):
2971 """Sets the symmetric sig_U tensor from the six unique values. 2972 """ 2973 self.sig_U = numpy.array([[u11, u12, u13], 2974 [u12, u22, u23], 2975 [u13, u23, u33]], float)
2976
2977 - def calc_Uiso(self):
2978 """Calculates the Uiso tensor from the Atom's temperature factor. 2979 """ 2980 if self.temp_factor is None: 2981 return None 2982 return numpy.identity(3, float) * (self.temp_factor * Constants.B2U)
2983
2984 - def get_U(self):
2985 """Returns the Atoms's U tensor if it exists, otherwise returns 2986 the isotropic U tensor calculated by self.calc_Uiso 2987 """ 2988 if self.U is not None: 2989 return self.U 2990 return self.calc_Uiso()
2991
2992 - def calc_anisotropy(self):
2993 """Calculates the anisotropy of that atom. Anisotropy is defined 2994 as the ratio of the minimum/maximum eigenvalues of the 3x3 2995 symmetric tensor defined by U. 2996 """ 2997 ## no Anisotropic values, we have a spherical isotropic atom 2998 if self.U is None: 2999 return 1.0 3000 3001 evals = linalg.eigenvalues(self.U) 3002 ansotropy = min(evals) / max(evals) 3003 return ansotropy
3004
3005 - def calc_anisotropy3(self):
3006 """Calculates the eigenvalues of the U matrix and returns the 3007 3-tuple of the eigenvalue ratios: (e1/e2, e1/e3, e2/e3) 3008 """ 3009 ## no Anisotropic values, we have a spherical atom 3010 if self.U is None: 3011 return (1.0, 1.0, 1.0) 3012 3013 e1, e2, e3 = linalg.eigenvalues(self.U) 3014 elist = [e1, e2, e3] 3015 elist.sort() 3016 e1, e2, e3 = elist 3017 3018 return (min(e1, e2) / max(e1, e2), 3019 min(e1, e3) / max(e1, e3), 3020 min(e2, e3) / max(e2, e3))
3021
3022 - def iter_atoms_by_distance(self, max_distance = None):
3023 """Iterates all atoms in the Structure object from the closest to the 3024 farthest up to the cutoff distance max_distance if given. Yields 3025 the 2-tuple (dist, atm). 3026 """ 3027 listx = [] 3028 3029 if max_distance: 3030 for atm in self.get_structure().iter_atoms(): 3031 d = AtomMath.calc_distance(self, atm) 3032 if d <= max_distance: 3033 listx.append((AtomMath.calc_distance(self, atm), atm)) 3034 else: 3035 for atm in self.get_structure().iter_atoms(): 3036 listx.append((AtomMath.calc_distance(self, atm), atm)) 3037 3038 listx.sort() 3039 return iter(listx)
3040
3041 - def set_model_id(self, model_id):
3042 """Sets the chain_id of the Atom and all alt_loc Atom 3043 objects. 3044 """ 3045 assert isinstance(model_id, int) 3046 for atm in self.iter_alt_loc(): 3047 atm.model_id = model_id
3048
3049 - def set_chain_id(self, chain_id):
3050 """Sets the chain_id of the Atom and all alt_loc Atom 3051 objects. 3052 """ 3053 assert isinstance(chain_id, str) 3054 for atm in self.iter_alt_loc(): 3055 atm.chain_id = chain_id
3056
3057 - def set_fragment_id(self, fragment_id):
3058 """Sets the fragment_id of the Atom and all alt_loc Atom 3059 objects. 3060 """ 3061 assert isinstance(fragment_id, str) 3062 for atm in self.iter_alt_loc(): 3063 atm.fragment_id = fragment_id
3064
3065 - def set_res_name(self, res_name):
3066 """Sets the fragment_id of the Atom and all alt_loc Atom 3067 objects. 3068 """ 3069 assert isinstance(res_name, str) 3070 for atm in self.iter_alt_loc(): 3071 atm.res_name = res_name
3072 3073
3074 -class Bond(object):
3075 """Indicates two atoms are bonded together. 3076 """
3077 - def __init__( 3078 self, 3079 atom1 = None, 3080 atom2 = None, 3081 bond_type = None, 3082 atom1_symop = None, 3083 atom2_symop = None, 3084 standard_res_bond = False, 3085 **args):
3086 3087 self.atom1 = atom1 3088 self.atom2 = atom2 3089 self.bond_type = bond_type 3090 self.atom1_symop = atom1_symop 3091 self.atom2_symop = atom2_symop 3092 self.standard_res_bond = standard_res_bond
3093
3094 - def __str__(self):
3095 return "Bond(%s %s)" % (self.atom1, self.atom2)
3096
3097 - def __deepcopy__(self, memo):
3098 return Bond( 3099 bond_type = self.bond_type, 3100 atom1_symop = self.atom1_symop, 3101 atom2_symop = self.atom2_symop, 3102 standard_res_bond = self.standard_res_bond)
3103
3104 - def get_partner(self, atm):
3105 """Returns the other atom involved in the bond. 3106 """ 3107 if atm == self.atom1: 3108 return self.atom2 3109 elif atm == self.atom2: 3110 return self.atom1 3111 return None
3112
3113 - def get_atom1(self):
3114 """Returns atom #1 of the pair of bonded atoms. This is also 3115 accessible by bond.atom1. 3116 """ 3117 return self.atom1
3118
3119 - def get_atom2(self):
3120 """Returns atom #2 of the pair of bonded atoms. 3121 """ 3122 return self.atom2
3123
3124 - def get_fragment1(self):
3125 """Returns the Fragment object of atom #1. 3126 """ 3127 return self.atom1.fragment
3128
3129 - def get_fragment2(self):
3130 """Returns the Fragment object of atom #2. 3131 """ 3132 return self.atom2.fragment
3133
3134 - def get_chain1(self):
3135 """Returns the Chain object of atom #1. 3136 """ 3137 return self.atom1.fragment.chain
3138
3139 - def get_chain2(self):
3140 """Returns the Chain object of atom #2. 3141 """ 3142 return self.atom2.fragment.chain
3143
3144 - def get_model1(self):
3145 """Returns the Model object of atom #1. 3146 """ 3147 return self.atom1.fragment.chain.model
3148
3149 - def get_model2(self):
3150 """Returns the Structure object of atom #2. 3151 """ 3152 return self.atom2.fragment.chain.model
3153
3154 - def get_structure1(self):
3155 """Returns the Structure object of atom #1. 3156 """ 3157 return self.atom1.fragment.chain.model.structure
3158
3159 - def get_structure2(self):
3160 """Returns the Structure object of atom #2. 3161 """ 3162 return self.atom2.fragment.chain.model.structure
3163
3164 - def calc_length(self):
3165 """Returns the length of the bond. 3166 """ 3167 return AtomMath.length(self.atom1.position - self.atom2.position)
3168 3169
3170 -class AlphaHelix(object):
3171 """Class containing information on a protein alpha helix. 3172 """
3173 - def __init__(self, 3174 helix_id = "", 3175 helix_class = "1", 3176 helix_length = 0, 3177 chain_id1 = "", 3178 frag_id1 = "", 3179 res_name1 = "", 3180 chain_id2 = "", 3181 frag_id2 = "", 3182 res_name2 = "", 3183 details = "", 3184 **args):
3185 3186 assert isinstance(helix_id, str) 3187 assert isinstance(helix_class, str) 3188 assert isinstance(helix_length, int) 3189 assert isinstance(details, str) 3190 assert isinstance(chain_id1, str) 3191 assert isinstance(frag_id1, str) 3192 assert isinstance(res_name1, str) 3193 assert isinstance(chain_id2, str) 3194 assert isinstance(frag_id2, str) 3195 assert isinstance(res_name2, str) 3196 assert isinstance(details, str) 3197 3198 self.model = None 3199 3200 self.helix_id = helix_id 3201 self.helix_class = helix_class 3202 self.helix_length = helix_length 3203 self.chain_id1 = chain_id1 3204 self.fragment_id1 = frag_id1 3205 self.res_name1 = res_name1 3206 self.chain_id2 = chain_id2 3207 self.fragment_id2 = frag_id2 3208 self.res_name2 = res_name2 3209 self.details = details 3210 3211 self.segment = None
3212
3213 - def __str__(self):
3214 return "AlphaHelix(%s %s %s:%s...%s:%s)" % ( 3215 self.helix_id, self.helix_class, 3216 self.chain_id1, 3217 self.fragment_id1, 3218 self.chain_id2, 3219 self.fragment_id2)
3220
3221 - def add_segment(self, segment):
3222 """Adds the Segment object this AlphaHelix spans. If the AlphaHelix 3223 already has a Segment, then it is replaced. The Segment objects added 3224 to AlphaHelix objects must have the attribute segment.chain referencing 3225 the source Chain object the Segment was sliced from. 3226 """ 3227 assert segment is None or isinstance(segment, Segment) 3228 self.segment = segment 3229 3230 ## just return if the segment is None 3231 if segment is None: 3232 return 3233 3234 ## reset AlphaHelix description with the description derived 3235 ## from the new Segment 3236 try: 3237 frag1 = segment[0] 3238 frag2 = segment[-1] 3239 except IndexError: 3240 return 3241 3242 self.chain_id1 = frag1.chain_id 3243 self.fragment_id1 = frag1.fragment_id 3244 self.res_name1 = frag1.res_name 3245 3246 self.chain_id2 = frag2.chain_id 3247 self.fragment_id2 = frag2.fragment_id 3248 self.res_name2 = frag2.res_name 3249 3250 self.helix_length = len(segment)
3251
3252 - def construct_segment(self):
3253 """Constructs the child Segment object from the Chain object found in 3254 the parent Structure object by the AlphaHelix chain_id/fragment_id 3255 information. Returns True if the Segment was created, or False if 3256 it was not. The Segment is not created when the fragment range 3257 fragment_id1:fragment_id2 cannot be found in the parent Chain object. 3258 """ 3259 if self.chain_id1 != self.chain_id2: 3260 ConsoleOutput.fatal("alpha helix spans multiple chains -- not supported") 3261 3262 ## get the Chain object from the parent Model 3263 try: 3264 chain = self.model[self.chain_id1] 3265 except KeyError: 3266 self.add_segment(None) 3267 return False 3268 3269 ## cut the Segment from the Chain using the given fragment_id 3270 ## range for the AlphaHelix 3271 try: 3272 segment = chain[self.fragment_id1:self.fragment_id2] 3273 segment.chain = chain 3274 except KeyError: 3275 self.add_segment(None) 3276 return False 3277 3278 self.add_segment(segment) 3279 return True
3280
3281 - def get_chain(self):
3282 """Returns the parent Chain object. If the AlphaHelix does not have 3283 a Segment child the raised AttributeError. 3284 """ 3285 return self.segment.chain
3286
3287 - def get_model(self):
3288 """Returns the parent Model object. 3289 """ 3290 return self.model
3291
3292 - def get_structure(self):
3293 """Returns the parent Structure object. 3294 """ 3295 return self.model.structure
3296
3297 - def get_segment(self):
3298 """Return the child Segment object this AlphaHelix spans in the 3299 parent Model. 3300 """ 3301 return self.segment
3302
3303 - def iter_fragments(self):
3304 """Iterates all Fragment objects in the AlphaHelix. 3305 """ 3306 if self.segment is None: 3307 return iter(list()) 3308 return self.segment.iter_fragments()
3309
3310 - def iter_atoms(self):
3311 """Iterates all Atom objects in the AlphaHelix. 3312 """ 3313 if self.segment is None: 3314 return iter(list()) 3315 return self.segment.iter_atoms()
3316
3317 - def iter_all_atoms(self):
3318 """Iterates all Atom objects in all AlphaHelix, plus any in 3319 non-default alt_loc conformations. 3320 """ 3321 if self.segment is None: 3322 return iter(list()) 3323 return self.segment.iter_all_atoms()
3324 3325
3326 -class Strand(object):
3327 """One strand of a BetaSheet. 3328 """
3329 - def __init__(self, 3330 chain_id1 = "", 3331 frag_id1 = "", 3332 res_name1 = "", 3333 chain_id2 = "", 3334 frag_id2 = "", 3335 res_name2 = "", 3336 reg_chain_id = "", 3337 reg_frag_id = "", 3338 reg_res_name = "", 3339 reg_atom = "", 3340 reg_prev_chain_id = "", 3341 reg_prev_frag_id = "", 3342 reg_prev_res_name = "", 3343 reg_prev_atom = "", 3344 **args):
3345 3346 assert isinstance(chain_id1, str) 3347 assert isinstance(frag_id1, str) 3348 assert isinstance(res_name1, str) 3349 assert isinstance(chain_id2, str) 3350 assert isinstance(frag_id2, str) 3351 assert isinstance(res_name2, str) 3352 assert isinstance(reg_chain_id, str) 3353 assert isinstance(reg_frag_id, str) 3354 assert isinstance(reg_res_name, str) 3355 assert isinstance(reg_atom, str) 3356 assert isinstance(reg_prev_chain_id, str) 3357 assert isinstance(reg_prev_frag_id, str) 3358 assert isinstance(reg_prev_res_name, str) 3359 assert isinstance(reg_prev_atom, str) 3360 3361 self.beta_sheet = None 3362 3363 self.chain_id1 = chain_id1 3364 self.fragment_id1 = frag_id1 3365 self.res_name1 = res_name1 3366 self.chain_id2 = chain_id2 3367 self.fragment_id2 = frag_id2 3368 self.res_name2 = res_name2 3369 self.reg_chain_id = reg_chain_id 3370 self.reg_fragment_id = reg_frag_id 3371 self.reg_res_name = reg_res_name 3372 self.reg_atom = reg_atom 3373 self.reg_prev_chain_id = reg_prev_chain_id 3374 self.reg_prev_fragment_id = reg_prev_frag_id 3375 self.reg_prev_res_name = reg_prev_res_name 3376 self.reg_prev_atom = reg_prev_atom 3377 3378 self.segment = None
3379
3380 - def __str__(self):
3381 return "Strand(%s:%s-%s:%s %s:%s:%s-%s:%s:%s)" % ( 3382 self.chain_id1, self.fragment_id1, 3383 self.chain_id2, self.fragment_id2, 3384 self.reg_chain_id, self.reg_fragment_id, self.reg_atom, 3385 self.reg_prev_chain_id, self.reg_prev_fragment_id, 3386 self.reg_prev_atom)
3387
3388 - def add_segment(self, segment):
3389 """Adds the Segment object this Strand spans. If the Strand 3390 already has a Segment, then it is replaced. The Segment objects added 3391 to Strand objects must have the attribute segment.chain referencing 3392 the source Chain object the Segment was sliced from. 3393 """ 3394 assert segment is None or isinstance(segment, Segment) 3395 3396 self.segment = segment 3397 if segment is None: 3398 return 3399 3400 ## reset Strand description with the description derived 3401 ## from the new Segment 3402 try: 3403 frag1 = segment[0] 3404 frag2 = segment[-1] 3405 except IndexError: 3406 return 3407 3408 self.chain_id1 = frag1.chain_id 3409 self.fragment_id1 = frag1.fragment_id 3410 self.res_name1 = frag1.res_name 3411 3412 self.chain_id2 = frag2.chain_id 3413 self.fragment_id2 = frag2.fragment_id 3414 self.res_name2 = frag2.res_name
3415
3416 - def construct_segment(self):
3417 """Constructs the child Segment object from the Chain object found in 3418 the parent Structure object by the BetaSheet chain_id/fragment_id 3419 information. Returns True if the Segment was created, or False if 3420 it was not. The Segment is not created when the fragment range 3421 fragment_id1:fragment_id2 cannot be found in the parent Chain object. 3422 """ 3423 assert self.chain_id1 == self.chain_id2 3424 3425 ## get the Chain object from the parent Model 3426 try: 3427 chain = self.beta_sheet.model[self.chain_id1] 3428 except KeyError: 3429 self.add_segment(None) 3430 return False 3431 3432 ## cut the Segment from the Chain using the given fragment_id 3433 ## range for the BetaSheet 3434 try: 3435 segment = chain[self.fragment_id1:self.fragment_id2] 3436 segment.chain = chain 3437 except KeyError: 3438 self.add_segment(None) 3439 return False 3440 3441 self.add_segment(segment) 3442 return True
3443
3444 - def get_beta_sheet(self):
3445 """Returns the parent BetaSheet object. 3446 """ 3447 return self.beta_sheet
3448
3449 - def get_chain(self):
3450 """Returns the parent Chain object. If the Strand does not have 3451 a Segment child the raised AttributeError. 3452 """ 3453 return self.segment.chain
3454
3455 - def get_model(self):
3456 """Returns the parent Model object. 3457 """ 3458 return self.beta_sheet.model
3459
3460 - def get_structure(self):
3461 """Returns the parent Structure object. 3462 """ 3463 return self.beta_sheet.model.structure
3464
3465 - def get_segment(self):
3466 """Return the child Segment object this AlphaHelix spans in the 3467 parent Model. 3468 """ 3469 return self.segment
3470
3471 - def iter_fragments(self):
3472 """Iterates all Fragment objects. 3473 """ 3474 if self.segment is None: 3475 return iter(list()) 3476 return self.segment.iter_fragments()
3477
3478 - def iter_atoms(self):
3479 """Iterates all Atom objects. 3480 """ 3481 if self.segment is None: 3482 return iter(list()) 3483 return self.segment.iter_atoms()
3484
3485 - def iter_all_atoms(self):
3486 """Iterates all Atom objects plus any in non-default alt_loc 3487 conformations. 3488 """ 3489 if self.segment is None: 3490 return iter(list()) 3491 return self.segment.iter_all_atoms()
3492 3493
3494 -class BetaSheet(object):
3495 """Class containing information on a protein beta sheet. BetaSheet 3496 objects contain a list of Segments spanning the beta sheet. 3497 """
3498 - def __init__(self, 3499 sheet_id = "", 3500 **args):
3501 3502 assert isinstance(sheet_id, str) 3503 3504 self.model = None 3505 3506 self.sheet_id = sheet_id 3507 self.strand_list = []
3508
3509 - def __str__(self):
3510 return "BetaSheet(%s %d)" % (self.sheet_id, len(self.strand_list))
3511
3512 - def add_strand(self, strand):
3513 """Adds a Segment instance. 3514 """ 3515 assert isinstance(strand, Strand) 3516 assert strand not in self.strand_list 3517 self.strand_list.append(strand) 3518 strand.beta_sheet = self
3519
3520 - def construct_segments(self):
3521 """Calls Strand.construct_segment() on all child Strand objects. 3522 """ 3523 for strand in self.strand_list: 3524 strand.construct_segment()
3525
3526 - def get_model(self):
3527 """REturns the parent Model object. 3528 """ 3529 return self.model
3530
3531 - def get_structure(self):
3532 """Returns the parent Structure object. 3533 """ 3534 return self.model.structure
3535
3536 - def iter_strands(self):
3537 """Iterates over all child Strands objects. 3538 """ 3539 return iter(self.strand_list)
3540
3541 - def iter_fragments(self):
3542 """Iterates over all Fragment objects. 3543 """ 3544 for strand in self.strand_list: 3545 for frag in strand.iter_fragments(): 3546 yield frag
3547
3548 - def iter_atoms(self):
3549 """Iterates all Atom objects. 3550 """ 3551 for strand in self.strand_list: 3552 for atm in strand.iter_atoms(): 3553 yield atm
3554
3555 - def iter_all_atoms(self):
3556 """Iterates all Atom objects plus any in non-default alt_loc 3557 conformations. 3558 """ 3559 for strand in self.strand_list: 3560 for atm in strand.iter_all_atoms(): 3561 yield atm
3562 3563
3564 -class Site(object):
3565 """List of Fragments within a structure involved in a SITE description. 3566 """
3567 - def __init__(self, 3568 site_id = "", 3569 fragment_list = [], 3570 **args):
3571 3572 assert isinstance(site_id, str) 3573 assert isinstance(fragment_list, list) 3574 3575 self.model = None 3576 self.site_id = site_id 3577 self.fragment_dict_list = fragment_list
3578
3579 - def __str__(self):
3580 return "Site(id=%s)" % (self.site_id)
3581
3582 - def add_fragment(self, fragment_dict, fragment):
3583 """Adds a Fragment object to the fragment_dict and updates the 3584 values in fragment_dict to reflect the new Fragment object. The 3585 fragment_dict is added to the Site if it is not already in it. 3586 """ 3587 if fragment is not None: 3588 fragment_dict["fragment"] = fragment 3589 fragment_dict["chain_id"] = fragment.chain_id 3590 fragment_dict["frag_id"] = fragment.fragment_id 3591 fragment_dict["res_name"] = fragment.res_name 3592 3593 if fragment_dict not in self.fragment_dict_list: 3594 self.fragment_dict_list.append(fragment_dict) 3595 3596 else: 3597 if fragment_dict.has_key("fragment"): 3598 del fragment_dict["fragment"]
3599
3600 - def construct_fragments(self):
3601 """Using the site fragment descriptions, finds the Fragment objects 3602 in the parent Model. 3603 """ 3604 for frag_dict in self.fragment_dict_list: 3605 try: 3606 chain = self.model[frag_dict["chain_id"]] 3607 frag = chain[frag_dict["frag_id"]] 3608 except KeyError: 3609 self.add_fragment(frag_dict, None) 3610 continue 3611 3612 self.add_fragment(frag_dict, frag)
3613
3614 - def get_model(self):
3615 """Returns the parent Model object. 3616 """ 3617 return self.model
3618
3619 - def get_structure(self):
3620 """Returns the parent Structure object. 3621 """ 3622 return self.model.structure
3623
3624 - def iter_fragments(self):
3625 """Iterates child Fragment objects. 3626 """ 3627 for frag_dict in self.fragment_dict_list: 3628 try: 3629 yield frag_dict["fragment"] 3630 except KeyError: 3631 pass
3632
3633 - def iter_atoms(self):
3634 """Iterates all Atom objects. 3635 """ 3636 for frag in self.iter_fragments(): 3637 for atm in frag.iter_atoms(): 3638 yield atm
3639
3640 - def iter_all_atoms(self):
3641 """Iterates all Atom objects plus any in non-default alt_loc 3642 conformations. 3643 """ 3644 for frag in self.iter_fragments(): 3645 for atm in frag.iter_all_atoms(): 3646 yield atm
3647
3648 -def fragment_id_split(frag_id):
3649 """Split a string fragment_id into a 2-tuple of: 3650 (sequence_num, insertion_code) 3651 """ 3652 try: 3653 return (int(frag_id), None) 3654 except ValueError: 3655 return (int(frag_id[:-1]), frag_id[-1:])
3656
3657 -def fragment_id_eq(frag_id1, frag_id2):
3658 """Performs a proper equivalency of fragment_id strings according 3659 to their sequence number, then insertion code. 3660 """ 3661 return frag_id1 == frag_id2
3662
3663 -def fragment_id_lt(frag_id1, frag_id2):
3664 """Performs a proper less than comparison of fragment_id strings 3665 according to their sequence number, then insertion code. 3666 """ 3667 return fragment_id_split(frag_id1) < fragment_id_split(frag_id2)
3668
3669 -def fragment_id_le(frag_id1, frag_id2):
3670 """Performs a proper less than or equal to comparison of fragment_id 3671 strings according to their sequence number, then insertion code. 3672 """ 3673 return fragment_id_split(frag_id1) <= fragment_id_split(frag_id2)
3674
3675 -def fragment_id_gt(frag_id1, frag_id2):
3676 """Performs a proper greater than comparison of fragment_id strings 3677 according to their sequence number, then insertion code. 3678 """ 3679 return fragment_id_split(frag_id1) > fragment_id_split(frag_id2)
3680
3681 -def fragment_id_ge(frag_id1, frag_id2):
3682 """Performs a proper greater than or equal to comparison of 3683 fragment_id strings according to their sequence number, then 3684 insertion code. 3685 """ 3686 return fragment_id_split(frag_id1) >= fragment_id_split(frag_id2)
3687
3688 -def fragment_id_cmp(frag_id1, frag_id2):
3689 """Compare two fragment ids. 3690 """ 3691 if fragment_id_lt(frag_id1, frag_id2): 3692 return -1 3693 if fragment_id_lt(frag_id1, frag_id2): 3694 return 0 3695 return 1
3696
3697 -def iter_fragments(fragiter, start_frag_id = None, stop_frag_id = None):
3698 """Given a fragment iterator and a start and end fragment id, 3699 return an iterator which yields only fragments within the range. 3700 """ 3701 if start_frag_id and stop_frag_id: 3702 dpred = lambda f: fragment_id_lt(f.fragment_id, start_frag_id) 3703 tpred = lambda f: fragment_id_le(f.fragment_id, stop_frag_id) 3704 return itertools.takewhile(tpred, itertools.dropwhile(dpred, fragiter)) 3705 elif start_frag_id and not stop_frag_id: 3706 dpred = lambda f: fragment_id_lt(f.fragment_id, start_frag_id) 3707 return itertools.dropwhile(dpred, fragiter) 3708 elif not start_frag_id and stop_frag_id: 3709 tpred = lambda f: fragment_id_le(f.fragment_id, stop_frag_id) 3710 return itertools.takewhile(tpred, fragiter) 3711 return fragiter
3712
3713 -class FragmentID(object):
3714 """Stores a fragment_id as integer residue sequence number and a 3715 single-character insertion code. 3716 """
3717 - def __init__(self, frag_id):
3718 self.res_seq = 1 3719 self.icode = "" 3720 try: 3721 self.res_seq = int(frag_id) 3722 except ValueError: 3723 try: 3724 self.res_seq = int(frag_id[:-1]) 3725 except ValueError: 3726 pass 3727 else: 3728 self.icode = frag_id[-1]
3729 - def __str__(self):
3730 return "%d%s" % (self.res_seq, self.icode)
3731 - def __lt__(self, other):
3732 assert isinstance(other, FragmentID) 3733 return (self.res_seq, self.icode) < (other.res_seq, other.icode)
3734 - def __le__(self, other):
3735 assert isinstance(other, FragmentID) 3736 return (self.res_seq, self.icode) <= (other.res_seq, other.icode)
3737 - def __eq__(self, other):
3738 assert isinstance(other, FragmentID) 3739 return (self.res_seq, self.icode) == (other.res_seq, other.icode)
3740 - def __ne__(self, other):
3741 assert isinstance(other, FragmentID) 3742 return (self.res_seq, self.icode) != (other.res_seq, other.icode)
3743 - def __gt__(self, other):
3744 assert isinstance(other, FragmentID) 3745 return (self.res_seq, self.icode) > (other.res_seq, other.icode)
3746 - def __ge__(self, other):
3747 assert isinstance(other, FragmentID) 3748 return (self.res_seq, self.icode) >= (other.res_seq, other.icode)
3749 3750
3751 -class AtomList(list):
3752 """Provides the functionality of a Python list class for containing 3753 Atom instances. It also provides class methods for performing some 3754 useful calculations on the list of atoms. 3755 """
3756 - def calc_centroid(self):
3757 """Calculates the centroid of all contained Atom instances and 3758 returns a Vector to the centroid. 3759 """ 3760 num = 0 3761 centroid = numpy.zeros(3, float) 3762 for atm in self: 3763 if atm.position is not None: 3764 centroid += atm.position 3765 num += 1 3766 return centroid / num
3767
3768 - def calc_adv_temp_factor(self):
3769 """Calculates the average temperature factor of all contained Atom 3770 instances and returns the average temperature factor. 3771 """ 3772 num_tf = 0 3773 adv_tf = 0.0 3774 3775 for atm in self: 3776 if atm.temp_factor is not None: 3777 adv_tf += atm.temp_factor 3778 num_tf += 1 3779 3780 return adv_tf / num_tf
3781
3782 - def calc_adv_U(self):
3783 """Calculates the average U matrix of all contained Atom instances and 3784 returns the 3x3 symmetric U matrix of that average. 3785 """ 3786 num_U = 0 3787 adv_U = numpy.zeros((3,3), float) 3788 3789 for atm in self: 3790 ## use the atom's U matrix if it exists, otherwise use the 3791 ## temperature factor 3792 3793 if atm.U is not None: 3794 adv_U += atm.U 3795 num_U += 1 3796 3797 return adv_U / num_U
3798
3799 - def calc_adv_anisotropy(self):
3800 """Calculates the average anisotropy for all Atoms in the AtomList. 3801 """ 3802 num_atoms = 0 3803 adv_aniso = 0.0 3804 3805 for atm in self: 3806 try: 3807 adv_aniso += atm.calc_anisotropy() 3808 except ZeroDivisionError: 3809 pass 3810 else: 3811 num_atoms += 1 3812 3813 return adv_aniso / num_atoms
3814
3815 - def calc_adv_anisotropy3(self):
3816 """Calculates the average anisotropy 3-tuple for all Atoms in the 3817 AtomList. 3818 """ 3819 num_atoms = 0 3820 adv_aniso1 = 0.0 3821 adv_aniso2 = 0.0 3822 adv_aniso3 = 0.0 3823 3824 for atm in self: 3825 try: 3826 a1, a2, a3 = atm.calc_anisotropy3() 3827 except ZeroDivisionError: 3828 pass 3829 else: 3830 adv_aniso1 += a1 3831 adv_aniso2 += a2 3832 adv_aniso3 += a3 3833 num_atoms += 1 3834 3835 return (adv_aniso1 / num_atoms, 3836 adv_aniso2 / num_atoms, 3837 adv_aniso3 / num_atoms)
3838 3839 3840 ### <testing>
3841 -def test_module():
3842 struct = Structure() 3843 3844 for mx in xrange(1, 4): 3845 mid = str(mx) 3846 for cid in ["A", "B", "C", "D"]: 3847 for fx in xrange(1, 4): 3848 fid = str(fx) 3849 3850 for name in ["N", "CA", "C", "O"]: 3851 3852 for alt_loc in ["A", "B", "C"]: 3853 3854 if alt_loc == "C" and name == "CA": continue 3855 3856 atm = Atom( 3857 name = name, 3858 alt_loc = alt_loc, 3859 model = mid, 3860 chain_id = cid, 3861 res_name = "GLY", 3862 fragment_id = fid) 3863 3864 struct.add_atom(atm) 3865 3866 for cx in struct.iter_chains(): 3867 print "iter_chains: ",cx 3868 for fx in struct.iter_fragments(): 3869 print "iter_fragments: ",fx 3870 for ax in fx.iter_all_atoms(): 3871 print "iter_all_atoms: ",ax 3872 3873 for ax in struct.iter_atoms(): 3874 print "iter_atoms: ",ax 3875 3876 struct.set_default_alt_loc("C") 3877 for ax in struct.iter_atoms(): 3878 print "iter_atoms: ",ax 3879 3880 3881 ## make some exceptions happen 3882 chk_atm = Atom( 3883 name = "CX", 3884 alt_loc = "B", 3885 model = "1", 3886 chain_id = "A", 3887 res_name = "GLY", 3888 fragment_id = "1") 3889 3890 for a in struct.iter_atoms(): 3891 print "WARNING! Bad atom name: ", a
3892 3893 if __name__ == "__main__": 3894 test_module() 3895 ### </testing> 3896