ForceField.h

Go to the documentation of this file.
00001 //
00002 //  Copyright (C) 2004-2006 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 #ifndef __RD_FORCEFIELD_H__
00011 #define __RD_FORCEFIELD_H__
00012 
00013 #include <vector>
00014 #include <boost/smart_ptr.hpp>
00015 #include <Geometry/point.h>
00016 
00017 namespace ForceFields {
00018   class ForceFieldContrib;
00019   typedef std::vector<int> INT_VECT;
00020   typedef boost::shared_ptr<ForceFieldContrib> ContribPtr;
00021   typedef std::vector<ContribPtr> ContribPtrVect;
00022   
00023   //-------------------------------------------------------
00024   //! A class to store forcefields and handle minimization
00025   /*!
00026      A force field is used like this (schematically):
00027 
00028      \verbatim
00029        ForceField ff;
00030 
00031        // add contributions:
00032        for contrib in contribs:
00033          ff.contribs().push_back(contrib);
00034          
00035        // set up the points:
00036        for positionPtr in positions:
00037          ff.positions().push_back(point);
00038 
00039        // initialize:
00040        ff.initialize()
00041 
00042        // and minimize:
00043        needsMore = ff.minimize();
00044 
00045      \endverbatim
00046 
00047      <b>Notes:</b>
00048        - The ForceField owns its contributions, which are stored using smart
00049          pointers.
00050        - Distance calculations are currently lazy; the full distance matrix is
00051          never generated.  In systems where the distance matrix is not sparse,
00052          this is almost certainly inefficient.
00053 
00054   */
00055   class ForceField {
00056   public:
00057     //! construct with a dimension
00058     ForceField(unsigned int dimension=3) : d_dimension(dimension), df_init(false),
00059                                            d_numPoints(0), dp_distMat(0) {};
00060 
00061     ~ForceField();
00062 
00063     //! does initialization
00064     void initialize();
00065 
00066 
00067     //! calculates and returns the energy based on existing positions in the forcefield
00068     /*!
00069 
00070     \return the current energy
00071 
00072       <b>Note:</b>
00073         This function is less efficient than calcEnergy with postions passed in as double *
00074         the positions need to be converted to double * here
00075     */
00076     double calcEnergy() const;
00077 
00078     // these next two aren't const because they may update our
00079     // distance matrix
00080 
00081     //! calculates and returns the energy of the position passed in
00082     /*!
00083       \param pos an array of doubles.  Should be \c 3*this->numPoints() long.
00084 
00085       \return the current energy
00086 
00087       <b>Side effects:</b>
00088         - Calling this resets the current distance matrix
00089         - The individual contributions may further update the distance matrix
00090     */
00091     double calcEnergy(double *pos);
00092 
00093     //! calculates the gradient of the energy at the current position
00094     /*!
00095 
00096       \param forces an array of doubles.  Should be \c 3*this->numPoints() long.
00097 
00098       <b>Note:</b>
00099         This function is less efficient than calcGrad with positions passed in
00100         the positions need to be converted to double * here
00101      */
00102     void calcGrad(double *forces) const;
00103 
00104     //! calculates the gradient of the energy at the provided position
00105     /*!
00106 
00107       \param pos      an array of doubles.  Should be \c 3*this->numPoints() long.
00108       \param forces   an array of doubles.  Should be \c 3*this->numPoints() long.
00109 
00110       <b>Side effects:</b>
00111         - The individual contributions may modify the distance matrix
00112      */
00113     void calcGrad(double *pos,double *forces);
00114     
00115     //! minimizes the energy of the system by following gradients
00116     /*!
00117       \param maxIts    the maximum number of iterations to try
00118       \param forceTol  the convergence criterion for forces
00119       \param energyTol the convergence criterion for energies
00120 
00121       \return an integer value indicating whether or not the convergence
00122               criteria were achieved:
00123         - 0: indicates success
00124         - 1: the minimization did not converge in \c maxIts iterations.
00125     */
00126     int minimize(unsigned int maxIts=200,double forceTol=1e-4,double energyTol=1e-6);
00127 
00128     // ---------------------------
00129     // setters and getters
00130 
00131     //! returns a reference to our points (a PointPtrVect)
00132     RDGeom::PointPtrVect &positions() { return d_positions; };
00133     const RDGeom::PointPtrVect &positions() const { return d_positions; };
00134 
00135     //! returns a reference to our contribs (a ContribPtrVect)
00136     ContribPtrVect &contribs() { return d_contribs; };
00137     const ContribPtrVect &contribs() const { return d_contribs; };
00138 
00139     //! returns the distance between two points
00140     /*!
00141       \param i point index
00142       \param j point index
00143       \param pos (optional) If this argument is provided, it will be used
00144           to provide the positions of points. \c pos should be
00145           \c 3*this->numPoints() long.
00146 
00147       \return the distance
00148 
00149       <b>Side effects:</b>
00150         - if the distance between i and j has not previously been calculated,
00151           our internal distance matrix will be updated.
00152     */
00153     double distance(unsigned int i,unsigned int j,double *pos=0);
00154 
00155     //! returns the distance between two points
00156     /*!
00157       \param i point index
00158       \param j point index
00159       \param pos (optional) If this argument is provided, it will be used
00160           to provide the positions of points. \c pos should be
00161           \c 3*this->numPoints() long.
00162 
00163       \return the distance
00164 
00165       <b>Note:</b>
00166         The internal distance matrix is not updated in this case
00167     */
00168     double distance(unsigned int i,unsigned int j,double *pos=0) const;
00169 
00170     //! returns the dimension of the forcefield
00171     unsigned int dimension() const {
00172       return d_dimension;
00173     }
00174 
00175     //! returns the number of points the ForceField is handling
00176     unsigned int numPoints() const { return d_numPoints; };
00177 
00178     INT_VECT &fixedPoints() { return d_fixedPoints; };
00179     const INT_VECT &fixedPoints() const { return d_fixedPoints; };
00180     
00181   protected:
00182     unsigned int d_dimension;
00183     bool df_init;              //!< whether or not we've been initialized
00184     unsigned int d_numPoints;  //!< the number of active points
00185     double *dp_distMat;        //!< our internal distance matrix
00186     RDGeom::PointPtrVect d_positions;  //!< pointers to the points we're using
00187     ContribPtrVect d_contribs; //!< contributions to the energy
00188     INT_VECT d_fixedPoints;
00189     unsigned int d_matSize;
00190     //! scatter our positions into an array
00191     /*!
00192         \param pos     should be \c 3*this->numPoints() long;
00193     */
00194     void scatter(double *pos) const;
00195 
00196     //! update our positions from an array
00197     /*!
00198         \param pos     should be \c 3*this->numPoints() long;
00199     */
00200     void gather(double *pos);
00201 
00202     //! initializes our internal distance matrix
00203     void initDistanceMatrix();
00204   };
00205 }
00206 #endif