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