1 /**********************************************************************
2 forcefield.h - Handle OBForceField class.
3 
4 Copyright (C) 2006-2007 by Tim Vandermeersch <tim.vandermeersch@gmail.com>
5 
6 This file is part of the Open Babel project.
7 For more information, see <http://openbabel.org/>
8 
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation version 2 of the License.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 ***********************************************************************/
18 
19 #ifndef OB_FORCEFIELD_H
20 #define OB_FORCEFIELD_H
21 
22 #include <vector>
23 #include <string>
24 
25 #include <openbabel/babelconfig.h>
26 #include <openbabel/mol.h>  // TODO: Move OBMol code out of the header (use OBMol*)
27 #include <openbabel/atom.h> // TODO: Move OBAtom code out of the header
28 #include <openbabel/plugin.h>
29 #include <openbabel/bitvec.h>
30 #include <float.h>
31 
32 namespace OpenBabel
33 {
34   class OBGridData;
35 
36   // log levels
37 #define OBFF_LOGLVL_NONE	0   //!< no output
38 #define OBFF_LOGLVL_LOW		1   //!< SteepestDescent progress... (no output from Energy())
39 #define OBFF_LOGLVL_MEDIUM	2   //!< individual energy terms
40 #define OBFF_LOGLVL_HIGH	3   //!< individual calculations and parameters
41 
42   // terms
43 #define OBFF_ENERGY		(1 << 0)   //!< all terms
44 #define OBFF_EBOND		(1 << 1)   //!< bond term
45 #define OBFF_EANGLE		(1 << 2)   //!< angle term
46 #define OBFF_ESTRBND		(1 << 3)   //!< strbnd term
47 #define OBFF_ETORSION		(1 << 4)   //!< torsion term
48 #define OBFF_EOOP		(1 << 5)   //!< oop term
49 #define OBFF_EVDW		(1 << 6)   //!< vdw term
50 #define OBFF_EELECTROSTATIC	(1 << 7)   //!< electrostatic term
51 
52   // constraint types
53 #define OBFF_CONST_IGNORE	(1 << 0)   //!< ignore the atom while setting up calculations
54 #define OBFF_CONST_ATOM		(1 << 1)   //!< fix the atom position
55 #define OBFF_CONST_ATOM_X	(1 << 2)   //!< fix the x coordinate of the atom position
56 #define OBFF_CONST_ATOM_Y	(1 << 3)   //!< fix the y coordinate of the atom position
57 #define OBFF_CONST_ATOM_Z	(1 << 4)   //!< fix the z coordinate of the atom position
58 #define OBFF_CONST_DISTANCE	(1 << 5)   //!< constrain distance length
59 #define OBFF_CONST_ANGLE	(1 << 6)   //!< constrain angle
60 #define OBFF_CONST_TORSION	(1 << 7)   //!< constrain torsion
61 #define OBFF_CONST_CHIRAL	(1 << 8)   //!< constrain chiral volume
62 
63   // mode arguments for SteepestDescent, ConjugateGradients, ...
64 #define OBFF_NUMERICAL_GRADIENT  	(1 << 0)  //!< use numerical gradients
65 #define OBFF_ANALYTICAL_GRADIENT	(1 << 1)  //!< use analytical gradients
66 
67 const double KCAL_TO_KJ = 4.1868;
68 const double GAS_CONSTANT = 8.31446261815324e-3 / KCAL_TO_KJ;  //!< kcal mol^-1 K^-1 (2018 CODATA recommended value)
69 
70   // inline if statements for logging.
71 #define IF_OBFF_LOGLVL_LOW    if(_loglvl >= OBFF_LOGLVL_LOW)
72 #define IF_OBFF_LOGLVL_MEDIUM if(_loglvl >= OBFF_LOGLVL_MEDIUM)
73 #define IF_OBFF_LOGLVL_HIGH   if(_loglvl >= OBFF_LOGLVL_HIGH)
74 
75   //! The type of line search to be used for optimization -- simple or Newton numeric
76   struct LineSearchType
77   {
78     enum {
79       Simple, Newton2Num
80     };
81   };
82   /*
83   struct ConstraintType
84   {
85     enum {
86       Ignore, Atom, AtomX, AtomY, AtomZ, Distance, Angle, Torsion, Chiral
87     };
88   };
89   */
90 
91   //! \class OBFFParameter forcefield.h <openbabel/forcefield.h>
92   //! \brief Internal class for OBForceField to hold forcefield parameters
93   class OBFPRT OBFFParameter {
94   public:
95     //! Used to store integer atom types
96     int         a, b, c, d;
97     //! used to store string atom types
98     std::string _a, _b, _c, _d;
99 
100     //! Used to store integer type parameters (bondtypes, multiplicity, ...)
101     std::vector<int>    _ipar;
102     //! Used to store double type parameters (force constants, bond lengths, angles, ...)
103     std::vector<double> _dpar;
104 
105     //! Assignment
106     OBFFParameter& operator=(const OBFFParameter &ai)
107       {
108         if (this != &ai) {
109           a = ai.a;
110           b = ai.b;
111           c = ai.c;
112           d = ai.d;
113           _a = ai._a;
114           _b = ai._b;
115           _c = ai._c;
116           _d = ai._d;
117           _ipar = ai._ipar;
118           _dpar = ai._dpar;
119         }
120 
121         return *this;
122       }
123 
124     //! Reset the atom types and set all parameters to zero
clear()125     void clear ()
126     {
127       a = b = c = d = 0;
128       _ipar.clear();
129       _dpar.clear();
130     }
131   }; // class OBFFParameter
132 
133   // specific class introductions in forcefieldYYYY.cpp (for YYYY calculations)
134 
135   //! \class OBFFCalculation2 forcefield.h <openbabel/forcefield.h>
136   //! \brief Internal class for OBForceField to hold energy and gradient calculations on specific force fields
137   class OBFPRT OBFFCalculation2
138   {
139   public:
140     //! Used to store the energy for this OBFFCalculation
141     double energy;
142     //! Used to store the atoms for this OBFFCalculation
143     OBAtom *a, *b;
144     //! Used to store the index of atoms for this OBFFCalculation
145     int idx_a, idx_b;
146     //! Pointer to atom coordinates as double[3]
147     double *pos_a, *pos_b;
148     //! Pointer to atom forces
149     double force_a[3], force_b[3];
150     //! Destructor
~OBFFCalculation2()151     virtual ~OBFFCalculation2()
152     {
153     }
154     //! \return Setup pointers to atom positions and forces (To be called
155     //!  while setting up calculations). Sets optimized to true.
SetupPointers()156     virtual void SetupPointers()
157     {
158       if (!a || !b) return;
159       pos_a = a->GetCoordinate();
160       idx_a = a->GetIdx();
161       pos_b = b->GetCoordinate();
162       idx_b = b->GetIdx();
163     }
164   };
165 
166   //! \class OBFFCalculation3 forcefield.h <openbabel/forcefield.h>
167   //! \brief Internal class for OBForceField to hold energy and gradient calculations on specific force fields
168   class OBFPRT OBFFCalculation3: public OBFFCalculation2
169   {
170   public:
171     //! Used to store the atoms for this OBFFCalculation
172     OBAtom *c;
173     //! Used to store the index of atoms for this OBFFCalculation
174     int idx_c;
175     //! Pointer to atom coordinates as double[3]
176     double *pos_c;
177     //! Pointer to atom forces
178     double force_c[3];
179     //! Destructor
~OBFFCalculation3()180     virtual ~OBFFCalculation3()
181     {
182     }
183     //! \return Setup pointers to atom positions and forces (To be called
184     //!  while setting up calculations). Sets optimized to true.
SetupPointers()185     virtual void SetupPointers()
186     {
187       if (!a || !b || !c) return;
188       pos_a = a->GetCoordinate();
189       idx_a = a->GetIdx();
190       pos_b = b->GetCoordinate();
191       idx_b = b->GetIdx();
192       pos_c = c->GetCoordinate();
193       idx_c = c->GetIdx();
194     }
195   };
196 
197   //! \class OBFFCalculation4 forcefield.h <openbabel/forcefield.h>
198   //! \brief Internal class for OBForceField to hold energy and gradient calculations on specific force fields
199   class OBFPRT OBFFCalculation4: public OBFFCalculation3
200   {
201   public:
202     //! Used to store the atoms for this OBFFCalculation
203     OBAtom *d;
204     //! Used to store the index of atoms for this OBFFCalculation
205     int idx_d;
206     //! Pointer to atom coordinates as double[3]
207     double *pos_d;
208     //! Pointer to atom forces
209     double force_d[3];
210     //! Destructor
~OBFFCalculation4()211     virtual ~OBFFCalculation4()
212     {
213     }
214     //! \return Setup pointers to atom positions and forces (To be called
215     //!  while setting up calculations). Sets optimized to true.
SetupPointers()216     void SetupPointers()
217     {
218       if (!a || !b || !c || !d) return;
219       pos_a = a->GetCoordinate();
220       idx_a = a->GetIdx();
221       pos_b = b->GetCoordinate();
222       idx_b = b->GetIdx();
223       pos_c = c->GetCoordinate();
224       idx_c = c->GetIdx();
225       pos_d = d->GetCoordinate();
226       idx_d = d->GetIdx();
227     }
228   };
229 
230   //! \class OBFFConstraint forcefield.h <openbabel/forcefield.h>
231   //! \brief Internal class for OBForceField to hold constraints
232   //! \since version 2.2
233   class OBFPRT OBFFConstraint
234   {
235   public:
236     //! Used to store the contraint energy for this OBFFConstraint
237     double factor, constraint_value;
238     double rab0, rbc0;
239     //! Used to store the contraint type for this OBFFConstraint
240     int type, ia, ib, ic, id;
241     //! Used to store the atoms for this OBFFCostraint
242     OBAtom *a, *b, *c, *d;
243     //! Used to store the gradients for this OBFFCalculation
244     vector3 grada, gradb, gradc, gradd;
245 
246     //! Constructor
OBFFConstraint()247     OBFFConstraint()
248       {
249         a = b = c = d = nullptr;
250         ia = ib = ic = id = 0;
251         constraint_value = 0.0;
252         factor = 0.0;
253       }
254     //! Destructor
~OBFFConstraint()255     ~OBFFConstraint()
256       {
257       }
258 
GetGradient(int a)259     vector3 GetGradient(int a)
260     {
261       if (a == ia)
262         return grada;
263       else if (a == ib)
264         return gradb;
265       else if (a == ic)
266         return gradc;
267       else if (a == id)
268         return gradd;
269       else
270         return  VZero;
271     }
272   };
273 
274   //! \class OBFFConstraints forcefield.h <openbabel/forcefield.h>
275   //! \brief Internal class for OBForceField to handle constraints
276   //! \since version 2.2
277   class OBFPRT OBFFConstraints
278   {
279   public:
280     //! Constructor
281     OBFFConstraints();
282     //! Destructor
~OBFFConstraints()283     ~OBFFConstraints()
284       {
285         _constraints.clear();
286         _ignored.Clear();
287         _fixed.Clear();
288         _Xfixed.Clear();
289         _Yfixed.Clear();
290         _Zfixed.Clear();
291       }
292     //! Clear all constraints
293     void Clear();
294     //! Get the constraint energy
295     double GetConstraintEnergy();
296     //! Get the constraint gradient for atom with index a
297     vector3 GetGradient(int a);
298     //! Get the constrain gradient for the atom
299     OBFFConstraints& operator=(const OBFFConstraints &ai)
300       {
301         if (this != &ai) {
302           _constraints = ai._constraints;
303           _ignored = ai._ignored;
304           _fixed = ai._fixed;
305           _Xfixed = ai._Xfixed;
306           _Yfixed = ai._Yfixed;
307           _Zfixed = ai._Zfixed;
308         }
309         return *this;
310       }
311 
312     /*! Translate indices to OBAtom* objects, this function is called from OBForceField::Setup,
313      *  this function doesn't have to be called from anywhere else.
314      */
315     void Setup(OBMol &mol);
316 
317     /////////////////////////////////////////////////////////////////////////
318     // Set Constraints                                                     //
319     /////////////////////////////////////////////////////////////////////////
320     //! \name Methods to set constraints
321     //@{
322     //! Set Constraint factor
323     void SetFactor(double factor);
324     //! Ignore the atom while setting up calculations
325     void AddIgnore(int a);
326     //! Fix the position of an atom
327     void AddAtomConstraint(int a);
328     //! Fix the x coordinate of the atom position
329     void AddAtomXConstraint(int a);
330     //! Fix the y coordinate of the atom position
331     void AddAtomYConstraint(int a);
332     //! Fix the z coordinate of the atom position
333     void AddAtomZConstraint(int a);
334     //! Constrain the bond length a-b
335     void AddDistanceConstraint(int a, int b, double length);
336     //! Constrain the angle a-b-c
337     void AddAngleConstraint(int a, int b, int c, double angle);
338     //! Constrain the torsion angle a-b-c-d
339     void AddTorsionConstraint(int a, int b, int c, int d, double torsion);
340     //! Delete a constraint
341     //! \par index constraint index
342     void DeleteConstraint(int index);
343     //@}
344     /////////////////////////////////////////////////////////////////////////
345     // Get Constraints                                                     //
346     /////////////////////////////////////////////////////////////////////////
347     //! \name Methods to get information about set constraints
348     //@{
349     //! Get Constraint factor
350     double GetFactor();
351     //! \returns the number of set constraints
352     int Size() const;
353     /*! The following constraint types are known: OBFF_CONST_IGNORE (ignore
354      *  the atom while setting up calculations, forcefield implementations
355      *  need to check this value in their setup function), OBFF_CONST_ATOM
356      *  (fix atom position), OBFF_CONST_ATOM_X (fix x coordinate),
357      *  OBFF_CONST_ATOM_Y (fix y coordinate), OBFF_CONST_ATOM_Z (fix z
358      *  coordinate), OBFF_CONST_BOND (constrain bond length), OBFF_CONST_ANGLE
359      *  (constrain angle), OBFF_CONST_TORSION (constrain torsion angle)
360      *  \return the constraint type
361      */
362     int GetConstraintType(int index) const;
363     /*! \return The constraint value, this can be a bond length, angle or
364      *   torsion angle depending on the constraint type.
365      */
366     double GetConstraintValue(int index) const;
367     //! \return The constraint atom a (or fixed atom)
368     //! \par index constraint index
369     int GetConstraintAtomA(int index) const;
370     //! \return The constraint atom b
371     //! \par index constraint index
372     int GetConstraintAtomB(int index) const;
373     //! \return The constraint atom c
374     //! \par index constraint index
375     int GetConstraintAtomC(int index) const;
376     //! \return The constraint atom d
377     //! \par index constraint index
378     int GetConstraintAtomD(int index) const;
379     //! \return true if this atom is ignored
380     //! \par a atom index
381     bool IsIgnored(int a);
382     //! \return true if this atom is fixed
383     //! \par a atom index
384     bool IsFixed(int a);
385     //! \return true if the x coordinate for this atom is fixed
386     //! \par a atom index
387     bool IsXFixed(int a);
388     //! \return true if the y coordinate for this atom is fixed
389     //! \par a atom index
390     bool IsYFixed(int a);
391     //! \return true if the z coordinate for this atom is fixed
392     //! \par a atom index
393     bool IsZFixed(int a);
394     //! \return the ignored atom indexes as bitvec. (used in
395     //! OBForceField::Setup() to determine if a call to
396     //! OBForceField::SetupCalculations() is needed)
GetIgnoredBitVec()397     OBBitVec GetIgnoredBitVec() { return _ignored; }
398     //! \return the fixed atom indexes as bitvec. (used in
399     //! OBForceField::SystematicRotorSearch() and similar)
GetFixedBitVec()400     OBBitVec GetFixedBitVec() { return _fixed; }
401     //@}
402 
403   private:
404     std::vector<OBFFConstraint> _constraints;
405     OBBitVec	_ignored;
406     OBBitVec	_fixed;
407     OBBitVec	_Xfixed;
408     OBBitVec	_Yfixed;
409     OBBitVec	_Zfixed;
410     double _factor;
411   };
412 
413   // Class OBForceField
414   // class introduction in forcefield.cpp
415   class OBFPRT OBForceField : public OBPlugin
416   {
417     MAKE_PLUGIN(OBForceField)
418 
419     protected:
420 
421       /*!
422       Get the correct OBFFParameter from a OBFFParameter vector.
423 
424       \code vector<OBFFParameter> parameters; \endcode
425 
426       this vector is filled with entries (as OBFFParameter) from
427       a parameter file. This happens in the Setup() function.
428 
429       \code GetParameter(a, 0, 0, 0, parameters); \endcode
430 
431       returns the first OBFFParameter from vector<OBFFParameter>
432       parameters where: pa = a (pa = parameter.a)
433 
434       use: vdw parameters, ...
435 
436       \code GetParameter(a, b, 0, 0, parameters); \endcode
437 
438       returns the first OBFFParameter from vector<OBFFParameter>
439       parameters where: pa = a & pb = b      (ab)
440       or: pa = b & pb = a      (ba)
441 
442       use: bond parameters, vdw parameters (pairs), ...
443 
444       \code GetParameter(a, b, c, 0, parameters); \endcode
445 
446       returns the first OBFFParameter from vector<OBFFParameter>
447       parameters where: pa = a & pb = b & pc = c     (abc)
448       or: pa = c & pb = b & pc = a     (cba)
449 
450       use: angle parameters, ...
451 
452       \code GetParameter(a, b, c, d, parameters); \endcode
453 
454       returns the first OBFFParameter from vector<OBFFParameter>
455       parameters where: pa = a & pb = b & pc = c & pd = d    (abcd)
456       or: pa = d & pb = b & pc = c & pd = a    (dbca)
457       or: pa = a & pb = c & pc = b & pd = d    (acbd)
458       or: pa = d & pb = c & pc = b & pd = a    (dcba)
459 
460       use: torsion parameters, ...
461     */
462     OBFFParameter* GetParameter(int a, int b, int c, int d, std::vector<OBFFParameter> &parameter);
463     //! see GetParameter(int a, int b, int c, int d, std::vector<OBFFParameter> &parameter)
464     OBFFParameter* GetParameter(const char* a, const char* b, const char* c, const char* d,
465         std::vector<OBFFParameter> &parameter);
466     //! Get index for vector<OBFFParameter> ...
467     int GetParameterIdx(int a, int b, int c, int d, std::vector<OBFFParameter> &parameter);
468 
469     /*! Calculate the potential energy function derivative numerically with
470      *  repect to the coordinates of atom with index a (this vector is the gradient)
471      *
472      * \param a  provides coordinates
473      * \param terms OBFF_ENERGY, OBFF_EBOND, OBFF_EANGLE, OBFF_ESTRBND, OBFF_ETORSION,
474      * OBFF_EOOP, OBFF_EVDW, OBFF_ELECTROSTATIC
475      * \return the negative gradient of atom a
476      */
477     vector3 NumericalDerivative(OBAtom *a, int terms = OBFF_ENERGY);
478     //! OB 3.0
479     vector3 NumericalSecondDerivative(OBAtom *a, int terms = OBFF_ENERGY);
480 
481     /*
482      *   NEW gradients functions
483      */
484 
485     /*! Set the gradient for atom with index idx to grad
486      */
SetGradient(double * grad,int idx)487     void SetGradient(double *grad, int idx)
488     {
489       const int coordIdx = (idx - 1) * 3;
490       for (unsigned int i = 0; i < 3; ++i) {
491         _gradientPtr[coordIdx + i] = grad[i];
492       }
493     }
494 
495     /*! Add grad to the gradient for atom with index idx
496      */
AddGradient(double * grad,int idx)497     void AddGradient(double *grad, int idx)
498     {
499       const int coordIdx = (idx - 1) * 3;
500       for (unsigned int i = 0; i < 3; ++i) {
501         _gradientPtr[coordIdx + i] += grad[i];
502       }
503     }
504 
505     /*! Set all gradients to zero
506      */
ClearGradients()507     virtual void ClearGradients()
508     {
509       // We cannot use memset because IEEE floating point representations
510       // are not guaranteed by C/C++ standard, but this loop can be
511       // unrolled or vectorized by compilers
512       for (unsigned int i = 0; i < _ncoords; ++i)
513         _gradientPtr[i] = 0.0;
514       //      memset(_gradientPtr, '\0', sizeof(double)*_ncoords);
515     }
516 
517     /*! Check if two atoms are in the same ring. [NOTE: this function uses SSSR,
518      *  this means that not all rings are found for bridged rings. This causes
519      *  some problems with the MMFF94 validation.]
520      *  \param a atom a
521      *  \param b atom b
522      *  \return true if atom a and b are in the same ring
523      */
524     bool IsInSameRing(OBAtom* a, OBAtom* b);
525 
526     // general variables
527     OBMol 	_mol; //!< Molecule to be evaluated or minimized
528     bool 	_init; //!< Used to make sure we only parse the parameter file once, when needed
529     std::string	_parFile; //! < parameter file name
530     bool 	_validSetup; //!< was the last call to Setup successful
531     double	*_gradientPtr; //!< pointer to the gradients (used by AddGradient(), minimization functions, ...)
532     // logging variables
533     std::ostream* _logos; //!< Output for logfile
534     char 	_logbuf[BUFF_SIZE+1]; //!< Temporary buffer for logfile output
535     int 	_loglvl; //!< Log level for output
536     int 	_origLogLevel;
537     // conformer genereation (rotor search) variables
538     int 	_current_conformer; //!< used to hold i for current conformer (needed by UpdateConformers)
539     std::vector<double> _energies; //!< used to hold the energies for all conformers
540     // minimization variables
541     double 	_econv, _gconv, _e_n1; //!< Used for conjugate gradients and steepest descent(Initialize and TakeNSteps)
542     int 	_cstep, _nsteps; //!< Used for conjugate gradients and steepest descent(Initialize and TakeNSteps)
543     double 	*_grad1; //!< Used for conjugate gradients and steepest descent(Initialize and TakeNSteps)
544     unsigned int _ncoords; //!< Number of coordinates for conjugate gradients
545     int         _linesearch; //!< LineSearch type
546     // molecular dynamics variables
547     double 	_timestep; //!< Molecular dynamics time step in picoseconds
548     double 	_temp; //!< Molecular dynamics temperature in Kelvin
549     double 	*_velocityPtr; //!< pointer to the velocities
550     // contraint varibles
551     static OBFFConstraints _constraints; //!< Constraints
552     static unsigned int _fixAtom; //!< SetFixAtom()/UnsetFixAtom()
553     static unsigned int _ignoreAtom; //!< SetIgnoreAtom()/UnsetIgnoreAtom()
554     // cut-off variables
555     bool 	_cutoff; //!< true = cut-off enabled
556     double 	_rvdw; //!< VDW cut-off distance
557     double 	_rele; //!< Electrostatic cut-off distance
558     double _epsilon; //!< Dielectric constant for electrostatics
559     OBBitVec	_vdwpairs; //!< VDW pairs that should be calculated
560     OBBitVec	_elepairs; //!< Electrostatic pairs that should be calculated
561     int 	_pairfreq; //!< The frequence to update non-bonded pairs
562     // group variables
563     std::vector<OBBitVec> _intraGroup; //!< groups for which intra-molecular interactions should be calculated
564     std::vector<OBBitVec> _interGroup; //!< groups for which intra-molecular interactions should be calculated
565     std::vector<std::pair<OBBitVec, OBBitVec> > _interGroups; //!< groups for which intra-molecular
566                                                               //!< interactions should be calculated
567   public:
568     /*! Clone the current instance. May be desirable in multithreaded environments,
569      *  Should be deleted after use
570      */
571     virtual OBForceField* MakeNewInstance()=0;
572 
573     //! Destructor
~OBForceField()574     virtual ~OBForceField()
575     {
576       if (_grad1 != nullptr) {
577         delete [] _grad1;
578         _grad1 = nullptr;
579       }
580       if (_gradientPtr != nullptr) {
581         delete [] _gradientPtr;
582 	_gradientPtr = nullptr;
583       }
584     }
585 
586     //! \return Plugin type ("forcefields")
TypeID()587     const char* TypeID()
588     {
589       return "forcefields";
590     }
591 
592     /*! \param ID forcefield id (Ghemical, MMFF94, UFF, ...).
593      *  \return A pointer to a forcefield (the default if ID is empty), or NULL if not available.
594      */
FindForceField(const std::string & ID)595     static OBForceField* FindForceField(const std::string& ID)
596     {
597       return FindType(ID.c_str());
598     }
599     /*! \param ID forcefield id (Ghemical, MMFF94, UFF, ...).
600      *  \return A pointer to a forcefield (the default if ID is empty), or NULL if not available.
601      */
FindForceField(const char * ID)602     static OBForceField* FindForceField(const char *ID)
603     {
604       return FindType(ID);
605     }
606     /*
607      *
608      */
SetParameterFile(const std::string & filename)609     void SetParameterFile(const std::string &filename)
610     {
611       _parFile = filename;
612       _init = false;
613     }
614     /*! \return The unit (kcal/mol, kJ/mol, ...) in which the energy is expressed as std::string.
615      */
GetUnit()616     virtual std::string GetUnit() { return std::string("au"); }
617     /* Does this force field have analytical gradients defined for all
618      * calculation components (bonds, angles, non-bonded, etc.)
619      * If this is true, code should default to using OBFF_ANALYTICAL_GRADIENT
620      * for SteepestDescent() or ConjugateGradients().
621      * \return True if all analytical gradients are implemented.
622      */
HasAnalyticalGradients()623     virtual bool HasAnalyticalGradients() { return false; }
624     /*! Setup the forcefield for mol (assigns atom types, charges, etc.). Keep current constraints.
625      *  \param mol The OBMol object that contains the atoms and bonds.
626      *  \return True if successful.
627      */
628     bool Setup(OBMol &mol);
629     /*! Setup the forcefield for mol (assigns atom types, charges, etc.). Use new constraints.
630      *  \param mol The OBMol object that contains the atoms and bonds.
631      *  \param constraints The OBFFConstraints object that contains the constraints.
632      *  \return True if successful.
633      */
634     bool Setup(OBMol &mol, OBFFConstraints &constraints);
635     /*! Load the parameters (this function is overloaded by the individual forcefields,
636      *  and is called autoamically from OBForceField::Setup()).
637      */
638     // move to protected in future version
ParseParamFile()639     virtual bool ParseParamFile() { return false; }
640     /*! Set the atom types (this function is overloaded by the individual forcefields,
641      *  and is called autoamically from OBForceField::Setup()).
642      */
643     // move to protected in future version
SetTypes()644     virtual bool SetTypes() { return false; }
645     /*! Set the formal charges (this function is overloaded by the individual forcefields,
646      *  and is called autoamically from OBForceField::Setup()).
647      */
648     // move to protected in future version
SetFormalCharges()649     virtual bool SetFormalCharges() { return false; }
650     /*! Set the partial charges (this function is overloaded by the individual forcefields,
651      *  and is called autoamically from OBForceField::Setup()).
652      */
653     // move to protected in future version
SetPartialCharges()654     virtual bool SetPartialCharges() { return false; }
655     /*! Setup the calculations (this function is overloaded by the individual forcefields,
656      *  and is called autoamically from OBForceField::Setup()).
657      */
658     // move to protected in future version
SetupCalculations()659     virtual bool SetupCalculations() { return false; }
660     /*! Setup the pointers to the atom positions in the OBFFCalculation objects. This method
661      *  will iterate over all the calculations and call SetupPointers for each one. (This
662      *  function should be implemented by the individual force field implementations).
663      */
664     // move to protected in future version
SetupPointers()665     virtual bool SetupPointers() { return false; }
666     /*! Compare the internal forcefield OBMol object to mol. If the two have the
667      *  same number of atoms and bonds, and all atomic numbers are the same,
668      *  this function returns false, and no call to Setup is needed.
669      *  \return True if Setup needs to be called.
670      */
671     bool IsSetupNeeded(OBMol &mol);
672     /*! Get the force atom types. The atom types will be added to
673      *  the atoms of mol as OBPairData. The attribute will be "FFAtomType".
674      *
675      *  \code
676      *  ...
677      *  pFF->Setup(&mol);
678      *  pFF->GetAtomTypes(&mol);
679      *  FOR_ATOMS_OF_MOL (atom, mol) {
680      *    OBPairData *type = (OBPairData*) atom->GetData("FFAtomType");
681      *    if (type)
682      *      cout << "atom " << atom->GetIdx() << " : " << type->GetValue() << endl;
683      *  }
684      *  ...
685      *  \endcode
686      */
687     bool GetAtomTypes(OBMol &mol);
688     /*! Get the force field formal charges. The formal charges will be added to
689      *  the atoms of mol as OBPairData. The attribute will be "FFPartialCharge".
690      *
691      *  \code
692      *  ...
693      *  pFF->Setup(&mol);
694      *  pFF->GetPartialCharges(&mol);
695      *  FOR_ATOMS_OF_MOL (atom, mol) {
696      *    OBPairData *chg = (OBPairData*) atom->GetData("FFPartialCharge");
697      *    if (chg)
698      *      cout << "atom " << atom->GetIdx() << " : " << chg->GetValue() << endl;
699      *  }
700      *  ...
701      *  \endcode
702      */
703     bool GetPartialCharges(OBMol &mol);
704 
705 
706 
707     /*! Get coordinates for current conformer and attach OBConformerData with energies, forces, ... to mol.
708      *  \param mol The OBMol object to copy the coordinates to (from OBForceField::_mol).
709      *  \return True if successful.
710      */
711     bool GetCoordinates(OBMol &mol);
712     //! \deprecated Use GetCooordinates instead.
UpdateCoordinates(OBMol & mol)713     bool UpdateCoordinates(OBMol &mol) {return GetCoordinates(mol); }
714     /*! Get coordinates for all conformers and attach OBConformerData with energies, forces, ... to mol.
715      *  \param mol The OBMol object to copy the coordinates to (from OBForceField::_mol).
716      *  \return True if successful.
717      */
718     bool GetConformers(OBMol &mol);
719     //! \deprecated Use GetConformers instead.
UpdateConformers(OBMol & mol)720     bool UpdateConformers(OBMol &mol) { return GetConformers(mol); }
721     /*! Set coordinates for current conformer.
722      *  \param mol the OBMol object to copy the coordinates from (to OBForceField::_mol).
723      *  \return true if successful.
724      */
725     bool SetCoordinates(OBMol &mol);
726     /*! Set coordinates for all conformers.
727      *  \param mol The OBMol object to copy the coordinates from (to OBForceField::_mol).
728      *  \return True if successful.
729      */
730     bool SetConformers(OBMol &mol);
731     /*! Create a grid with spacing @p step and @p padding. Place a probe atom of type probe at every grid point,
732      *  calculate the energy and store it in the grid. These grids can then be used to create isosurfaces to
733      *  identify locations where the probe atom has favourable interactions with the molecule.
734      *  \param step The grid step size in A..
735      *  \param padding The padding for the grid in A.
736      *  \param type The force field atom type for the probe.
737      *  \param pchg The partial charge for the probe atom.
738      *  \return Pointer to the grid constaining the results.
739      */
740     OBGridData *GetGrid(double step, double padding, const char *type, double pchg);
741 
742     /////////////////////////////////////////////////////////////////////////
743     // Interacting groups                                                  //
744     /////////////////////////////////////////////////////////////////////////
745 
746     //! \name Methods for specifying interaction groups
747     //@{
748     /*! Enable intra-molecular interactions for group (bonds, angles, strbnd, torsions, oop).
749      *  This function should be called before Setup().
750      *  \param group OBBitVec with bits set for the indexes of the atoms which make up the group.
751      */
752     void AddIntraGroup(OBBitVec &group);
753     /*! Enable inter-molecular interactions for group (non-bonded: vdw & ele).
754      *  This function should be called before Setup().
755      *  \param group OBBitVec with bits set for the indexes of the atoms which make up the group.
756      */
757     void AddInterGroup(OBBitVec &group);
758     /*! Enable inter-molecular interactions between group1 and group2 (non-bonded: vdw & ele).
759      *  Note that this function doesn't enable bonded interactions in either group. Non-bonded
760      *  interactions in the groups itself are also not enabled.
761      *  This function should be called before Setup().
762      *  \param group1 OBBitVec with bits set for the indexes of the atoms which make up the first group.
763      *  \param group2 OBBitVec with bits set for the indexes of the atoms which make up the second group.
764      */
765     void AddInterGroups(OBBitVec &group1, OBBitVec &group2);
766     /*! Clear all previously specified groups.
767      */
768     void ClearGroups();
769     /*! \return true if there are groups.
770      */
771     bool HasGroups();
772     //@}
773 
774     /////////////////////////////////////////////////////////////////////////
775     // Cut-off                                                             //
776     /////////////////////////////////////////////////////////////////////////
777 
778     //! \name Methods for Cut-off distances
779     //@{
780     /*! Enable or disable Cut-offs. Cut-offs are disabled by default.
781      *  \param enable Enable when true, disable when false.
782      */
EnableCutOff(bool enable)783     void EnableCutOff(bool enable)
784     {
785       _cutoff = enable;
786     }
787     /*! \return True if Cut-off distances are used.
788      */
IsCutOffEnabled()789     bool IsCutOffEnabled()
790     {
791       return _cutoff;
792     }
793     /*! Set the VDW cut-off distance to r. Note that this does not enable cut-off distances.
794      *  \param r The VDW cut-off distance to be used in A.
795      */
SetVDWCutOff(double r)796     void SetVDWCutOff(double r)
797     {
798       _rvdw = r;
799     }
800     /*! Get the VDW cut-off distance.
801      *  \return The VDW cut-off distance in A.
802      */
GetVDWCutOff()803     double GetVDWCutOff()
804     {
805       return _rvdw;
806     }
807     /*! Set the Electrostatic cut-off distance to r. Note that this does not
808      *  enable cut-off distances.
809      *  \param r The electrostatic cut-off distance to be used in A.
810      */
SetElectrostaticCutOff(double r)811     void SetElectrostaticCutOff(double r)
812     {
813       _rele = r;
814     }
815     /*! Get the Electrostatic cut-off distance.
816      *  \return The electrostatic cut-off distance in A.
817      */
GetElectrostaticCutOff()818     double GetElectrostaticCutOff()
819     {
820       return _rele;
821     }
822     /*! Set the dielectric constant for electrostatic SetupCalculations
823      * \param epsilon The relative permittivity to use (default = 1.0)
824      */
SetDielectricConstant(double epsilon)825      void SetDielectricConstant(double epsilon)
826      {
827        _epsilon = epsilon;
828      }
829      /* Get the dielectric permittivity used for electrostatic calculations
830      * \rreturn The current relative permittivity
831      */
GetDielectricConstant()832      double GetDielectricConstant()
833      {
834        return _epsilon;
835      }
836     /*! Set the frequency by which non-bonded pairs are updated. Values from 10 to 20
837      *  are recommended. Too low will decrease performance, too high will cause
838      *  non-bonded interactions within cut-off not to be calculated.
839      *  \param f The pair list update frequency.
840      */
SetUpdateFrequency(int f)841     void SetUpdateFrequency(int f)
842     {
843       _pairfreq = f;
844     }
845     /*! Get the frequency by which non-bonded pairs are updated.
846      *  \return The pair list update frequency.
847      */
GetUpdateFrequency()848     int GetUpdateFrequency()
849     {
850       return _pairfreq;
851     }
852     /*! Set the bits in _vdwpairs and _elepairs to 1 for interactions that
853      *  are within cut-off distance. This function is called in minimizing
854      *  algorithms such as SteepestDescent and ConjugateGradients.
855      */
856     void UpdatePairsSimple();
857 
858     //void UpdatePairsGroup(); TODO
859 
860     /*! Get the number of non-bonded pairs in _mol.
861      *  \return The number of atom pairs (ignores cutoff)
862      */
863     unsigned int GetNumPairs();
864     /*! Get the number of enabled electrostatic pairs in _mol.
865      *  \return The number of pairs currently enabled (within cut-off distance)
866      */
867     unsigned int GetNumElectrostaticPairs();
868     /*! Get the number of enabled VDW pairs in _mol.
869      *  \return The number of pairs currently enabled (within cut-off distance)
870      */
871     unsigned int GetNumVDWPairs();
872     /*! Set bits in range 0..._numpairs-1 to 1. Using this means there will
873      *  be no cut-off. (not-working: see code for more information.
874      */
EnableAllPairs()875     void EnableAllPairs()
876     {
877       // TODO: OBBitVec doesn't seem to be allocating it's memory correctly
878       //_vdwpairs.SetRangeOn(0, _numpairs-1);
879       //_elepairs.SetRangeOn(0, _numpairs-1);
880     }
881     //@}
882 
883     /*! Get the pointer to the gradients
884      */
885     virtual vector3 GetGradient(OBAtom *a, int /*terms*/ = OBFF_ENERGY)
886     {
887       const int coordIdx = (a->GetIdx() - 1) * 3;
888       return _gradientPtr + coordIdx;
889     }
890 
891     /*! Get the pointer to the gradients
892      */
GetGradientPtr()893     double* GetGradientPtr()
894     {
895       return _gradientPtr;
896     }
897 
898     /////////////////////////////////////////////////////////////////////////
899     // Energy Evaluation                                                   //
900     /////////////////////////////////////////////////////////////////////////
901 
902     //! \name Methods for energy evaluation
903     //@{
904     /*! \param gradients Set to true when the gradients need to be calculated
905      *  (needs to be done before calling GetGradient()).
906      *  \return Total energy.
907      *   \par Output to log:
908      *    OBFF_LOGLVL_NONE:   none \n
909      *    OBFF_LOGLVL_LOW:    none \n
910      *    OBFF_LOGLVL_MEDIUM: energy for individual energy terms \n
911      *    OBFF_LOGLVL_HIGH:   energy for individual energy interactions \n
912      */
UNUSED(gradients)913     virtual double Energy(bool UNUSED(gradients) = true) { return 0.0f; }
914     /*! \param gradients Set to true when the gradients need to be calculated
915      *  (needs to be done before calling GetGradient()).
916      *  \return Bond stretching energy.
917      *   \par Output to log:
918      *    see Energy()
919      */
UNUSED(gradients)920     virtual double E_Bond(bool UNUSED(gradients) = true) { return 0.0f; }
921     /*! \param gradients Set to true when the gradients need to be calculated
922      *  (needs to be done before calling GetGradient()).
923      *  \return Angle bending energy.
924      *  \par Output to log:
925      *   see Energy()
926      */
UNUSED(gradients)927     virtual double E_Angle(bool UNUSED(gradients) = true) { return 0.0f; }
928     /*! \param gradients Set to true when the gradients need to be calculated
929      *  (needs to be done before calling GetGradient()).
930      *  \return Stretch bending energy.
931      *   \par Output to log:
932      *    see Energy()
933      */
UNUSED(gradients)934     virtual double E_StrBnd(bool UNUSED(gradients) = true) { return 0.0f; }
935     /*! \param gradients Set to true when the gradients need to be calculated
936      *  (needs to be done before calling GetGradient()).
937      *  \return Torsional energy.
938      *    \par Output to log:
939      *	  see Energy()
940      */
UNUSED(gradients)941     virtual double E_Torsion(bool UNUSED(gradients) = true) { return 0.0f; }
942     /*! \param gradients Set to true when the gradients need to be calculated
943      *  (needs to be done before calling GetGradient()).
944      *  \return Out-Of-Plane bending energy.
945      *   \par Output to log:
946      *	  see Energy()
947      */
UNUSED(gradients)948     virtual double E_OOP(bool UNUSED(gradients) = true) { return 0.0f; }
949     /*! \param gradients Set to true when the gradients need to be calculated
950      *  (needs to be done before calling GetGradient()).
951      *  \return Van der Waals energy.
952      *   \par Output to log:
953      *	  see Energy()
954      */
UNUSED(gradients)955     virtual double E_VDW(bool UNUSED(gradients) = true) { return 0.0f; }
956     /*! \param gradients Set to true when the gradients need to be calculated
957      *  (needs to be done before calling GetGradient()).
958      *  \return Electrostatic energy.
959      *   \par Output to log:
960      *	  see Energy()
961      */
UNUSED(gradients)962     virtual double E_Electrostatic(bool UNUSED(gradients) = true) { return 0.0f; }
963     //@}
964 
965     /////////////////////////////////////////////////////////////////////////
966     // Logging                                                             //
967     /////////////////////////////////////////////////////////////////////////
968 
969     //! \name Methods for logging
970     //@{
971     /*! Print the atom types to the log.
972      */
973     void PrintTypes();
974     /*! Print the formal charges to the log (atom.GetPartialCharge(),
975      *  MMFF94 FC's are not always int).
976      */
977     void PrintFormalCharges();
978     /*! Print the partial charges to the log.
979      */
980     void PrintPartialCharges();
981     /*! Print the velocities to the log.
982      */
983     void PrintVelocities();
984     /*! Set the stream for logging (can also be &cout for logging to screen).
985      *  \param pos Stream (when pos is 0, std::cout wil be used).
986      *  \return True if successful.
987      */
988     bool SetLogFile(std::ostream *pos);
989     /*! Set the log level (OBFF_LOGLVL_NONE, OBFF_LOGLVL_LOW, OBFF_LOGLVL_MEDIUM, OBFF_LOGLVL_HIGH).
990      *  Inline if statements for logging are available:
991      *  \code
992      *  #define IF_OBFF_LOGLVL_LOW    if(_loglvl >= OBFF_LOGLVL_LOW)
993      *  #define IF_OBFF_LOGLVL_MEDIUM if(_loglvl >= OBFF_LOGLVL_MEDIUM)
994      *  #define IF_OBFF_LOGLVL_HIGH   if(_loglvl >= OBFF_LOGLVL_HIGH)
995      *  \endcode
996      *
997      *  example:
998      *  \code
999      *  SetLogLevel(OBFF_LOGLVL_MEDIUM);
1000      *  IF_OBFF_LOGLVL_HIGH {
1001      *    OBFFLog("this text will NOT be logged...\n");
1002      *  }
1003      *
1004      *  IF_OBFF_LOGLVL_LOW {
1005      *    OBFFLog"this text will be logged...\n");
1006      *  }
1007      *
1008      *  IF_OBFF_LOGLVL_MEDIUM {
1009      *    OBFFLog("this text will also be logged...\n");
1010      *  }
1011      *  \endcode
1012      */
1013     bool SetLogLevel(int level);
1014     /*! \return The log level.
1015      */
GetLogLevel()1016     int GetLogLevel() { return _loglvl; }
1017     /*! Print msg to the logfile.
1018      *  \param msg The message to print.
1019      */
OBFFLog(std::string msg)1020     void OBFFLog(std::string msg)
1021     {
1022       if (!_logos)
1023         return;
1024 
1025       *_logos << msg;
1026     }
1027     /*! Print msg to the logfile.
1028      *  \param msg The message to print.
1029      */
OBFFLog(const char * msg)1030     void OBFFLog(const char *msg)
1031     {
1032       if (!_logos)
1033         return;
1034 
1035       *_logos << msg;
1036     }
1037     //@}
1038 
1039     /////////////////////////////////////////////////////////////////////////
1040     // Structure Generation                                                //
1041     /////////////////////////////////////////////////////////////////////////
1042 
1043     //! \name Methods for structure generation
1044     //@{
1045     //! Generate coordinates for the molecule (distance geometry)
1046     //! \deprecated Use OBDistanceGeometry class instead
1047     void DistanceGeometry();
1048     /*! Generate conformers for the molecule (systematicaly rotating torsions).
1049      *
1050      *  The initial starting structure here is important, this structure should be
1051      *  minimized for the best results. SystematicRotorSearch works by rotating around
1052      *  the rotatable bond in a molecule (see OBRotamerList class). This rotating generates
1053      *  multiple conformers. The energy for all these conformers is then evaluated and the
1054      *  lowest energy conformer is selected.
1055      *
1056      *  \param geomSteps The number of steps to take during geometry optimization.
1057      *  \param sampleRingBonds Whether to sample ring torsions.
1058      *
1059      *	\par Output to log:
1060      *  This function should only be called with the log level set to OBFF_LOGLVL_NONE or OBFF_LOGLVL_LOW. Otherwise
1061      *	too much information about the energy calculations needed for this function will interfere with the output for
1062      *	this function. \n\n
1063      *  OBFF_LOGLVL_NONE:   None. \n
1064      *  OBFF_LOGLVL_LOW:    Number of rotatable bonds, energies for the conformers, which one is the lowest, ... \n
1065      *  OBFF_LOGLVL_MEDIUM: See note above. \n
1066      *  OBFF_LOGLVL_HIGH:   See note above. \n
1067      */
1068     void SystematicRotorSearch(unsigned int geomSteps = 2500, bool sampleRingBonds = false);
1069     /*! Generate conformers for the molecule by systematicaly rotating torsions. To be used in combination with
1070      *  SystematicRotorSearchNexConformer().
1071      *
1072      *  example:
1073      *  \code
1074      *  // pFF is a pointer to a OBForceField class
1075      *  pFF->SystematicRotorSearchInitialize(300);
1076      *  while (pFF->SystematicRotorSearchNextConformer(300)) {
1077      *    // do some updating in your program (show last generated conformer, ...)
1078      *  }
1079      *  \endcode
1080      *
1081      *  If you don't need any updating in your program, SystematicRotorSearch() is recommended.
1082      *
1083      *  \param geomSteps The number of steps to take during geometry optimization.
1084      *  \param sampleRingBonds Whether to sample ring torsions.
1085      *  \return The number of conformers.
1086      */
1087     int SystematicRotorSearchInitialize(unsigned int geomSteps = 2500, bool sampleRingBonds = false);
1088     /*! Evaluate the next conformer.
1089      *  \param geomSteps The number of steps to take during geometry optimization.
1090      *  \return True if there are more conformers.
1091      */
1092     bool SystematicRotorSearchNextConformer(unsigned int geomSteps = 2500);
1093     /*! Generate conformers for the molecule (randomly rotating torsions).
1094      *
1095      *  The initial starting structure here is important, this structure should be
1096      *  minimized for the best results. RandomRotorSearch works by randomly rotating around
1097      *  the rotatable bonds in a molecule (see OBRotamerList class). This rotating generates
1098      *  multiple conformers. The energy for all these conformers is then evaluated and the
1099      *  lowest energy conformer is selected.
1100      *
1101      *  \param conformers The number of random conformers to consider during the search.
1102      *  \param geomSteps The number of steps to take during geometry optimization for each conformer.
1103      *  \param sampleRingBonds Whether to sample ring torsions.
1104      *
1105      *	\par Output to log:
1106      *  This function should only be called with the log level set to OBFF_LOGLVL_NONE or OBFF_LOGLVL_LOW. Otherwise
1107      *	too much information about the energy calculations needed for this function will interfere with the output for
1108      *	this function. \n\n
1109      *  OBFF_LOGLVL_NONE:   None. \n
1110      *  OBFF_LOGLVL_LOW:    Number of rotatable bonds, energies for the conformers, which one is the lowest, ... \n
1111      *  OBFF_LOGLVL_MEDIUM: See note above. \n
1112      *  OBFF_LOGLVL_HIGH:   See note above. \n
1113      */
1114     void RandomRotorSearch(unsigned int conformers, unsigned int geomSteps = 2500,
1115                            bool sampleRingBonds = false);
1116     /*! Generate conformers for the molecule by randomly rotating torsions. To be used in combination with
1117      *  RandomRotorSearchNexConformer().
1118      *
1119      *  example:
1120      *  \code
1121      *  // pFF is a pointer to a OBForceField class
1122      *  pFF->RandomRotorSearchInitialize(300);
1123      *  while (pFF->RandomRotorSearchNextConformer(300)) {
1124      *    // do some updating in your program (show last generated conformer, ...)
1125      *  }
1126      *  \endcode
1127      *
1128      *  If you don't need any updating in your program, RandomRotorSearch() is recommended.
1129      *
1130      *  \param conformers The number of random conformers to consider during the search
1131      *  \param geomSteps The number of steps to take during geometry optimization
1132      *  \param sampleRingBonds Whether to sample ring torsions.
1133      */
1134     void RandomRotorSearchInitialize(unsigned int conformers, unsigned int geomSteps = 2500,
1135                                      bool sampleRingBonds = false);
1136     /*! Evaluate the next conformer.
1137      *  \param geomSteps The number of steps to take during geometry optimization.
1138      *  \return True if there are more conformers.
1139      */
1140     bool RandomRotorSearchNextConformer(unsigned int geomSteps = 2500);
1141     /*! Generate conformers for the molecule (randomly rotating torsions).
1142      *
1143      *  The initial starting structure here is important, this structure should be
1144      *  minimized for the best results. WeightedRotorSearch works by randomly rotating around
1145      *  the rotatable bonds in a molecule (see OBRotamerList class). Unlike RandomRotorSearch()
1146      *  the random choice of torsions is reweighted based on the energy of the generated conformer.
1147      *  Over time, the generated conformers for each step should become increasingly better.
1148      *  The lowest energy conformer is selected.
1149      *
1150      * \param conformers The number of random conformers to consider during the search.
1151      * \param geomSteps The number of steps to take during geometry optimization for each conformer.
1152      *  \param sampleRingBonds Whether to sample ring torsions.
1153      *
1154      *	\par Output to log:
1155      *  This function should only be called with the log level set to OBFF_LOGLVL_NONE or OBFF_LOGLVL_LOW. Otherwise
1156      *	too much information about the energy calculations needed for this function will interfere with the output for
1157      *	this function. \n\n
1158      *  OBFF_LOGLVL_NONE:   None. \n
1159      *  OBFF_LOGLVL_LOW:    Number of rotatable bonds, energies for the conformers, which one is the lowest, ... \n
1160      *  OBFF_LOGLVL_MEDIUM: See note above. \n
1161      *  OBFF_LOGLVL_HIGH:   See note above. \n
1162      */
1163     void WeightedRotorSearch(unsigned int conformers, unsigned int geomSteps,
1164                              bool sampleRingBonds = false);
1165     /**
1166      * @brief A fast rotor search to find low energy conformations
1167      *
1168      * Iterate over each of the rotors, and set the
1169      * torsion angle to that which minimizes the energy (while keeping the rest of the molecule
1170      * fixed). In general (for molecules with more than
1171      * one rotatable bond), this procedure will not find
1172      * the global minimum, but it will at least get rid of any bad
1173      * clashes, and it do so quickly.
1174      *
1175      * Torsions closer to the center
1176      * of the molecule will be optimized first as these most likely
1177      * to generate large clashes.
1178      *
1179      * One possible use of this procedure is to prepare a reasonable 3D structure
1180      * of a molecule for viewing. Another is to prepare the starting structure
1181      * for a more systematic rotor search (in which case you should geometry
1182      * optimize the final structure).
1183      *
1184      * @param permute Whether or not to permute the order of the 4 most central rotors.
1185      *                Default is true. This does a more thorough search, but takes 4! = 24 times
1186      *                as long.
1187      * @since version 2.4
1188      */
1189     int FastRotorSearch(bool permute = true);
1190 
1191 #ifdef HAVE_EIGEN
1192     //! \since version 2.4
1193     int DiverseConfGen(double rmsd, unsigned int nconfs = 0, double energy_gap = 50, bool verbose = false);
1194 #endif
1195 
1196     /////////////////////////////////////////////////////////////////////////
1197     // Energy Minimization                                                 //
1198     /////////////////////////////////////////////////////////////////////////
1199 
1200     //! \name Methods for energy minimization
1201     //@{
1202     /*! Set the LineSearchType. The default type is LineSearchType::Newton2Num.
1203      *  \param type The LineSearchType to be used in SteepestDescent and ConjugateGradients.
1204      */
SetLineSearchType(int type)1205     void SetLineSearchType(int type)
1206     {
1207       _linesearch = type;
1208     }
1209     /*! Get the LineSearchType.
1210      *  \return The current LineSearchType.
1211      */
GetLineSearchType()1212     int GetLineSearchType()
1213     {
1214       return _linesearch;
1215     }
1216     /*! Perform a linesearch starting at atom in direction direction.
1217      * \deprecated Current code should use LineSearch(double *, double*) instead.
1218      */
1219     vector3 LineSearch(OBAtom *atom, vector3 &direction);
1220     /*! Perform a linesearch for the entire molecule in direction @p direction.
1221      *  This function is called when using LineSearchType::Simple.
1222      *
1223      *  \param currentCoords Start coordinates.
1224      *  \param direction The search direction.
1225      *  \return alpha, The scale of the step we moved along the direction vector.
1226      *
1227      *  \par Output to log:
1228      *  OBFF_LOGLVL_NONE:   none \n
1229      *  OBFF_LOGLVL_LOW:    none \n
1230      *  OBFF_LOGLVL_MEDIUM: none \n
1231      *  OBFF_LOGLVL_HIGH:   none \n
1232      */
1233     double LineSearch(double *currentCoords, double *direction);
1234     /*! Perform a linesearch for the entire molecule.
1235      *  This function is called when using LineSearchType::Newton2Num.
1236      *
1237      *  \param direction The search direction.
1238      *  \return alpha, The scale of the step we moved along the direction vector.
1239      *
1240      *  \par Output to log:
1241      *  OBFF_LOGLVL_NONE:   none \n
1242      *  OBFF_LOGLVL_LOW:    none \n
1243      *  OBFF_LOGLVL_MEDIUM: none \n
1244      *  OBFF_LOGLVL_HIGH:   none \n
1245      */
1246     double Newton2NumLineSearch(double *direction);
1247     /*! Set the coordinates of the atoms to origCoord + step.
1248      *  \param origCoords Start coordinates.
1249      *  \param direction The search direction.
1250      *  \param step The step to take.
1251      */
1252     void   LineSearchTakeStep(double *origCoords, double *direction, double step);
1253     /*! Perform steepest descent optimalization for steps steps or until convergence criteria is reached.
1254      *
1255      *  \param steps The number of steps.
1256      *  \param econv Energy convergence criteria. (defualt is 1e-6)
1257      *  \param method Deprecated. (see HasAnalyticalGradients())
1258      *
1259      *  \par Output to log:
1260      *  This function should only be called with the log level set to OBFF_LOGLVL_NONE or OBFF_LOGLVL_LOW. Otherwise
1261      *  too much information about the energy calculations needed for the minimization will interfere with the list
1262      *  of energies for succesive steps. \n\n
1263      *  OBFF_LOGLVL_NONE:   none \n
1264      *  OBFF_LOGLVL_LOW:    header including number of steps and first step \n
1265      *  OBFF_LOGLVL_MEDIUM: see note above \n
1266      *  OBFF_LOGLVL_HIGH:   see note above \n
1267      */
1268     void SteepestDescent(int steps, double econv = 1e-6f, int method = OBFF_ANALYTICAL_GRADIENT);
1269     /*! Initialize steepest descent optimalization, to be used in combination with SteepestDescentTakeNSteps().
1270      *
1271      *  example:
1272      *  \code
1273      *  // pFF is a pointer to a OBForceField class
1274      *  pFF->SteepestDescentInitialize(100, 1e-5f);
1275      *  while (pFF->SteepestDescentTakeNSteps(5)) {
1276      *    // do some updating in your program (redraw structure, ...)
1277      *  }
1278      *  \endcode
1279      *
1280      *  If you don't need any updating in your program, SteepestDescent() is recommended.
1281      *
1282      *  \param steps The number of steps.
1283      *  \param econv Energy convergence criteria. (defualt is 1e-6)
1284      *  \param method Deprecated. (see HasAnalyticalGradients())
1285      *
1286      *  \par Output to log:
1287      *  This function should only be called with the log level set to OBFF_LOGLVL_NONE or OBFF_LOGLVL_LOW. Otherwise
1288      *  too much information about the energy calculations needed for the minimization will interfere with the list
1289      *  of energies for succesive steps. \n\n
1290      *  OBFF_LOGLVL_NONE:   none \n
1291      *  OBFF_LOGLVL_LOW:    header including number of steps \n
1292      *  OBFF_LOGLVL_MEDIUM: see note above \n
1293      *  OBFF_LOGLVL_HIGH:   see note above \n
1294      */
1295     void SteepestDescentInitialize(int steps = 1000, double econv = 1e-6f, int method = OBFF_ANALYTICAL_GRADIENT);
1296     /*! Take n steps in a steepestdescent optimalization that was previously initialized with SteepestDescentInitialize().
1297      *
1298      *  \param n The number of steps to take.
1299      *  \return False if convergence or the number of steps given by SteepestDescentInitialize() has been reached.
1300      *
1301      *  \par Output to log:
1302      *  This function should only be called with the log level set to OBFF_LOGLVL_NONE or OBFF_LOGLVL_LOW. Otherwise
1303      *  too much information about the energy calculations needed for the minimization will interfere with the list
1304      *  of energies for succesive steps. \n\n
1305      *  OBFF_LOGLVL_NONE:   none \n
1306      *  OBFF_LOGLVL_LOW:    step number, energy and energy for the previous step \n
1307      *  OBFF_LOGLVL_MEDIUM: see note above \n
1308      *  OBFF_LOGLVL_HIGH:   see note above \n
1309      */
1310     bool SteepestDescentTakeNSteps(int n);
1311     /*! Perform conjugate gradient optimalization for steps steps or until convergence criteria is reached.
1312      *
1313      *  \param steps The number of steps.
1314      *  \param econv Energy convergence criteria. (defualt is 1e-6)
1315      *  \param method Deprecated. (see HasAnalyticalGradients())
1316      *
1317      *  \par Output to log:
1318      *  This function should only be called with the log level set to OBFF_LOGLVL_NONE or OBFF_LOGLVL_LOW. Otherwise
1319      *  too much information about the energy calculations needed for the minimization will interfere with the list
1320      *  of energies for succesive steps. \n\n
1321      *  OBFF_LOGLVL_NONE:   none \n
1322      *  OBFF_LOGLVL_LOW:    information about the progress of the minimization \n
1323      *  OBFF_LOGLVL_MEDIUM: see note above \n
1324      *  OBFF_LOGLVL_HIGH:   see note above \n
1325      */
1326     void ConjugateGradients(int steps, double econv = 1e-6f, int method = OBFF_ANALYTICAL_GRADIENT);
1327     /*! Initialize conjugate gradient optimalization and take the first step, to be
1328      *  used in combination with ConjugateGradientsTakeNSteps().
1329      *
1330      *  example:
1331      *  \code
1332      *  // pFF is a pointer to a OBForceField class
1333      *  pFF->ConjugateGradientsInitialize(100, 1e-5f);
1334      *  while (pFF->ConjugateGradientsTakeNSteps(5)) {
1335      *    // do some updating in your program (redraw structure, ...)
1336      *  }
1337      *  \endcode
1338      *
1339      *  If you don't need any updating in your program, ConjugateGradients() is recommended.
1340      *
1341      *  \param steps The number of steps.
1342      *  \param econv Energy convergence criteria. (defualt is 1e-6)
1343      *  \param method Deprecated. (see HasAnalyticalGradients())
1344      *
1345      *  \par Output to log:
1346      *  This function should only be called with the log level set to OBFF_LOGLVL_NONE or OBFF_LOGLVL_LOW. Otherwise
1347      *  too much information about the energy calculations needed for the minimization will interfere with the list
1348      *  of energies for succesive steps. \n\n
1349      *  OBFF_LOGLVL_NONE:   none \n
1350      *  OBFF_LOGLVL_LOW:    header including number of steps and first step \n
1351      *  OBFF_LOGLVL_MEDIUM: see note above \n
1352      *  OBFF_LOGLVL_HIGH:   see note above \n
1353      */
1354     void ConjugateGradientsInitialize(int steps = 1000, double econv = 1e-6f, int method = OBFF_ANALYTICAL_GRADIENT);
1355     /*! Take n steps in a conjugate gradient optimalization that was previously
1356      *  initialized with ConjugateGradientsInitialize().
1357      *
1358      *  \param n The number of steps to take.
1359      *  \return False if convergence or the number of steps given by ConjugateGradientsInitialize() has been reached.
1360      *
1361      *  \par Output to log:
1362      *  This function should only be called with the log level set to OBFF_LOGLVL_NONE or OBFF_LOGLVL_LOW. Otherwise
1363      *  too much information about the energy calculations needed for the minimization will interfere with the list
1364      *  of energies for succesive steps. \n\n
1365      *  OBFF_LOGLVL_NONE:   none \n
1366      *  OBFF_LOGLVL_LOW:    step number, energy and energy for the previous step \n
1367      *  OBFF_LOGLVL_MEDIUM: see note above \n
1368      *  OBFF_LOGLVL_HIGH:   see note above \n
1369     */
1370     bool ConjugateGradientsTakeNSteps(int n);
1371     //@}
1372 
1373     /////////////////////////////////////////////////////////////////////////
1374     // Molecular Dynamics                                                  //
1375     /////////////////////////////////////////////////////////////////////////
1376 
1377     //! \name Methods for molecular dynamics
1378     //@{
1379     /*! Generate starting velocities with a Maxwellian distribution.
1380      */
1381     void GenerateVelocities();
1382     /*! Correct the velocities so that the following is true:
1383      *
1384      *  \code
1385      *        3N
1386      *       ----
1387      *  0.5  \    m_i * v_i^2 = 0.5 * Ndf * R * T = E_kin
1388      *       /
1389      *       ----
1390      *       i=1
1391      *
1392      *  E_kin : kinetic energy
1393      *  m_i : mass of atom i
1394      *  v_i : velocity of atom i
1395      *  Ndf : number of degrees of freedom (3 * number of atoms)
1396      *  R : gas constant
1397      *  T : temperature
1398      *  \endcode
1399      *
1400      */
1401     void CorrectVelocities();
1402     /*! Take n steps at temperature T. If no velocities are set, they will be generated.
1403      *
1404      *  example:
1405      *  \code
1406      *  // pFF is a pointer to a OBForceField class
1407      *  while (pFF->MolecularDynamicsTakeNSteps(5, 300)) {
1408      *    // do some updating in your program (redraw structure, ...)
1409      *  }
1410      * \endcode
1411      *
1412      *  \param n The number of steps to take.
1413      *  \param T Absolute temperature in Kelvin.
1414      *  \param timestep The time step in picoseconds. (10e-12 s)
1415      *  \param method OBFF_ANALYTICAL_GRADIENTS (default) or OBFF_NUMERICAL_GRADIENTS
1416      */
1417     void MolecularDynamicsTakeNSteps(int n, double T, double timestep = 0.001, int method = OBFF_ANALYTICAL_GRADIENT);
1418     //@}
1419 
1420     /////////////////////////////////////////////////////////////////////////
1421     // Constraints                                                         //
1422     /////////////////////////////////////////////////////////////////////////
1423 
1424     //! \name Methods for constraints
1425     //@{
1426     /*! Get the current constraints.
1427      *  \return The current constrains stored in the force field.
1428      */
1429     OBFFConstraints& GetConstraints();
1430     /*! Set the constraints.
1431      *  \param constraints The new constraints to be used.
1432      */
1433     void SetConstraints(OBFFConstraints& constraints);
1434     /*! Fix the atom position until UnsetFixAtom() is called. This function
1435      *  can be used in programs that allow the user to interact with a molecule
1436      *  that is being minimized without having to check if the atom is already
1437      *  fixed in the constraints set by Setup() or SetConstraints(). Using this
1438      *  makes sure the selected atom follows the mouse cursur.
1439      *  \param index The index for the atom to fix.
1440      */
1441     void SetFixAtom(int index);
1442     /*! Undo last SetFixAtom. This function will not remove the fix atom
1443      *  constraint for this atom if set by Setup() or SetConstraints().
1444      */
1445     void UnsetFixAtom();
1446     /*! Ignore the atom until UnsetIgnoreAtom() is called. This function
1447      *  can be used in programs that allow the user to interact with a molecule
1448      *  that is being minimized without having to check if the atom is already
1449      *  ignored in the constraints set by Setup() or SetConstraints(). Using this
1450      *  makes sure, in drawing mode, you can close rings without your newly
1451      *  created puching the other atoms away.
1452      *  \param index The index for the atom to ignore.
1453      */
1454     void SetIgnoreAtom(int index);
1455     /*! Undo last SetIgnoreAtom. This function will not remove the ignore atom
1456      *  constraint for this atom if set by Setup() or SetConstraints().
1457      */
1458     void UnsetIgnoreAtom();
1459 
1460     //! internal function
1461     static bool IgnoreCalculation(int a, int b);
1462     //! internal function
1463     static bool IgnoreCalculation(int a, int b, int c);
1464     //! internal function
1465     static bool IgnoreCalculation(int a, int b, int c, int d);
1466     //@}
1467 
1468 
1469     /////////////////////////////////////////////////////////////////////////
1470     // Validation                                                          //
1471     /////////////////////////////////////////////////////////////////////////
1472 
1473     //! \name Methods for forcefield validation
1474     //@{
1475     //! (debugging)
1476     bool DetectExplosion();
1477     //! (debugging)
1478     vector3 ValidateLineSearch(OBAtom *atom, vector3 &direction);
1479     //! (debugging)
1480     void ValidateSteepestDescent(int steps);
1481     //! (debugging)
1482     void ValidateConjugateGradients(int steps);
1483     //! Validate the force field implementation (debugging)
Validate()1484     virtual bool Validate() { return false; }
1485     /*!
1486       Validate the analytical gradients by comparing them to numerical ones. This function has to
1487       be implemented force field specific. (debugging)
1488     */
ValidateGradients()1489     virtual bool ValidateGradients() { return false; }
1490     /*!
1491       Calculate the error of the analytical gradient (debugging)
1492       \return  error = fabs(numgrad - anagrad) / anagrad * 100%
1493     */
1494     vector3 ValidateGradientError(vector3 &numgrad, vector3 &anagrad);
1495     //@}
1496 
1497     /////////////////////////////////////////////////////////////////////////
1498     // Vector Analysis                                                     //
1499     /////////////////////////////////////////////////////////////////////////
1500 
1501     //! \name Methods for vector analysis (used by OBFFXXXXCalculationYYYY)
1502     //@{
1503     /*! Calculate the derivative of a vector length. The vector is given by a - b,
1504      * the length of this vector rab = sqrt(ab.x^2 + ab.y^2 + ab.z^2).
1505      * \param pos_a atom a (coordinates)
1506      * \param pos_b atom b (coordinates)
1507      * \param force_a - return value for the force on atom a
1508      * \param force_b - return value for the force on atom b
1509      * \return The distance between a and b (bondlength for bond stretching, separation for vdw, electrostatic)
1510      */
1511     static double VectorBondDerivative(double *pos_a, double *pos_b,
1512                                        double *force_a, double *force_b);
1513     /*! To be used for VDW or Electrostatic interactions. This
1514      *  is faster than VectorBondDerivative, but does no error checking.
1515      */
1516     static double VectorDistanceDerivative(const double* const pos_i, const double* const pos_j,
1517                                            double *force_i, double *force_j);
1518     //! \deprecated
1519     static double VectorLengthDerivative(vector3 &a, vector3 &b);
1520 
1521     /*! Calculate the derivative of a angle a-b-c. The angle is given by dot(ab,cb)/rab*rcb.
1522      *  Used for harmonic (cubic) angle potentials.
1523      * \param pos_a atom a (coordinates)
1524      * \param pos_b atom b (coordinates)
1525      * \param pos_c atom c (coordinates)
1526      * \param force_a - return value for the force on atom a
1527      * \param force_b - return value for the force on atom b
1528      * \param force_c - return value for the force on atom c
1529      * \return The angle between a-b-c
1530      */
1531     static double VectorAngleDerivative(double *pos_a, double *pos_b, double *pos_c,
1532                                         double *force_a, double *force_b, double *force_c);
1533     //! \deprecated
1534     static double VectorAngleDerivative(vector3 &a, vector3 &b, vector3 &c);
1535     /*! Calculate the derivative of a OOP angle a-b-c-d. b is the central atom, and a-b-c is the plane.
1536      * The OOP angle is given by 90° - arccos(dot(corss(ab,cb),db)/rabbc*rdb).
1537      * \param pos_a atom a (coordinates)
1538      * \param pos_b atom b (coordinates)
1539      * \param pos_c atom c (coordinates)
1540      * \param pos_d atom d (coordinates)
1541      * \param force_a - return value for the force on atom a
1542      * \param force_b - return value for the force on atom b
1543      * \param force_c - return value for the force on atom c
1544      * \param force_d - return value for the force on atom d
1545      * \return The OOP angle for a-b-c-d
1546      */
1547     static double VectorOOPDerivative(double *pos_a, double *pos_b, double *pos_c, double *pos_d,
1548                                       double *force_a, double *force_b, double *force_c, double *force_d);
1549     //! \deprecated
1550     static double VectorOOPDerivative(vector3 &a, vector3 &b, vector3 &c, vector3 &d);
1551     /*! Calculate the derivative of a torsion angle a-b-c-d. The torsion angle is given by arccos(dot(corss(ab,bc),cross(bc,cd))/rabbc*rbccd).
1552      * \param pos_a atom a (coordinates)
1553      * \param pos_b atom b (coordinates)
1554      * \param pos_c atom c (coordinates)
1555      * \param pos_d atom d (coordinates)
1556      * \param force_a - return value for the force on atom a
1557      * \param force_b - return value for the force on atom b
1558      * \param force_c - return value for the force on atom c
1559      * \param force_d - return value for the force on atom d
1560      * \return The tosion angle for a-b-c-d
1561      */
1562     static double VectorTorsionDerivative(double *pos_a, double *pos_b, double *pos_c, double *pos_d,
1563                                           double *force_a, double *force_b, double *force_c, double *force_d);
1564     //! \deprecated
1565     static double VectorTorsionDerivative(vector3 &a, vector3 &b, vector3 &c, vector3 &d);
1566 
1567     /*! inline fuction to speed up minimization speed
1568      * \param i pointer to i[3]
1569      * \param j pointer to j[3]
1570      * \param result pointer to result[3], will be set to i - j
1571      */
VectorSubtract(double * i,double * j,double * result)1572     static void VectorSubtract(double *i, double *j, double *result)
1573     {
1574       for (unsigned int c = 0; c < 3; ++c)
1575         result[c] = i[c] - j[c];
1576     }
1577 
VectorSubtract(const double * const i,const double * const j,double * result)1578     static void VectorSubtract(const double* const i, const double* const j, double *result)
1579     {
1580       for (unsigned int c = 0; c < 3; ++c)
1581         result[c] = i[c] - j[c];
1582     }
1583 
1584     /*! inline fuction to speed up minimization speed
1585      * \param i pointer to i[3]
1586      * \param j pointer to j[3]
1587      * \param result pointer to result[3], will be set to i + j
1588      */
VectorAdd(double * i,double * j,double * result)1589     static void VectorAdd(double *i, double *j, double *result)
1590     {
1591       for (unsigned int c = 0; c < 3; ++c)
1592         result[c] = i[c] + j[c];
1593     }
1594 
1595     /*! inline fuction to speed up minimization speed
1596      * \param i pointer to i[3]
1597      * \param n divide x,y,z with n
1598      * \param result pointer to result[3]
1599      */
VectorDivide(double * i,double n,double * result)1600     static void VectorDivide(double *i, double n, double *result)
1601     {
1602       for (unsigned int c = 0; c < 3; ++c)
1603         result[c] = i[c] / n;
1604     }
1605 
1606     /*! inline fuction to speed up minimization speed
1607      * \param i pointer to i[3]
1608      * \param n multiply x,y,z with n
1609      * \param result pointer to result[3]
1610      */
VectorMultiply(double * i,double n,double * result)1611     static void VectorMultiply(double *i, double n, double *result)
1612     {
1613       for (unsigned int c = 0; c < 3; ++c)
1614         result[c] = i[c] * n;
1615     }
1616 
VectorMultiply(const double * const i,const double n,double * result)1617     static void VectorMultiply(const double* const i, const double n, double *result)
1618     {
1619       for (unsigned int c = 0; c < 3; ++c)
1620         result[c] = i[c] * n;
1621     }
1622 
1623     /*! inline fuction to speed up minimization speed
1624      * \param i pointer to i[3], multiply this vector by n and set this vector to the result.
1625      * \param n the scalar value to be multipled
1626      */
VectorSelfMultiply(double * i,double n)1627     static void VectorSelfMultiply(double *i, double n)
1628     {
1629       for (unsigned int c = 0; c < 3; ++c)
1630         i[c] *= n;
1631     }
1632 
1633     /*! inline fuction to speed up minimization speed
1634      * \param i pointer to i[3] to be normalized
1635      */
VectorNormalize(double * i)1636     static void VectorNormalize(double *i)
1637     {
1638       double length = VectorLength(i);
1639       for (unsigned int c = 0; c < 3; ++c)
1640         i[c] /= length;
1641     }
1642 
1643     /*! inline fuction to speed up minimization speed
1644      * \param from pointer to i[3] to be copied from
1645      * \param to pointer to j[3] to be copied to
1646      */
VectorCopy(double * from,double * to)1647     static void VectorCopy(double *from, double *to)
1648     {
1649       for (unsigned int c = 0; c < 3; ++c)
1650         to[c] = from[c];
1651     }
1652 
1653     /*! inline fuction to speed up minimization speed
1654      * \param i pointer to i[3]
1655      * \return the vector length
1656      */
VectorLength(double * i)1657     static double VectorLength(double *i)
1658     {
1659       return sqrt( i[0]*i[0] + i[1]*i[1] + i[2]*i[2] );
1660     }
1661 
VectorDistance(double * pos_i,double * pos_j)1662     static double VectorDistance(double *pos_i, double *pos_j)
1663     {
1664       double ij[3];
1665       VectorSubtract(pos_i, pos_j, ij);
1666       const double rij = VectorLength(ij);
1667       return rij;
1668     }
1669 
1670     /*! inline fuction to speed up minimization speed
1671      * \param i pointer to i[3]
1672      * \param j pointer to j[3]
1673      * \param k pointer to k[3]
1674      * \return the vector angle ijk (deg)
1675      */
1676     static double VectorAngle(double *i, double *j, double *k);
1677 
1678     /*! inline fuction to speed up minimization speed
1679      * \param i pointer to i[3]
1680      * \param j pointer to j[3]
1681      * \param k pointer to k[3]
1682      * \param l pointer to l[3]
1683      * \return the vector torson ijkl (deg)
1684      */
1685     static double VectorTorsion(double *i, double *j, double *k, double *l);
1686 
1687     /*! inline fuction to speed up minimization speed
1688      * \param i pointer to i[3]
1689      * \param j pointer to j[3]
1690      * \param k pointer to k[3]
1691      * \param l pointer to l[3]
1692      * \return the vector torson ijkl (deg)
1693      */
1694     static double VectorOOP(double *i, double *j, double *k, double *l);
1695 
1696     /*! inline fuction to speed up minimization speed
1697      * \param i pointer to i[3], will set x,y,z to 0,0,0
1698      */
VectorClear(double * i)1699     static void VectorClear(double *i)
1700     {
1701       for (unsigned int c = 0; c < 3; ++c)
1702         i[c] = 0.0;
1703     }
1704 
1705     /*! inline fuction to speed up minimization speed
1706      * \param i pointer to i[3]
1707      * \param j pointer to j[3]
1708      * \return the dot product
1709      */
VectorDot(double * i,double * j)1710     static double VectorDot(double *i, double *j)
1711     {
1712       double result = 0.0;
1713       // Written as a loop for vectorization
1714       // Loop will be unrolled by compiler otherwise
1715       for (unsigned int c = 0; c < 3; ++c)
1716         result += i[c]*j[c];
1717       return result;
1718     }
1719 
1720     /*! inline fuction to speed up minimization speed
1721      * \param i pointer to i[3]
1722      * \param j pointer to j[3]
1723      * \param result the dot product (as a return value double[3])
1724      */
VectorCross(double * i,double * j,double * result)1725     static void VectorCross(double *i, double *j, double *result)
1726     {
1727       result[0] =   i[1]*j[2] - i[2]*j[1];
1728       result[1] = - i[0]*j[2] + i[2]*j[0];
1729       result[2] =   i[0]*j[1] - i[1]*j[0];
1730     }
1731 
PrintVector(double * i)1732     static void PrintVector(double *i)
1733     {
1734       std::cout << "<" << i[0] << ", " << i[1] << ", " << i[2] << ">" << std::endl;
1735     }
1736     //@}
1737 
1738   }; // class OBForceField
1739 
1740 }// namespace OpenBabel
1741 
1742 #endif   // OB_FORCEFIELD_H
1743 
1744 //! \file forcefield.h
1745 //! \brief Handle forcefields
1746