Atom.h

Go to the documentation of this file.
00001 //
00002 //  Copyright (C) 2001-2010 Greg Landrum and Rational Discovery LLC
00003 //
00004 //   @@ All Rights Reserved @@
00005 //  This file is part of the RDKit.
00006 //  The contents are covered by the terms of the BSD license
00007 //  which is included in the file license.txt, found at the root
00008 //  of the RDKit source tree.
00009 //
00010 /*! \file Atom.h
00011 
00012   \brief Defines the Atom class and associated typedefs
00013 
00014 */  
00015 #ifndef _RD_ATOM_H
00016 #define _RD_ATOM_H
00017 
00018 // Std stuff
00019 #include <iostream>
00020 #include <boost/foreach.hpp>
00021 
00022 // ours
00023 #include <Query/QueryObjects.h>
00024 #include <RDGeneral/types.h>
00025 
00026 
00027 namespace RDKit{
00028   class ROMol;
00029   class RWMol;
00030   
00031   //! The class for representing atoms
00032   /*!
00033 
00034     <b>Notes:</b>
00035       - many of the methods of Atom require that the Atom be associated
00036         with a molecule (an ROMol).
00037       - each Atom maintains a Dict of \c properties:  
00038           - Each \c property is keyed by name and can store an
00039             arbitrary type.
00040           - \c Properties can be marked as \c calculated, in which case
00041             they will be cleared when the \c clearComputedProps() method
00042             is called.
00043           - Because they have no impact upon chemistry, all \c property
00044             operations are \c const, this allows extra flexibility for
00045             clients who need to store extra data on Atom objects.
00046       - Atom objects are lazy about computing their explicit and implicit valence
00047         values.  These will not be computed until their values are requested.
00048 
00049     <b>Chirality:</b>
00050 
00051     The chirality of an Atom is determined by two things:
00052       - its \c chiralTag
00053       - the input order of its bonds (see note below for handling of
00054         implicit Hs)
00055 
00056     For tetrahedral coordination, the \c chiralTag tells you what
00057     direction you have to rotate to get from bond 2 to bond 3 while looking
00058     down bond 1. This is pretty much identical to the SMILES representation of
00059     chirality.
00060 
00061     NOTE: if an atom has an implicit H, the bond to that H is considered to be
00062     at the *end* of the list of other bonds.
00063 
00064   */
00065   class Atom {
00066     friend class MolPickler; //!< the pickler needs access to our privates
00067     friend class ROMol;
00068     friend class RWMol;
00069   public:
00070 
00071     typedef boost::shared_ptr<Atom>    ATOM_SPTR;
00072     typedef boost::shared_ptr<const Atom>    C_ATOM_SPTR;
00073     // FIX: grn...
00074     typedef Queries::Query<int,Atom const *,true> QUERYATOM_QUERY;
00075 
00076     //! store hybridization
00077     typedef enum {
00078       UNSPECIFIED=0, //!< hybridization that hasn't been specified
00079       S,
00080       SP,
00081       SP2,
00082       SP3,
00083       SP3D,
00084       SP3D2,
00085       OTHER          //!< unrecognized hybridization
00086     } HybridizationType;
00087 
00088     //! store type of chirality
00089     typedef enum {
00090       CHI_UNSPECIFIED=0,  //!< chirality that hasn't been specified
00091       CHI_TETRAHEDRAL_CW, //!< tetrahedral: clockwise rotation (SMILES @@)
00092       CHI_TETRAHEDRAL_CCW,//!< tetrahedral: counter-clockwise rotation (SMILES @)
00093       CHI_OTHER           //!< some unrecognized type of chirality
00094     } ChiralType;
00095 
00096     Atom();
00097     //! construct an Atom with a particular atomic number
00098     explicit Atom(unsigned int num);
00099     //! construct an Atom with a particular symbol (looked up in the PeriodicTable)
00100     explicit Atom(std::string what);
00101     Atom(const Atom & other);
00102     virtual ~Atom();
00103 
00104     //! makes a copy of this Atom and returns a pointer to it.
00105     /*!
00106       <b>Note:</b> the caller is responsible for <tt>delete</tt>ing the result
00107     */
00108     virtual Atom *copy() const;
00109 
00110     //! returns our atomic number
00111     const int getAtomicNum() const { return d_atomicNum; };
00112     //! sets our atomic number
00113     void setAtomicNum(int newNum) { d_atomicNum = newNum; };
00114 
00115     //! returns our symbol (determined by our atomic number)
00116     std::string getSymbol() const;
00117 
00118     //! returns a reference to the ROMol that owns this Atom
00119     ROMol &getOwningMol() const { return *dp_mol; };
00120   
00121     //! returns our index within the ROMol
00122     const unsigned int getIdx() const {return d_index;};
00123     //! sets our index within the ROMol
00124     /*!
00125       <b>Notes:</b>
00126         - this makes no sense if we do not have an owning molecule
00127         - the index should be <tt>< this->getOwningMol()->getNumAtoms()</tt>
00128     */
00129     void setIdx(unsigned int index) {d_index=index;};
00130 
00131     //! returns the explicit degree of the Atom (number of bonded
00132     //!   neighbors in the graph)
00133     /*!
00134       <b>Notes:</b>
00135         - requires an owning molecule
00136     */
00137     unsigned int getDegree() const;
00138 
00139     //! returns the total degree of the Atom (number of bonded
00140     //!   neighbors + number of Hs)
00141     /*!
00142       <b>Notes:</b>
00143         - requires an owning molecule
00144     */
00145     unsigned int getTotalDegree() const;
00146 
00147     //! \brief returns the total number of Hs (implicit and explicit) that
00148     //! this Atom is bound to
00149     /*!
00150       <b>Notes:</b>
00151         - requires an owning molecule
00152     */
00153     unsigned int getTotalNumHs(bool includeNeighbors=false) const;
00154 
00155     //! returns the number of implicit Hs this Atom is bound to
00156     /*!
00157       <b>Notes:</b>
00158         - requires an owning molecule
00159     */
00160     unsigned int getNumImplicitHs() const;
00161 
00162     //! returns the explicit valence (including Hs) of this atom
00163     int getExplicitValence() const;
00164 
00165     //! returns the implicit valence for this Atom
00166     /*!
00167       <b>Notes:</b>
00168         - requires an owning molecule
00169     */
00170     int getImplicitValence() const;
00171 
00172     //! returns the number of radical electrons for this Atom
00173     /*!
00174       <b>Notes:</b>
00175         - requires an owning molecule
00176     */
00177     unsigned int getNumRadicalElectrons() const { return d_numRadicalElectrons; };
00178     void setNumRadicalElectrons(unsigned int num) { d_numRadicalElectrons=num; };
00179 
00180 
00181     //! returns the formal charge of this atom
00182     const int getFormalCharge() const { return d_formalCharge; };
00183     //! set's the formal charge of this atom
00184     void setFormalCharge(int what) { d_formalCharge = what;} ;
00185 
00186     //! \brief sets our \c noImplicit flag, indicating whether or not
00187     //!  we are allowed to have implicit Hs
00188     void setNoImplicit( bool what ) { df_noImplicit = what; };
00189     //! returns the \c noImplicit flag
00190     bool getNoImplicit() const { return df_noImplicit; };
00191     
00192     //! sets our number of explict Hs
00193     void setNumExplicitHs(unsigned int what) { d_numExplicitHs = what; };
00194     //! returns our number of explict Hs
00195     unsigned int getNumExplicitHs() const { return d_numExplicitHs; };
00196   
00197     //! sets our \c isAromatic flag, indicating whether or not we are aromatic
00198     void setIsAromatic( bool what ) { df_isAromatic = what; };
00199     //! returns our \c isAromatic flag
00200     bool getIsAromatic() const { return df_isAromatic; };
00201 
00202     //! sets our mass (for isotopes)
00203     void setMass( double what) { d_mass = what; };
00204     //! returns our mass
00205     double getMass() const {return d_mass; };
00206 
00207     //! sets our \c dativeFlag
00208     // intended to be used only in construction.
00209     // NOTE: the dative flag is not currently used anywhere
00210     void setDativeFlag(int what) {
00211       d_dativeFlag = what;
00212     };
00213     //! returns our \c dativeFlag
00214     // NOTE: the dative flag is not currently used anywhere
00215     int getDativeFlag() const {
00216       return d_dativeFlag;
00217     };
00218     bool hasDativeFlag(int what) const {
00219       return d_dativeFlag==what;
00220     };
00221     //! clears our \c dativeFlag
00222     // NOTE: the dative flag is not currently used anywhere
00223     void clearDativeFlag(){ d_dativeFlag = 0; };
00224 
00225     //! sets our \c chiralTag
00226     void setChiralTag(ChiralType what) { d_chiralTag = what; };
00227     //! inverts our \c chiralTag
00228     void invertChirality();
00229     //! returns our \c chiralTag
00230     ChiralType getChiralTag() const { return d_chiralTag; };
00231 
00232     //! sets our hybridization
00233     void setHybridization(HybridizationType what) { d_hybrid = what; };
00234     //! returns our hybridization
00235     HybridizationType getHybridization() const { return d_hybrid; };
00236 
00237     // ------------------------------------
00238     // Some words of explanation before getting down into
00239     // the query stuff.
00240     // These query functions are really only here so that they
00241     //  can have real functionality in subclasses (like QueryAtoms).
00242     // Since pretty much it's gonna be a mistake to call any of these
00243     //  (ever), we're saddling them all with a precondition which
00244     //  is guaranteed to fail.  I'd like to have them be pure virtual,
00245     //  but that doesn't work since we need to be able to instantiate
00246     //  Atoms.
00247     // ------------------------------------
00248 
00249     // This method can be used to distinguish query atoms from standard atoms:
00250     virtual bool hasQuery() const { return false; };
00251    
00252     //! NOT CALLABLE
00253     virtual void setQuery(QUERYATOM_QUERY *what);
00254 
00255     //! NOT CALLABLE
00256     virtual QUERYATOM_QUERY *getQuery() const;
00257     //! NOT CALLABLE
00258     virtual void expandQuery(QUERYATOM_QUERY *what,
00259                              Queries::CompositeQueryType how=Queries::COMPOSITE_AND,
00260                              bool maintainOrder=true);
00261 
00262     //! returns whether or not we match the argument
00263     /*!
00264         <b>Notes:</b>
00265           - for Atom objects, "match" means that atomic numbers are the same.
00266     */
00267     virtual bool Match(Atom const *what) const;
00268     //! \overload
00269     virtual bool Match(const ATOM_SPTR what) const;
00270   
00271 
00272     // ------------------------------------
00273     //  Local Property Dict functionality
00274     //  all setProp functions are const because they
00275     //     are not meant to change the atom chemically 
00276     // ------------------------------------
00277     //! returns a list with the names of our \c properties
00278     STR_VECT getPropList() const {
00279       return dp_props->keys();
00280     }
00281 
00282     //! sets a \c property value
00283     /*!
00284        \param key the name under which the \c property should be stored.
00285            If a \c property is already stored under this name, it will be
00286            replaced.
00287        \param val the value to be stored
00288        \param computed (optional) allows the \c property to be flagged
00289            \c computed.
00290      */
00291     template <typename T>
00292     void setProp(const char *key, T val, bool computed=false) const{
00293     
00294       //if(!dp_props) dp_props = new Dict();
00295       std::string what(key);
00296       setProp(what,val, computed);
00297     }
00298 
00299     //! \overload
00300     template <typename T>
00301     void setProp(const std::string key, T val, bool computed=false) const {
00302       if (computed) {
00303         STR_VECT compLst;
00304         if(hasProp("__computedProps")) getProp("__computedProps", compLst);
00305         if (std::find(compLst.begin(), compLst.end(), key) == compLst.end()) {
00306           compLst.push_back(key);
00307           dp_props->setVal("__computedProps", compLst);
00308         }
00309       }
00310       //setProp(key.c_str(),val);
00311       dp_props->setVal(key, val);
00312     }
00313 
00314     //! allows retrieval of a particular property value
00315     /*!
00316 
00317        \param key the name under which the \c property should be stored.
00318            If a \c property is already stored under this name, it will be
00319            replaced.
00320        \param res a reference to the storage location for the value.
00321 
00322        <b>Notes:</b>
00323          - if no \c property with name \c key exists, a KeyErrorException will be thrown.
00324          - the \c boost::lexical_cast machinery is used to attempt type conversions.
00325            If this fails, a \c boost::bad_lexical_cast exception will be thrown.
00326 
00327     */
00328     template <typename T>
00329     void getProp(const char *key,T &res) const {
00330       //PRECONDITION(dp_props,"getProp called on empty property dict");
00331       dp_props->getVal(key,res);
00332     }
00333     //! \overload
00334     template <typename T>
00335     void getProp(const std::string key,T &res) const {
00336       //return getProp(key.c_str(),res);
00337       dp_props->getVal(key,res);
00338     }
00339 
00340     //! returns whether or not we have a \c property with name \c key
00341     bool hasProp(const char *key) const {
00342       if(!dp_props) return false;
00343       return dp_props->hasVal(key);
00344     };
00345     //! \overload
00346     bool hasProp(const std::string key) const {
00347       if(!dp_props) return false;
00348       return dp_props->hasVal(key);
00349     };
00350 
00351     
00352     //! clears the value of a \c property
00353     /*!
00354        <b>Notes:</b>
00355          - if no \c property with name \c key exists, a KeyErrorException
00356            will be thrown.
00357          - if the \c property is marked as \c computed, it will also be removed
00358            from our list of \c computedProperties
00359     */
00360     void clearProp(const char *key) const {
00361       std::string what(key);
00362       clearProp(what);
00363     };
00364     //! \overload
00365     void clearProp(const std::string key) const {
00366       if(hasProp("__computedProps")){
00367         STR_VECT compLst;
00368         getProp("__computedProps", compLst);
00369         STR_VECT_I svi = std::find(compLst.begin(), compLst.end(), key);
00370         if (svi != compLst.end()) {
00371           compLst.erase(svi);
00372           dp_props->setVal("__computedProps", compLst);
00373         }
00374       }    
00375       dp_props->clearVal(key);
00376     };
00377 
00378     //! clears all of our \c computed \c properties
00379     void clearComputedProps() const {
00380       if(!hasProp("__computedProps")) return;
00381       STR_VECT compLst;
00382       getProp("__computedProps", compLst);
00383       BOOST_FOREACH(const std::string &sv,compLst){
00384         dp_props->clearVal(sv);
00385       }
00386       compLst.clear();
00387       dp_props->setVal("__computedProps", compLst);
00388     }
00389 
00390     //! returns the perturbation order for a list of integers
00391     /*!
00392 
00393       This value is associated with chirality.
00394 
00395       \param probe a list of bond indices.  This must be the same
00396         length as our number of incoming bonds (our degree).
00397       
00398       \return the number of swaps required to convert the ordering
00399         of the probe list to match the order of our incoming bonds:
00400         e.g. if our incoming bond order is: <tt>[0,1,2,3]</tt>
00401         \verbatim
00402         getPerturbationOrder([1,0,2,3]) = 1
00403         getPerturbationOrder([1,2,3,0]) = 3
00404         getPerturbationOrder([1,2,0,3]) = 2
00405         \endverbatim
00406 
00407       See the class documentation for a more detailed description
00408       of our representation of chirality.
00409 
00410       <b>Notes:</b>
00411         - requires an owning molecule
00412       
00413     */
00414     int getPerturbationOrder(INT_LIST probe) const;
00415 
00416     //! calculates any of our lazy \c properties
00417     /*!
00418       <b>Notes:</b>
00419         - requires an owning molecule
00420         - the current lazy \c properties are implicit and explicit valence
00421     */
00422     void updatePropertyCache(bool strict=true);
00423 
00424     //! calculates and returns our explicit valence
00425     /*!
00426       <b>Notes:</b>
00427         - requires an owning molecule
00428     */
00429     int calcExplicitValence(bool strict=true);
00430 
00431     //! calculates and returns our implicit valence
00432     /*!
00433       <b>Notes:</b>
00434         - requires an owning molecule
00435     */
00436     int calcImplicitValence(bool strict=true);
00437 
00438   protected:
00439     //! sets our owning molecule
00440     void setOwningMol(ROMol *other);
00441     //! sets our owning molecule
00442     void setOwningMol(ROMol &other) {setOwningMol(&other);};
00443 
00444     bool df_isAromatic; 
00445     bool df_noImplicit;
00446     int d_dativeFlag;
00447     unsigned int d_numExplicitHs;
00448     int d_formalCharge;
00449     unsigned int d_atomicNum;
00450     unsigned int d_index;
00451     // NOTE that these cannot be signed ints, they are calculated using
00452     // a lazy scheme and are initialized to -1 to indicate that the
00453     // calculation has not yet been done.
00454     int d_implicitValence, d_explicitValence;
00455     unsigned int d_numRadicalElectrons;
00456     ChiralType d_chiralTag;
00457     HybridizationType d_hybrid;
00458     double d_mass;
00459     ROMol *dp_mol;
00460     Dict *dp_props;
00461     void initAtom();
00462   };
00463 
00464 };
00465 //! allows Atom objects to be dumped to streams
00466 std::ostream & operator<<(std::ostream& target, const RDKit::Atom &at);
00467 
00468 #endif