Back to index

python-biopython  1.60
Residue.py
Go to the documentation of this file.
00001 # Copyright (C) 2002, Thomas Hamelryck (thamelry@binf.ku.dk)
00002 # This code is part of the Biopython distribution and governed by its
00003 # license.  Please see the LICENSE file that should have been included
00004 # as part of this package.  
00005 
00006 # My Stuff
00007 from Bio.PDB.PDBExceptions import PDBConstructionException
00008 from Bio.PDB.Entity import Entity, DisorderedEntityWrapper
00009 
00010 
00011 """Residue class, used by Structure objects."""
00012 
00013 
00014 _atom_name_dict={}
00015 _atom_name_dict["N"]=1
00016 _atom_name_dict["CA"]=2
00017 _atom_name_dict["C"]=3
00018 _atom_name_dict["O"]=4
00019 
00020 
00021 class Residue(Entity):
00022     """
00023     Represents a residue. A Residue object stores atoms.
00024     """
00025     def __init__(self, id, resname, segid):
00026         self.level="R"
00027         self.disordered=0
00028         self.resname=resname
00029         self.segid=segid
00030         Entity.__init__(self, id)
00031 
00032     # Special methods
00033 
00034     def __repr__(self):
00035         resname=self.get_resname()
00036         hetflag, resseq, icode=self.get_id()
00037         full_id=(resname, hetflag, resseq, icode)
00038         return "<Residue %s het=%s resseq=%s icode=%s>" % full_id
00039 
00040     # Private methods
00041 
00042     def _sort(self, a1, a2):
00043         """Sort the Atom objects.
00044 
00045         Atoms are sorted alphabetically according to their name, 
00046         but N, CA, C, O always come first.
00047 
00048         Arguments:
00049         o a1, a2 - Atom objects
00050         """
00051         name1=a1.get_name()
00052         name2=a2.get_name()
00053         if name1==name2:
00054             return(cmp(a1.get_altloc(), a2.get_altloc()))
00055         if name1 in _atom_name_dict:
00056             index1=_atom_name_dict[name1]
00057         else:
00058             index1=None
00059         if name2 in _atom_name_dict:
00060             index2=_atom_name_dict[name2]
00061         else:
00062             index2=None
00063         if index1 and index2:
00064             return cmp(index1, index2)
00065         if index1:
00066             return -1
00067         if index2:
00068             return 1
00069         return cmp(name1, name2)
00070 
00071     # Public methods
00072 
00073     def add(self, atom):
00074         """Add an Atom object.
00075 
00076         Checks for adding duplicate atoms, and raises a
00077         PDBConstructionException if so.
00078         """
00079         atom_id=atom.get_id()
00080         if self.has_id(atom_id):
00081             raise PDBConstructionException( \
00082                 "Atom %s defined twice in residue %s" % (atom_id, self))
00083         Entity.add(self, atom)
00084 
00085     def sort(self):
00086         self.child_list.sort(self._sort)
00087 
00088     def flag_disordered(self):
00089         "Set the disordered flag."
00090         self.disordered=1
00091 
00092     def is_disordered(self):
00093         "Return 1 if the residue contains disordered atoms."
00094         return self.disordered
00095 
00096     def get_resname(self):
00097         return self.resname
00098 
00099     def get_unpacked_list(self):
00100         """
00101         Returns the list of all atoms, unpack DisorderedAtoms."
00102         """
00103         atom_list=self.get_list()
00104         undisordered_atom_list=[]
00105         for atom in atom_list:
00106             if atom.is_disordered():
00107                 undisordered_atom_list=(undisordered_atom_list+ atom.disordered_get_list())
00108             else:
00109                 undisordered_atom_list.append(atom)
00110         return undisordered_atom_list       
00111 
00112     def get_segid(self):
00113         return self.segid
00114 
00115 
00116 class DisorderedResidue(DisorderedEntityWrapper):
00117     """
00118     DisorderedResidue is a wrapper around two or more Residue objects. It is
00119     used to represent point mutations (e.g. there is a Ser 60 and a Cys 60 residue,
00120     each with 50 % occupancy).
00121     """
00122     def __init__(self, id):
00123         DisorderedEntityWrapper.__init__(self, id)
00124 
00125     def __repr__(self):
00126         resname=self.get_resname()
00127         hetflag, resseq, icode=self.get_id()
00128         full_id=(resname, hetflag, resseq, icode)
00129         return "<DisorderedResidue %s het=%s resseq=%i icode=%s>" % full_id
00130 
00131     def add(self, atom):
00132         residue=self.disordered_get()
00133         if not atom.is_disordered()==2:
00134             # Atoms in disordered residues should have non-blank
00135             # altlocs, and are thus represented by DisorderedAtom objects.
00136             resname=residue.get_resname()
00137             het, resseq, icode=residue.get_id() 
00138             # add atom anyway, if PDBParser ignores exception the atom will be part of the residue
00139             residue.add(atom)
00140             raise PDBConstructionException( \
00141                 "Blank altlocs in duplicate residue %s (%s, %i, %s)" \
00142                 % (resname, het, resseq, icode) )
00143         residue.add(atom)
00144 
00145     def sort(self):
00146         "Sort the atoms in the child Residue objects."
00147         for residue in self.disordered_get_list():
00148             residue.sort() 
00149 
00150     def disordered_add(self, residue):
00151         """Add a residue object and use its resname as key.
00152 
00153         Arguments:
00154         o residue - Residue object
00155         """
00156         resname=residue.get_resname()
00157         # add chain parent to residue
00158         chain=self.get_parent()
00159         residue.set_parent(chain)
00160         assert(not self.disordered_has_id(resname))
00161         self[resname]=residue
00162         self.disordered_select(resname)
00163