RDCode: EmbeddedFrag.h Source File

- Main Page
- Namespaces
- Classes
- Files
- Directories

# EmbeddedFrag.h

Go to the documentation of this file.

    00001 //
    00002 //  Copyright (C) 2003-2008 Greg Landrum and Rational Discovery LLC
    00003 //
    00004 //   @@ All Rights Reserved  @@
    00005 //
    00006 #ifndef _RD_EMBEDDED_FRAG_H_
    00007 #define _RD_EMBEDDED_FRAG_H_
    00008
    00009 #include <RDGeneral/types.h>
    00010 #include <Geometry/Transform2D.h>
    00011 #include <Geometry/point.h>
    00012 #include "DepictUtils.h"
    00013 #include <boost/smart_ptr.hpp>
    00014
    00015
    00016 namespace RDKit {
    00017   class ROMol;
    00018   class Bond;
    00019 }
    00020
    00021 namespace RDDepict {
    00022   typedef boost::shared_array<double> DOUBLE_SMART_PTR;
    00023
    00024   //! Class that contains the data for an atoms that has alredy been embedded
    00025   class EmbeddedAtom {
    00026   public:
    00027     typedef enum {
    00028       UNSPECIFIED=0,
    00029       CISTRANS,
    00030       RING} EAtomType;
    00031
    00032     EmbeddedAtom() : aid(0), angle(-1.0), nbr1(-1), nbr2(-1),
    00033                      CisTransNbr(-1), ccw(true), rotDir(0), d_density(-1.0){
    00034       neighs.clear();
    00035     }
    00036
    00037     EmbeddedAtom(unsigned int aid, const RDGeom::Point2D &pos) :
    00038       aid(aid), angle(-1.0), nbr1(-1), nbr2(-1),
    00039       CisTransNbr(-1), ccw(true), rotDir(0), d_density(-1.0) {
    00040       loc = pos;
    00041     }
    00042
    00043     EmbeddedAtom& operator=(const EmbeddedAtom& other) {
    00044       loc = other.loc;
    00045       angle = other.angle;
    00046       nbr1 = other.nbr1;
    00047       nbr2 = other.nbr2;
    00048       CisTransNbr = other.CisTransNbr;
    00049       rotDir = other.rotDir;
    00050       normal = other.normal;
    00051       ccw = other.ccw;
    00052       neighs = other.neighs;
    00053       d_density = other.d_density;
    00054       return *this;
    00055     }
    00056
    00057     void Transform(const RDGeom::Transform2D &trans) {
    00058       RDGeom::Point2D temp = loc + normal;
    00059       trans.TransformPoint(loc);
    00060       trans.TransformPoint(temp);
    00061       normal = temp - loc;
    00062     }
    00063
    00064     void Reflect(const RDGeom::Point2D &loc1,
    00065                  const RDGeom::Point2D &loc2) {
    00066       RDGeom::Point2D temp = loc + normal;
    00067       loc = reflectPoint(loc, loc1, loc2);
    00068       temp = reflectPoint(temp, loc1, loc2);
    00069       normal = temp - loc;
    00070       ccw = (!ccw);
    00071     }
    00072
    00073     unsigned int aid; // the id of the atom
    00074
    00075     //! the angle that is already takes at this atom, so any new atom attaching to this
    00076     //! atom with have to fall in the available part
    00077     double angle;
    00078
    00079     //! the first neighbor of this atom that form the 'angle'
    00080     int nbr1;
    00081
    00082     //! the second neighbor of atom that from the 'angle'
    00083     int nbr2;
    00084
    00085     //! is this is a cis/trans atom the neighbor of this atom that is involved in the
    00086     //! cis/trans system - defaults to -1
    00087     int CisTransNbr;
    00088
    00089     //! which direction do we rotate this normal to add the next bond
    00090     //! if ccw is true we rotate counter cloack wise, otherwise rotate clock wise, by an angle that is
    00091     //! <= PI/2
    00092     bool ccw;
    00093
    00094     //! rotation direction around this atom when adding new atoms,
    00095     //! we determine this for the first neighbor and stick to this direction after that
    00096     //! useful only on atoms that are degree >= 4
    00097     int rotDir;
    00098
    00099     RDGeom::Point2D loc; // the current location of this atom
    00100     //! this is a normal vector to one of the bonds that added this atom
    00101     //! it provides the side on which we want to add a new bond to this atom,
    00102     //! this is only relevant when we are dealing with non ring atoms. We would like to draw chains in
    00103     //! a zig-zag manner
    00104     RDGeom::Point2D normal;
    00105
    00106     //! and these are the atom IDs of the neighbors that still need to be embedded
    00107     RDKit::INT_VECT neighs;
    00108
    00109     // density of the atoms around this atoms
    00110     // - this is sum of inverse of the square of distances to other atoms from this atom
    00111     // Used in the collision removal code - initialized to -1.0
    00112     double d_density;
    00113   };
    00114
    00115
    00116
    00117   typedef std::map<unsigned int, EmbeddedAtom> INT_EATOM_MAP;
    00118   typedef INT_EATOM_MAP::iterator INT_EATOM_MAP_I;
    00119   typedef INT_EATOM_MAP::const_iterator INT_EATOM_MAP_CI;
    00120
    00121
    00122   //! Class containing a fragment of a molecule that has already been embedded
    00123   /*
    00124     Here is how this class is designed to be used
    00125     - find a set of fused rings and compte the coordinates for the atoms in those ring
    00126     - them grow this sytem either by adding non ring neighbors
    00127     - or by adding other embedded fragment
    00128     - so at the end of the process  the whole molecule end up being one these embedded frag objects
    00129   */
    00130   class EmbeddedFrag {
    00131     // REVIEW: think about moving member functions up to global level and just using
    00132     // this class as a container
    00133
    00134   public:
    00135     //! Default constructor
    00136     EmbeddedFrag() : d_done(false), dp_mol(0){};
    00137
    00138     //! Intializer from a single atom id
    00139     /*!
    00140       A single Embedded Atom with this atom ID is added and placed at the origin
    00141     */
    00142     EmbeddedFrag(unsigned int aid, const RDKit::ROMol *mol);
    00143
    00144     //! Constructor when the coordinates have been specified for a set of atoms
    00145     /*!
    00146        This simply initialized a set of EmbeddedAtom to have the same coordinates as the
    00147        one's specified. No testing is done to verify any kind of ocrrectlness. Also
    00148        this fragment is less ready (to expand and add new neighbors) than when using other
    00149        constructors. This is because:
    00150        - the user may have specified coords for only a part of the atoms in a fused ring systems
    00151          in which case we need to find these atoms and merge these ring systems to this fragment
    00152        - The atoms are not yet aware of their neighbor (what is left to add etc.) this again
    00153          depends on  atoms properly so that new
    00154          neighbors can be added to them
    00155     */
    00156     EmbeddedFrag(const RDKit::ROMol *mol, const RDGeom::INT_POINT2D_MAP &coordMap);
    00157
    00158     //! Initializer from a set of fused rings
    00159     /*!
    00160       ARGUMENTS:
    00161       \param mol        the molecule of interest
    00162       \param fusedRings a vector of rings, each ring is a list of atom ids
    00163     */
    00164     EmbeddedFrag(const RDKit::ROMol *mol, const RDKit::VECT_INT_VECT &fusedRings);
    00165
    00166     //! Initializer for a cis/trans system using the double bond
    00167     /*!
    00168       ARGUMENTS:
    00169       \param dblBond   the double bond that is involed in the cis/trans configuration
    00170     */
    00171     explicit EmbeddedFrag(const RDKit::Bond* dblBond);
    00172
    00173     //! Expand this embedded system by adding negihboring atoms or other embedded systems
    00174     /*!
    00175
    00176       Note that both nratms and efrags are modified in this function
    00177       as we start merging them with the current fragment
    00178
    00179     */
    00180     void expandEfrag(RDKit::INT_LIST &nratms, std::list<EmbeddedFrag> &efrags);
    00181
    00182     //! Add a new non-ring atom to this object
    00183     /*
    00184       ARGUMENTS:
    00185       \param aid     ID of the atom to be added
    00186       \param toAid   ID of the atom that is already in this object to which this atom is added
    00187     */
    00188     void addNonRingAtom(unsigned int aid, unsigned int toAid);
    00189
    00190     //! Merge this embedded object with another embedded fragment
    00191     /*!
    00192
    00193       The transformation (rotation + translation required to attached
    00194       the passed in object will be computed and applied. The
    00195       coordinates of the atoms in this object will remain fixed We
    00196       will assume that there are no common atoms between the two
    00197       fragments to start with
    00198
    00199       ARGUMENTS:
    00200       \param  embObj  another EmbeddedFrag object to be merged with this object
    00201       \param  toAid   the atom in this embedded fragment to which the new object will be attached
    00202       \param  nbrAid  the atom in the other fragment to attach to
    00203       \param  mol     the molecule of interest
    00204     */
    00205     void mergeNoCommon(EmbeddedFrag &embObj, unsigned int toAid,
    00206                        unsigned int nbrAid); //, const RDKit::ROMol *mol);
    00207
    00208     //! Merge this embedded object with another embedded fragment
    00209     /*!
    00210
    00211       The transformation (rotation + translation required to attached
    00212       the passed in object will be computed and applied. The
    00213       coordinates of the atoms in this object will remain fixed This
    00214       already know there are a atoms in common and we will use them to
    00215       merge things
    00216
    00217       ARGUMENTS:
    00218       \param embObj    another EmbeddedFrag object to be merged with this object
    00219       \param commAtms  a vector of ids of the common atoms
    00220       \param mol       the molecule of interest
    00221
    00222     */
    00223     void mergeWithCommon(EmbeddedFrag &embObj, RDKit::INT_VECT &commAtms);
    00224     //const RDKit::ROMol *mol);
    00225
    00226     void mergeFragsWithComm(std::list<EmbeddedFrag> &efrags); //, const RDKit::ROMol *mol);
    00227
    00228     //! Mark this fragment to be done for final embedding
    00229     void markDone() {
    00230       d_done = true;
    00231     }
    00232
    00233     //! If this fragment done for the final embedding
    00234     bool isDone() {
    00235       return d_done;
    00236     }
    00237
    00238     //! Get the molecule that this embedded fragmetn blongs to
    00239     const RDKit::ROMol *getMol() const { return dp_mol;}
    00240
    00241     //! Find the common atom ids between this fragment and a second one
    00242     RDKit::INT_VECT findCommonAtoms(const EmbeddedFrag &efrag2);
    00243
    00244     //! Find a neighbor to a non-ring atom among the already embedded atoms
    00245     /*!
    00246       ARGUMENTS:
    00247       \param aid  the atom id of interest
    00248       \param mol  molecule object
    00249
    00250       RETURNS:
    00251       \return the id of the atom if we found a neighbor
    00252                    -1 otherwise
    00253
    00254       NOTE: by definition we can have only one neighbor in the embdded system.
    00255     */
    00256     int findNeighbor(unsigned int aid); //, const RDKit::ROMol *mol);
    00257
    00258     //! Tranform this object to a new coordinates system
    00259     /*!
    00260       ARGUMENTS:
    00261       \param trans : the transformation that need to be applied to the atoms in this object
    00262     */
    00263     void Transform(const RDGeom::Transform2D &trans);
    00264
    00265     void Reflect(const RDGeom::Point2D &loc1,
    00266                  const RDGeom::Point2D &loc2);
    00267
    00268     const INT_EATOM_MAP &GetEmbeddedAtoms() const {
    00269       return d_eatoms;
    00270     }
    00271
    00272     void Translate(const RDGeom::Point2D &shift) {
    00273       INT_EATOM_MAP_I eari;
    00274       for (eari = d_eatoms.begin(); eari != d_eatoms.end(); eari++) {
    00275         eari->second.loc += shift;
    00276       }
    00277     }
    00278
    00279     EmbeddedAtom GetEmbeddedAtom(unsigned int aid) const {
    00280       INT_EATOM_MAP_CI posi = d_eatoms.find(aid);
    00281       if (posi == d_eatoms.end()) {
    00282         PRECONDITION(0, "Embedded atom does not contain embedded atom specified");
    00283       }
    00284       return posi->second;
    00285     }
    00286
    00287     //! the number of atoms in the embedded system
    00288     int Size() const {
    00289       return d_eatoms.size();
    00290     }
    00291
    00292     //! \brief compute a box that encloses the fragment
    00293     void computeBox();
    00294
    00295     //! \brief Flip atoms on one side of a bond - used in removing colissions
    00296     /*!
    00297       ARGUMENTS:
    00298       \param mol - molecule involved in the frgament
    00299       \param bondId - the bond used as the mirror to flip
    00300     */
    00301     void flipAboutBond(unsigned int bondId); //const RDKit::ROMol *mol, unsigned int bondId);
    00302
    00303     void openAngles(const double *dmat, unsigned int aid1, unsigned int aid2);
    00304
    00305     std::vector<PAIR_I_I> findCollisions(const double *dmat, bool includeBonds=1);
    00306
    00307     void computeDistMat(DOUBLE_SMART_PTR &dmat);
    00308
    00309     double mimicDistMatAndDensityCostFunc(const DOUBLE_SMART_PTR *dmat,
    00310                                           double mimicDmatWt);
    00311
    00312     void permuteBonds(unsigned int aid, unsigned int aid1, unsigned int aid2);
    00313
    00314     void randomSampleFlipsAndPermutations(unsigned int nBondsPerSample=3,
    00315                                           unsigned int nSamples=100, int seed=100,
    00316                                           const DOUBLE_SMART_PTR *dmat=0,
    00317                                           double mimicDmatWt=0.0,
    00318                                           bool permuteDeg4Nodes=false);
    00319
    00320     //! Remove collisions in a structure by flipping rotable bonds
    00321     //! along the shortest path between two colliding atoms
    00322     void removeCollisionsBondFlip();
    00323
    00324     //! Remove collision by opening angles at the offending atoms
    00325     void removeCollisionsOpenAngles();
    00326
    00327     //! Remove collisions by shortening bonds along the shortest path between the atoms
    00328     void removeCollisionsShortenBonds();
    00329
    00330     //! helpers funtions to
    00331
    00332
    00333     //! \brief make list of neighbors for each atom in the embedded system that
    00334     //!  still need to be embedded
    00335     void setupNewNeighs(); //const RDKit::ROMol *mol);
    00336
    00337     //! update the  unembedded neighbor atom list for a specified atom
    00338     void updateNewNeighs(unsigned int aid); //, const RDKit::ROMol *mol);
    00339
    00340     //! \brief Find all atoms in this embedded system that are
    00341     //!  within a specified distant of a point
    00342     int findNumNeigh(const RDGeom::Point2D &pt, double radius);
    00343
    00344
    00345     inline double getBoxPx() {return d_px;}
    00346     inline double getBoxNx() {return d_nx;}
    00347     inline double getBoxPy() {return d_py;}
    00348     inline double getBoxNy() {return d_ny;}
    00349
    00350     void canonicalizeOrientation();
    00351
    00352
    00353   private:
    00354
    00355     double totalDensity();
    00356
    00357     void embedFusedRings(const RDKit::VECT_INT_VECT &fusedRings);
    00358
    00359     //! \brief Find a transform to join a ring to the current embedded frag when we
    00360     //! have only on common atom
    00361     /*!
    00362       So this is the state of affairs assumed here:
    00363       - we already have some rings in the fused system embeded and the
    00364         coordinates for the atoms
    00365       - the coordinates for the atoms in the new ring (with the center
    00366         of rings at the origin) are available nringCors. we want to
    00367         translate and rotate this ring to join with the already
    00368         embeded rings.
    00369       - only one atom is common between this new ring and the atoms
    00370         that are already embedded
    00371       - so we need to compute a transform that includes a translation
    00372         so that the common atom overlaps and the rotation to minimize
    00373         overalp with other atoms.
    00374
    00375       Here's what is done:
    00376       - we bisect the remaining sweep angle at the common atom and
    00377         attach the new ring such that the center of the new ring falls
    00378         on this bisecting line
    00379
    00380       NOTE: It is assumed here that the original coordinates for the
    00381       new ring are such that the center is at the origin (this is the
    00382       way rings come out of embedRing)
    00383     */
    00384     RDGeom::Transform2D computeOneAtomTrans(unsigned int commAid,
    00385                                             const EmbeddedFrag &other);
    00386
    00387
    00388     RDGeom::Transform2D computeTwoAtomTrans(unsigned int aid1, unsigned int aid2,
    00389                                             const RDGeom::INT_POINT2D_MAP &nringCor);
    00390
    00391     //! Merge a ring with already embedded atoms
    00392     /*!
    00393       It is assumed that the new rings has already been oriented
    00394       correctly etc.  This function just update all the relevant data,
    00395       like the neighbor information and the sweep angle
    00396     */
    00397     void mergeRing(const EmbeddedFrag &embRing, unsigned int nCommon,
    00398                    const RDKit::INT_VECT &pinAtoms);
    00399
    00400     //! Reflect a fragment if necessary through a line connecting two atoms
    00401     /*!
    00402
    00403       We want add the new fragment such that, most of its atoms fall
    00404       on the side opoiste to where the atoms already embedded are aid1
    00405       and aid2 give the atoms that were used to align the new ring to
    00406       the embedded atoms and we will assume that that process has
    00407       already taken place (i.e. transformRing has been called)
    00408
    00409     */
    00410     void reflectIfNecessaryDensity(EmbeddedFrag &embFrag, unsigned int aid1,
    00411                                    unsigned int aid2);
    00412
    00413     //! Reflect a fragment if necessary based on the cis/trans specification
    00414     /*!
    00415
    00416       we want to add the new fragment such that the cis/trans
    00417       specification on bond between aid1 and aid2 is not violated. We
    00418       will assume that aid1 and aid2 from this fragments as well as
    00419       embFrag are already aligned to each other.
    00420
    00421       \param embFrag   the fragment that will be reflected if necessary
    00422       \param ctCase    which fragment if the cis/trans dbl bond
    00423                         - 1 means embFrag is the cis/trans fragment
    00424                         - 2 mean "this" is the cis/trans fragment
    00425       \param aid1      first atom that forms the plane (line) of reflection
    00426       \param aid2      seconf atom that forms the plane of reflection
    00427     */
    00428     void reflectIfNecessaryCisTrans(EmbeddedFrag &embFrag, unsigned int ctCase,
    00429                                     unsigned int aid1, unsigned int aid2);
    00430
    00431     //! Reflect a fragment if necessary based on a thrid common point
    00432     /*!
    00433
    00434       we want add the new fragment such that the thrid point falls on
    00435       the same side of aid1 and aid2. We will assume that aid1 and
    00436       aid2 from this fragments as well as embFrag are already aligned
    00437       to each other.
    00438
    00439     */
    00440     void reflectIfNecessaryThirdPt(EmbeddedFrag &embFrag, unsigned int aid1, unsigned int aid2,
    00441                                    unsigned int aid3);
    00442
    00443     //! \brief Initialize this fragment from a ring and coordinates for its atoms
    00444     /*!
    00445       ARGUMENTS:
    00446       /param ring     a vector of atom ids in the ring; it is assumed that there in
    00447                       clockwise or anti-clockwise order
    00448       /param nringMap a map of atomId to coordinate map for the atoms in the ring
    00449     */
    00450     void initFromRingCoords(const RDKit::INT_VECT &ring,
    00451                             const RDGeom::INT_POINT2D_MAP &nringMap);
    00452
    00453     //! Helper function to addNonRingAtom to a specified atoms in the fragment
    00454     /*
    00455       Add an atom to this embedded fragment when the fragment already
    00456       has a atleast two previously added neighbors to 'toAid'. In this
    00457       case we have to choose where the the new neighbor goes based on
    00458       the angle that is already taken around the atom.
    00459
    00460       ARGUMENTS:
    00461       \param aid    ID of the atom to be added
    00462       \param toAid  ID of the atom that is already in this object to which this atom is added
    00463     */
    00464     void addAtomToAtomWithAng(unsigned int aid, unsigned int toAid);
    00465
    00466
    00467     //! Helper function to addNonRingAtom to a specified atoms in the fragment
    00468     /*!
    00469
    00470       Add an atom (aid) to an atom (toAid) in this embedded fragment
    00471       when 'toAid' has one or no neighbors previously added. In this
    00472       case where the new atom should fall is determined by the degree
    00473       of 'toAid' and the congestion around it.
    00474
    00475       ARGUMENTS:
    00476       \param  aid     ID of the atom to be added
    00477       \param  toAid   ID of the atom that is already in this object to which this atom is added
    00478       \param  mol     the molecule we are dealing with
    00479     */
    00480     void addAtomToAtomWithNoAng(unsigned int aid,
    00481                                 unsigned int toAid); //, const RDKit::ROMol *mol);
    00482
    00483     //! Helper funtion to contructor that takes predefined coordinates
    00484     /*!
    00485
    00486       Given an atom with more than 2 neighbors all embedded in this
    00487       fragment this function tries to determine
    00488
    00489       - how much of an angle if left for any new neighbors yet to be
    00490         added
    00491       - which atom should we rotate when we add a new neighbor and in
    00492         which direction (clockwise or anticlockwise
    00493
    00494       This is how it works
    00495       - find the pair of nbrs that have the largest angle
    00496       - this will most likely be the angle that is available - unless
    00497         we have fused rings and we found on of the ring angle !!!! -
    00498         in this cae we find the next best
    00499       - find the smallest anngle that contains one of these nbrs -
    00500         this determined which
    00501       - way we want to rotate
    00502
    00503       ARGUMENTS:
    00504       \param aid        the atom id where we are centered right now
    00505       \param doneNbrs   list of neighbors that are already embedded around aid
    00506     */
    00507     void computeNbrsAndAng(unsigned int aid, const RDKit::INT_VECT &doneNbrs);
    00508     //const RDKit::ROMol *mol);
    00509
    00510     //! are we embedded with the final (molecule) coordinates
    00511     bool d_done;
    00512     double d_px, d_nx, d_py, d_ny;
    00513
    00514     //! a map that takes one from teh atom id to the embeddedatom object for that atom.
    00515     INT_EATOM_MAP d_eatoms;
    00516
    00517     //RDKit::INT_DEQUE d_attachPts;
    00518     RDKit::INT_LIST d_attachPts;
    00519
    00520     // pointer to the owning molecule
    00521     const RDKit::ROMol *dp_mol;
    00522
    00523   };
    00524
    00525
    00526 }
    00527
    00528 #endif