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> ¶meter); 463 //! see GetParameter(int a, int b, int c, int d, std::vector<OBFFParameter> ¶meter) 464 OBFFParameter* GetParameter(const char* a, const char* b, const char* c, const char* d, 465 std::vector<OBFFParameter> ¶meter); 466 //! Get index for vector<OBFFParameter> ... 467 int GetParameterIdx(int a, int b, int c, int d, std::vector<OBFFParameter> ¶meter); 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