Back to index

python-biopython  1.60
Entity.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 from copy import copy
00007 
00008 from Bio.PDB.PDBExceptions import PDBConstructionException, PDBException
00009 
00010 """Base class for Residue, Chain, Model and Structure classes.
00011 
00012 It is a simple container class, with list and dictionary like properties.
00013 """
00014 
00015 
00016 class Entity(object):
00017     """
00018     Basic container object. Structure, Model, Chain and Residue
00019     are subclasses of Entity. It deals with storage and lookup.
00020     """
00021     def __init__(self, id):
00022         self.id=id
00023         self.full_id=None
00024         self.parent=None
00025         self.child_list=[]
00026         self.child_dict={}
00027         # Dictionary that keeps addictional properties
00028         self.xtra={}
00029     
00030     # Special methods   
00031 
00032     def __len__(self):
00033         "Return the number of children."
00034         return len(self.child_list)
00035 
00036     def __getitem__(self, id):
00037         "Return the child with given id."
00038         return self.child_dict[id]
00039 
00040     def __delitem__(self, id):
00041         "Remove a child."
00042         return self.detach_child(id)
00043 
00044     def __contains__(self, id):
00045         "True if there is a child element with the given id."
00046         return (id in self.child_dict)
00047 
00048     def __iter__(self):
00049         "Iterate over children."
00050         for child in self.child_list:
00051             yield child
00052 
00053     # Public methods    
00054 
00055     def get_level(self):
00056         """Return level in hierarchy.
00057 
00058         A - atom
00059         R - residue
00060         C - chain
00061         M - model
00062         S - structure
00063         """
00064         return self.level
00065 
00066     def set_parent(self, entity):
00067         "Set the parent Entity object."
00068         self.parent=entity
00069 
00070     def detach_parent(self):
00071         "Detach the parent."
00072         self.parent=None
00073 
00074     def detach_child(self, id):
00075         "Remove a child."
00076         child=self.child_dict[id] 
00077         child.detach_parent()
00078         del self.child_dict[id]
00079         self.child_list.remove(child)
00080 
00081     def add(self, entity):
00082         "Add a child to the Entity."
00083         entity_id=entity.get_id()
00084         if self.has_id(entity_id):
00085             raise PDBConstructionException( \
00086                 "%s defined twice" % str(entity_id))
00087         entity.set_parent(self)
00088         self.child_list.append(entity)
00089         self.child_dict[entity_id]=entity
00090     
00091     def insert(self, pos, entity):
00092         "Add a child to the Entity at a specified position."
00093         entity_id=entity.get_id()
00094         if self.has_id(entity_id):
00095             raise PDBConstructionException( \
00096                 "%s defined twice" % str(entity_id))
00097         entity.set_parent(self)
00098         self.child_list[pos:pos] = [entity]
00099         self.child_dict[entity_id]=entity        
00100 
00101     def get_iterator(self):
00102         "Return iterator over children."
00103         for child in self.child_list:
00104             yield child
00105 
00106     def get_list(self):
00107         "Return a copy of the list of children."
00108         return copy(self.child_list)
00109 
00110     def has_id(self, id):
00111         """True if a child with given id exists."""
00112         return (id in self.child_dict)
00113 
00114     def get_parent(self):
00115         "Return the parent Entity object."
00116         return self.parent
00117 
00118     def get_id(self):
00119         "Return the id."
00120         return self.id
00121 
00122     def get_full_id(self):
00123         """Return the full id.
00124 
00125         The full id is a tuple containing all id's starting from
00126         the top object (Structure) down to the current object. A full id for
00127         a Residue object e.g. is something like:
00128 
00129         ("1abc", 0, "A", (" ", 10, "A"))
00130 
00131         This corresponds to:
00132 
00133         Structure with id "1abc"
00134         Model with id 0
00135         Chain with id "A"
00136         Residue with id (" ", 10, "A")
00137 
00138         The Residue id indicates that the residue is not a hetero-residue 
00139         (or a water) beacuse it has a blank hetero field, that its sequence 
00140         identifier is 10 and its insertion code "A".
00141         """
00142         if self.full_id==None:
00143             entity_id=self.get_id()
00144             l=[entity_id]   
00145             parent=self.get_parent()
00146             while not (parent is None):
00147                 entity_id=parent.get_id()
00148                 l.append(entity_id)
00149                 parent=parent.get_parent()
00150             l.reverse()
00151             self.full_id=tuple(l)
00152         return self.full_id
00153 
00154     def transform(self, rot, tran):
00155         """
00156         Apply rotation and translation to the atomic coordinates.
00157 
00158         Example:
00159                 >>> rotation=rotmat(pi, Vector(1,0,0))
00160                 >>> translation=array((0,0,1), 'f')
00161                 >>> entity.transform(rotation, translation)
00162 
00163         @param rot: A right multiplying rotation matrix
00164         @type rot: 3x3 Numeric array
00165 
00166         @param tran: the translation vector
00167         @type tran: size 3 Numeric array
00168         """
00169         for o in self.get_list():
00170             o.transform(rot, tran)
00171 
00172     def copy(self):
00173         shallow = copy(self)
00174 
00175         shallow.child_list = []
00176         shallow.child_dict = {}
00177         shallow.xtra = copy(self.xtra)
00178 
00179         shallow.detach_parent()
00180 
00181         for child in self.child_list:
00182             shallow.add(child.copy())
00183         return shallow
00184 
00185 class DisorderedEntityWrapper(object):
00186     """
00187     This class is a simple wrapper class that groups a number of equivalent
00188     Entities and forwards all method calls to one of them (the currently selected 
00189     object). DisorderedResidue and DisorderedAtom are subclasses of this class.
00190     
00191     E.g.: A DisorderedAtom object contains a number of Atom objects,
00192     where each Atom object represents a specific position of a disordered
00193     atom in the structure.
00194     """
00195     def __init__(self, id):
00196         self.id=id
00197         self.child_dict={}
00198         self.selected_child=None
00199         self.parent=None    
00200 
00201     # Special methods
00202 
00203     def __getattr__(self, method):
00204         "Forward the method call to the selected child."
00205         if not hasattr(self, 'selected_child'):
00206             # Avoid problems with pickling
00207             # Unpickling goes into infinite loop!
00208             raise AttributeError
00209         return getattr(self.selected_child, method)
00210 
00211     def __getitem__(self, id):
00212         "Return the child with the given id."
00213         return self.selected_child[id]
00214 
00215     # XXX Why doesn't this forward to selected_child?
00216     # (NB: setitem was here before getitem, iter, len, sub)
00217     def __setitem__(self, id, child):
00218         "Add a child, associated with a certain id."
00219         self.child_dict[id]=child
00220 
00221     def __contains__(self, id):
00222         "True if the child has the given id."
00223         return (id in self.selected_child)
00224 
00225     def __iter__(self):
00226         "Return the number of children."
00227         return iter(self.selected_child)
00228 
00229     def __len__(self):
00230         "Return the number of children."
00231         return len(self.selected_child)
00232 
00233     def __sub__(self, other):
00234         """Subtraction with another object."""
00235         return self.selected_child - other
00236 
00237     # Public methods    
00238 
00239     def get_id(self):
00240         "Return the id."
00241         return self.id
00242 
00243     def disordered_has_id(self, id):
00244         """True if there is an object present associated with this id."""
00245         return (id in self.child_dict)
00246 
00247     def detach_parent(self):
00248         "Detach the parent"
00249         self.parent=None
00250         for child in self.disordered_get_list():
00251             child.detach_parent()
00252 
00253     def get_parent(self):
00254         "Return parent."
00255         return self.parent
00256 
00257     def set_parent(self, parent):
00258         "Set the parent for the object and its children."
00259         self.parent=parent
00260         for child in self.disordered_get_list():
00261             child.set_parent(parent)
00262 
00263     def disordered_select(self, id):
00264         """Select the object with given id as the currently active object.
00265 
00266         Uncaught method calls are forwarded to the selected child object.
00267         """
00268         self.selected_child=self.child_dict[id]
00269     
00270     def disordered_add(self, child):
00271         "This is implemented by DisorderedAtom and DisorderedResidue."
00272         raise NotImplementedError
00273 
00274     def is_disordered(self):
00275         """
00276         Return 2, indicating that this Entity is a collection of Entities.
00277         """
00278         return 2
00279 
00280     def disordered_get_id_list(self):
00281         "Return a list of id's."
00282         l=self.child_dict.keys()
00283         # sort id list alphabetically
00284         l.sort()
00285         return l
00286         
00287     def disordered_get(self, id=None):
00288         """Get the child object associated with id.
00289 
00290         If id is None, the currently selected child is returned.
00291         """
00292         if id==None:
00293             return self.selected_child
00294         return self.child_dict[id]
00295 
00296     def disordered_get_list(self):
00297         "Return list of children."
00298         return self.child_dict.values()