def add(self, entity): "Add a child to the Entity." entity_id = entity.get_id() if self.has_id(entity_id): raise PDBConstructionException( \ "%s defined twice" % str(entity_id)) entity.set_parent(self) self.child_list.append(entity) self.child_dict[entity_id] = entity
def add(self, atom): """Add an Atom object. Checks for adding duplicate atoms, and raises a PDBConstructionException if so. """ atom_id = atom.get_id() if self.has_id(atom_id): raise PDBConstructionException( \ "Atom %s defined twice in residue %s" % (atom_id, self)) Entity.add(self, atom)
def add(self, atom): residue = self.disordered_get() if not atom.is_disordered() == 2: # Atoms in disordered residues should have non-blank # altlocs, and are thus represented by DisorderedAtom objects. resname = residue.get_resname() het, resseq, icode = residue.get_id() # add atom anyway, if PDBParser ignores exception the atom will be part of the residue residue.add(atom) raise PDBConstructionException( \ "Blank altlocs in duplicate residue %s (%s, %i, %s)" \ % (resname, het, resseq, icode) ) residue.add(atom)
def _handle_PDB_exception(self, message, line_counter): """ This method catches an exception that occurs in the StructureBuilder object (if PERMISSIVE==1), or raises it again, this time adding the PDB line number to the error message. """ message = "%s at line %i." % (message, line_counter) if self.PERMISSIVE: # just print a warning - some residues/atoms may be missing print "PDBConstructionException: %s" % message print "Exception ignored.\nSome atoms or residues may be missing in the data structure." else: # exceptions are fatal - raise again with new message (including line nr) raise PDBConstructionException(message)
def _parse_coordinates(self, coords_trailer): "Parse the atomic data in the PDB file." local_line_counter = 0 structure_builder = self.structure_builder current_model_id = 0 # Flag we have an open model model_open = 0 current_chain_id = None current_segid = None current_residue_id = None current_resname = None for i in range(0, len(coords_trailer)): line = coords_trailer[i] record_type = line[0:6] global_line_counter = self.line_counter + local_line_counter + 1 structure_builder.set_line_counter(global_line_counter) if (record_type == 'ATOM ' or record_type == 'HETATM'): # Initialize the Model - there was no explicit MODEL record if not model_open: structure_builder.init_model(current_model_id) current_model_id += 1 model_open = 1 fullname = line[12:16] # get rid of whitespace in atom names split_list = fullname.split() if len(split_list) != 1: # atom name has internal spaces, e.g. " N B ", so # we do not strip spaces name = fullname else: # atom name is like " CA ", so we can strip spaces name = split_list[0] altloc = line[16:17] resname = line[17:20] chainid = line[21:22] try: serial_number = int(line[6:11]) except: serial_number = 0 resseq = int(line[22:26].split()[0]) # sequence identifier icode = line[26:27] # insertion code if record_type == 'HETATM': # hetero atom flag if resname == "HOH" or resname == "WAT": hetero_flag = "W" else: hetero_flag = "H" else: hetero_flag = " " residue_id = (hetero_flag, resseq, icode) # atomic coordinates try: x = float(line[30:38]) y = float(line[38:46]) z = float(line[46:54]) except: #Should we allow parsing to continue in permissive mode? #If so what coordindates should we default to? Easier to abort! raise PDBConstructionException(\ "Invalid or missing coordinate(s) at line %i." \ % global_line_counter) coord = numpy.array((x, y, z), 'f') # occupancy & B factor try: occupancy = float(line[54:60]) except: self._handle_PDB_exception("Invalid or missing occupancy", global_line_counter) occupancy = 0.0 #Is one or zero a good default? try: bfactor = float(line[60:66]) except: self._handle_PDB_exception("Invalid or missing B factor", global_line_counter) bfactor = 0.0 #The PDB use a default of zero if the data is missing segid = line[72:76] element = line[76:78].strip() if current_segid != segid: current_segid = segid structure_builder.init_seg(current_segid) if current_chain_id != chainid: current_chain_id = chainid structure_builder.init_chain(current_chain_id) current_residue_id = residue_id current_resname = resname try: structure_builder.init_residue(resname, hetero_flag, resseq, icode) except PDBConstructionException, message: self._handle_PDB_exception(message, global_line_counter) elif current_residue_id != residue_id or current_resname != resname: current_residue_id = residue_id current_resname = resname try: structure_builder.init_residue(resname, hetero_flag, resseq, icode) except PDBConstructionException, message: self._handle_PDB_exception(message, global_line_counter) # init atom try: structure_builder.init_atom(name, coord, bfactor, occupancy, altloc, fullname, serial_number, element) except PDBConstructionException, message: self._handle_PDB_exception(message, global_line_counter)
def init_residue(self, resname, field, resseq, icode): """ Initiate a new Residue object. Arguments: o resname - string, e.g. "ASN" o field - hetero flag, "W" for waters, "H" for hetero residues, otherwise blanc. o resseq - int, sequence identifier o icode - string, insertion code """ if field != " ": if field == "H": # The hetero field consists of H_ + the residue name (e.g. H_FUC) field = "H_" + resname res_id = (field, resseq, icode) if field == " ": if self.chain.has_id(res_id): # There already is a residue with the id (field, resseq, icode). # This only makes sense in the case of a point mutation. if __debug__: sys.stderr.write( "WARNING: Residue ('%s', %i, '%s') redefined at line %i.\n" % (field, resseq, icode, self.line_counter)) duplicate_residue = self.chain[res_id] if duplicate_residue.is_disordered() == 2: # The residue in the chain is a DisorderedResidue object. # So just add the last Residue object. if duplicate_residue.disordered_has_id(resname): # The residue was already made self.residue = duplicate_residue duplicate_residue.disordered_select(resname) else: # Make a new residue and add it to the already # present DisorderedResidue new_residue = Residue(res_id, resname, self.segid) duplicate_residue.disordered_add(new_residue) self.residue = duplicate_residue return else: # Make a new DisorderedResidue object and put all # the Residue objects with the id (field, resseq, icode) in it. # These residues each should have non-blanc altlocs for all their atoms. # If not, the PDB file probably contains an error. if not self._is_completely_disordered(duplicate_residue): # if this exception is ignored, a residue will be missing self.residue = None raise PDBConstructionException(\ "Blank altlocs in duplicate residue %s ('%s', %i, '%s')" \ % (resname, field, resseq, icode)) self.chain.detach_child(res_id) new_residue = Residue(res_id, resname, self.segid) disordered_residue = DisorderedResidue(res_id) self.chain.add(disordered_residue) disordered_residue.disordered_add(duplicate_residue) disordered_residue.disordered_add(new_residue) self.residue = disordered_residue return residue = Residue(res_id, resname, self.segid) self.chain.add(residue) self.residue = residue