RDCode: SLNParseOps.h Source File

# 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