SLNParseOps.h

Go to the documentation of this file.
00001 //
00002 //  Copyright (c) 2008, Novartis Institutes for BioMedical Research Inc.
00003 //  All rights reserved.
00004 // 
00005 // Redistribution and use in source and binary forms, with or without
00006 // modification, are permitted provided that the following conditions are
00007 // met: 
00008 //
00009 //     * Redistributions of source code must retain the above copyright 
00010 //       notice, this list of conditions and the following disclaimer.
00011 //     * Redistributions in binary form must reproduce the above
00012 //       copyright notice, this list of conditions and the following 
00013 //       disclaimer in the documentation and/or other materials provided 
00014 //       with the distribution.
00015 //     * Neither the name of Novartis Institutes for BioMedical Research Inc. 
00016 //       nor the names of its contributors may be used to endorse or promote 
00017 //       products derived from this software without specific prior
00018 //       written permission.
00019 //
00020 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00021 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00023 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00024 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00025 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00026 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00027 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00028 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00029 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00030 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031 //
00032 // Created by Greg Landrum, September 2006
00033 //
00034 #ifndef __RD_SLNPARSEOPS_H__
00035 #define __RD_SLNPARSEOPS_H__
00036 
00037 #include <vector>
00038 #include <GraphMol/SLNParse/SLNParse.h>
00039 #include <GraphMol/SLNParse/SLNAttribs.h>
00040 #include <GraphMol/RDKitBase.h>
00041 #include <GraphMol/RDKitQueries.h>
00042 #include <boost/lexical_cast.hpp>
00043 
00044 namespace RDKit{
00045   namespace SLNParse{
00046     namespace {
00047       //!  set a bookmark in the molecule if the atom has an associated ID:
00048       void bookmarkAtomID(RWMol *mp,Atom *atom){
00049         PRECONDITION(mp,"bad molecule");
00050         PRECONDITION(atom,"bad atom");
00051         if(atom->hasProp("_AtomID")){
00052           unsigned int label;
00053           atom->getProp("_AtomID",label);
00054           if(mp->hasAtomBookmark(label)){
00055             std::stringstream err;
00056             err << "SLN Parser error: Atom ID " << label << " used a second time.";
00057             throw SLNParseException(err.str());
00058           }
00059           if(mp->hasBondBookmark(label)){
00060             std::stringstream err;
00061             err << "SLN Parser error: Atom ID " << label << " appears *after* its ring closure.";
00062             throw SLNParseException(err.str());
00063           }
00064           mp->setAtomBookmark(atom,label);
00065         }
00066       }
00067 
00068       //! adds a bond, being careful to handle aromaticity properly
00069       template<typename BondType>
00070       void addBondToMol(RWMol *mp,BondType *bond){
00071         PRECONDITION(mp,"null molecule");
00072         PRECONDITION(bond,"null bond");
00073         mp->addBond(bond,true);
00074         if(bond->getBondType()==Bond::AROMATIC){
00075           // SLN doesn't have aromatic atom types, aromaticity is a property
00076           // of the bonds themselves, so we need to set the atom types:
00077           bond->setIsAromatic(true);
00078           bond->getBeginAtom()->setIsAromatic(true);
00079           bond->getEndAtom()->setIsAromatic(true);
00080         }
00081       }
00082     }// end of anonymous namespace
00083 
00084     // ------------------------------------------------------------------------------------
00085     //! initialize a molecule
00086     template <typename AtomType>
00087     int startMol(std::vector<RWMol *> &molList,AtomType *firstAtom){
00088       PRECONDITION(firstAtom,"empty atom");
00089       RWMol *mp = new RWMol();
00090       mp->addAtom(firstAtom,true,true);
00091       bookmarkAtomID(mp,firstAtom);
00092 
00093       // add any hydrogens that are set on the atom, otherwise getting the numbering right
00094       // is just too hard:
00095       for(unsigned int i=0;i<firstAtom->getNumExplicitHs();++i){
00096         int hIdx=mp->addAtom(new Atom(1),false,true);
00097         mp->addBond(0,hIdx,Bond::SINGLE);
00098       }
00099       firstAtom->setNumExplicitHs(0);
00100 
00101 
00102       int sz = molList.size();
00103       molList.push_back(mp);
00104       return sz;
00105     };
00106 
00107     // ------------------------------------------------------------------------------------
00108     //! adds an atom to a molecule
00109     template<typename AtomType,typename BondType>
00110     void addAtomToMol(std::vector<RWMol *> &molList,unsigned int idx,AtomType *atom,
00111                       BondType *bond){
00112       PRECONDITION(idx<molList.size(),"bad index");
00113       RWMol *mp=molList[idx];
00114       PRECONDITION(mp,"null molecule");
00115       PRECONDITION(atom,"empty atom");
00116       PRECONDITION(bond,"null bond");
00117 
00118       Atom *a1 = mp->getActiveAtom();
00119       int atomIdx1=a1->getIdx();
00120       int atomIdx2=mp->addAtom(atom,true,true);
00121       bookmarkAtomID(mp,atom);
00122       bond->setOwningMol(mp);
00123       bond->setBeginAtomIdx(atomIdx1);
00124       bond->setEndAtomIdx(atomIdx2);
00125       addBondToMol(mp,bond);
00126     
00127       // add any hydrogens that are set on the atom, otherwise getting the numbering right
00128       // is just too hard:
00129       for(unsigned int i=0;i<atom->getNumExplicitHs();++i){
00130         int hIdx=mp->addAtom(new Atom(1),false,true);
00131         mp->addBond(atomIdx2,hIdx,Bond::SINGLE);
00132       }
00133       atom->setNumExplicitHs(0);
00134       
00135     }
00136     //! \overload
00137     template<typename AtomType>
00138     void addAtomToMol(std::vector<RWMol *> &molList,unsigned int idx,AtomType *atom){
00139       addAtomToMol(molList,idx,atom,new Bond(Bond::SINGLE));
00140     }
00141 
00142     // ------------------------------------------------------------------------------------
00143     //! closes an indexed ring in a molecule using the bond provided
00144     // The bond is formed from the atom in the molecule with the
00145     // corresponding bookmark to the active atom
00146     //
00147     template <typename BondType>
00148     void closeRingBond(std::vector<RWMol *> &molList,unsigned int molIdx,
00149                        unsigned int ringIdx,BondType *bond,
00150                        bool postponeAllowed=true){
00151       PRECONDITION(molIdx<molList.size(),"bad index");
00152       RWMol *mp=molList[molIdx];
00153       PRECONDITION(mp,"null molecule");
00154       PRECONDITION(bond,"Null bond");
00155 
00156       if(!mp->hasAtomBookmark(ringIdx)){
00157         if(postponeAllowed){
00158           // save it for later:
00159           bond->setOwningMol(mp);
00160           bond->setEndAtomIdx(mp->getActiveAtom()->getIdx());
00161           mp->setBondBookmark(bond,ringIdx);
00162           return;
00163         } else {
00164           std::stringstream err;
00165           err << "SLN Parser error: Ring closure " << ringIdx << " does not have a corresponding opener.";
00166           throw SLNParseException(err.str());
00167         }
00168       }
00169       Atom *opener=mp->getAtomWithBookmark(ringIdx);
00170       CHECK_INVARIANT(opener,"invalid atom");
00171 
00172       Atom *closer=mp->getActiveAtom();
00173       bond->setOwningMol(mp);
00174       bond->setBeginAtom(opener);
00175       bond->setEndAtom(closer);
00176       addBondToMol(mp,bond);
00177     };
00178     //! \overload
00179     void closeRingBond(std::vector<RWMol *> &molList,unsigned int molIdx,unsigned int ringIdx){
00180       closeRingBond(molList,molIdx,ringIdx,new Bond(Bond::SINGLE));
00181     };
00182 
00183     // ------------------------------------------------------------------------------------
00184     // NOTE: this takes over responsibility for the bond
00185     template <typename BondType>
00186     int addBranchToMol(std::vector<RWMol *> &molList,unsigned int molIdx,
00187                        unsigned int branchIdx,BondType *&bond){
00188       PRECONDITION(molIdx<molList.size(),"bad index");
00189       RWMol *mp=molList[molIdx];
00190       PRECONDITION(mp,"null molecule");
00191       PRECONDITION(branchIdx<molList.size(),"bad index");
00192       RWMol *branch=molList[branchIdx];
00193       PRECONDITION(branch,"null branch");
00194       PRECONDITION(bond,"null bond");
00195 
00196       unsigned int activeAtomIdx=mp->getActiveAtom()->getIdx();
00197       unsigned int nOrigAtoms=mp->getNumAtoms();
00198 
00199       //
00200       // Add the fragment's atoms and bonds to the molecule:
00201       //
00202       mp->insertMol(*branch);
00203 
00204       // copy in any atom bookmarks from the branch:
00205       for(ROMol::ATOM_BOOKMARK_MAP::const_iterator bmIt=branch->getAtomBookmarks()->begin();
00206           bmIt != branch->getAtomBookmarks()->end();++bmIt){
00207         if(bmIt->first<0) continue;
00208         if(mp->hasAtomBookmark(bmIt->first)){
00209           std::stringstream err;
00210           err << "SLN Parser error: Atom ID " << bmIt->first << " used a second time.";
00211           throw SLNParseException(err.str());
00212         } else if(mp->hasBondBookmark(bmIt->first)){
00213             std::stringstream err;
00214             err << "SLN Parser error: Atom ID " << bmIt->first << " appears *after* its ring closure.";
00215             throw SLNParseException(err.str());
00216           }
00217         else {
00218           CHECK_INVARIANT(bmIt->second.size()==1,"bad atom bookmark list on branch");
00219           Atom *tgtAtom=mp->getAtomWithIdx((*bmIt->second.begin())->getIdx()+nOrigAtoms);
00220           mp->setAtomBookmark(tgtAtom,bmIt->first);
00221         }
00222       }
00223       
00224       // loop over bond bookmarks in the branch and close the corresponding rings
00225       for(ROMol::BOND_BOOKMARK_MAP::const_iterator bmIt=branch->getBondBookmarks()->begin();
00226           bmIt != branch->getBondBookmarks()->end();++bmIt){
00227         CHECK_INVARIANT(bmIt->second.size()>=1,"bad bond bookmark list on branch");
00228         for(ROMol::BOND_PTR_LIST::const_iterator bondIt=bmIt->second.begin();
00229             bondIt!=bmIt->second.end();++bondIt){
00230           Bond *tgtBond=*bondIt;
00231           if(bmIt->first>0 && mp->hasAtomBookmark(bmIt->first)){
00232             Atom *tmpAtom=mp->getActiveAtom();
00233             mp->setActiveAtom(mp->getAtomWithIdx(tgtBond->getEndAtomIdx()+nOrigAtoms));
00234             closeRingBond(molList,molIdx,bmIt->first,tgtBond,false);
00235             mp->setActiveAtom(tmpAtom);
00236           } else {
00237             // no partner found yet, copy into this mol:
00238             tgtBond->setOwningMol(mp);
00239             tgtBond->setEndAtomIdx(tgtBond->getEndAtomIdx()+nOrigAtoms);
00240             mp->setBondBookmark(tgtBond,bmIt->first);
00241           }
00242         }
00243       }
00244       
00245       // set the connecting bond:
00246       if(bond->getBondType()!=Bond::IONIC){
00247         bond->setOwningMol(mp);
00248         bond->setBeginAtomIdx(activeAtomIdx);
00249         bond->setEndAtomIdx(nOrigAtoms);
00250         addBondToMol(mp,bond);
00251       } else {
00252         delete bond;
00253       }
00254       bond=0;
00255         
00256       delete branch;
00257       unsigned int sz = molList.size();
00258       if ( sz==branchIdx+1) {
00259         molList.resize( sz-1 );
00260       }
00261       return molIdx;
00262     };
00263     //! \overload
00264     int addBranchToMol(std::vector<RWMol *> &molList,unsigned int molIdx,unsigned int branchIdx){
00265       Bond *newBond=new Bond(Bond::SINGLE);
00266       return addBranchToMol(molList,molIdx,branchIdx,newBond);
00267     };
00268 
00269     // ------------------------------------------------------------------------------------
00270     //! adds the atoms and bonds from a fragment to the molecule, sets no bond between them
00271     int addFragToMol(std::vector<RWMol *> &molList,unsigned int molIdx,unsigned int fragIdx){
00272       Bond *newBond=new Bond(Bond::IONIC);
00273       return addBranchToMol(molList,molIdx,fragIdx,newBond);
00274     }
00275 
00276     //! convenience function to convert the argument to a string
00277     template <typename T>
00278     std::string convertToString(T val){
00279       std::string res=boost::lexical_cast<std::string>(val);
00280       return  res;
00281     }
00282 
00283     void CleanupAfterParseError(RWMol *mol){
00284       PRECONDITION(mol,"no molecule");
00285       // blow out any partial bonds:
00286       RWMol::BOND_BOOKMARK_MAP *marks = mol->getBondBookmarks();
00287       RWMol::BOND_BOOKMARK_MAP::iterator markI=marks->begin();
00288       while(markI != marks->end()){
00289         RWMol::BOND_PTR_LIST &bonds=markI->second;
00290         for(RWMol::BOND_PTR_LIST::iterator bondIt=bonds.begin();
00291             bondIt!=bonds.end();++bondIt){
00292           delete *bondIt;
00293         }
00294         ++markI;
00295       }
00296     }
00297   } // end of namespace SLNParse
00298 } // end of namespace RDKit
00299 #endif

Generated on Fri Apr 3 06:03:02 2009 for RDCode by  doxygen 1.5.6