[Biopython-dev] Questions on StructureBuilder, MMCIFParser, and MMCIFlex

Paul B tallpaulinjax at yahoo.com
Sun Nov 1 14:50:31 EST 2009






Hi,
 
I'm a computer science guy trying to figure out some chemistry logic to support my thesis, so bear with me! :-) To sum it up, I'm not sure MMCIFParser is handling ATOM and MODEL records correctly because of this code in MMCIFParser:
            if fieldname=="HETATM":
                hetatm_flag="H"
            else:
                hetatm_flag=" "
This causes ATOM (and potentially MODEL) records to die as seen in the exception below (I think!)
 
My questions are:
1. Am I correct the correct code is insufficient?
2. What additional logic beyond just recognizing whether it's a HETATM, ATOM or MODEL record needs to be added?
 
Thanks!
 
Paul

 
Background:
I understand MMCIFlex.py et cetera is commented out in the Windows setup.py package due to difficulties compiling it. So I re-wrote MMCIFlex strictly in Python to emulate what I THINK the original MMCIFlex did. My version processes a .cif file one line at a time (readline()) then passes tokens back to MMCIF2Dict at  each call to get_token(). That seems to work fine for unit testing of my MMCIFlex and MMCIFDict which I had to slightly re-write (to ensure it handled how I passed SEMICOLONS line back etc).
 
However when I try and use this with MMCIFParser against the 2beg .cif file which has no HETATM records and, as I understand the definition, no disordered atoms I get:
 
C:\Python25\Lib\site-packages\Bio\PDB\StructureBuilder.py:85: PDBConstructionWar
ning: WARNING: Chain A is discontinuous at line 0.
  PDBConstructionWarning)
C:\Python25\Lib\site-packages\Bio\PDB\StructureBuilder.py:122: PDBConstructionWa
rning: WARNING: Residue (' ', 17, ' ') redefined at line 0.
  PDBConstructionWarning)
Traceback (most recent call last):
  File "MMCIFParser.py", line 140, in <module>
    structure=p.get_structure("test", filename)
  File "MMCIFParser.py", line 23, in get_structure
    self._build_structure(structure_id)
  File "MMCIFParser.py", line 88, in _build_structure
    icode)
  File "C:\Python25\lib\site-packages\Bio\PDB\StructureBuilder.py", line 148, in
 init_residue
    % (resname, field, resseq, icode))
PDBExceptions.PDBConstructionException: Blank altlocs in duplicate residue LEU (
' ', 17, ' ')
 
Basically what I think MIGHT be happening is MMCIFParser is currently only handling HETATM records, when some other kind of record comes in (ATOM, MODEL) it is treated incorrectly. See below.
 
MMCIFParser.py
    def _build_structure(self, structure_id):
 ....
        fieldname_list=mmcif_dict["_atom_site.group_PDB"]
 ....
        for i in xrange(0, len(atom_id_list)):
     ...
            altloc=alt_list[i]
            if altloc==".":
                altloc=" "
     ...
            fieldname=fieldname_list[i]
            #How are ATOM and MODEL records handled?
            if fieldname=="HETATM":
                hetatm_flag="H"
            else:
                hetatm_flag=" "
            if current_chain_id!=chainid:
                current_chain_id=chainid
                structure_builder.init_chain(current_chain_id)
                current_residue_id=resseq
                icode, int_resseq=self._get_icode(resseq)
                #This is line 87-88 in the real file
                structure_builder.init_residue(resname, hetatm_flag, int_resseq, 
                    icode)
 
Class StructureBuilder:
    ...
    def init_residue(self, resname, field, resseq, icode):
        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) 
       ...
        #This line will get executed for any non-HETATM record (ie ATOM Or MODEL)
        #because in MMCIFParser, if it wasn't a HETATM, then it's a ' ' ???
        if field==" ":
            if self.chain.has_id(res_id):
=======>But there are no point mutations in 2beg that I know of. Shouldn't be here!
                # There already is a residue with the id (field, resseq, icode).
                # This only makes sense in the case of a point mutation.
                if __debug__:
                    warnings.warn("WARNING: Residue ('%s', %i, '%s') "
                                  "redefined at line %i."
                                  % (field, resseq, icode, self.line_counter),
                                  PDBConstructionWarning)
                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-blank altlocs for all their atoms.
                    # If not, the PDB file probably contains an error. 
====>          #This is the line throwing the exception, but we shouldn't be here!
                    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



More information about the Biopython-dev mailing list