// // Copyright (C) 2004-2024 Paolo Tosco and other RDKit contributors // // @@ All Rights Reserved @@ // This file is part of the RDKit. // The contents are covered by the terms of the BSD license // which is included in the file license.txt, found at the root // of the RDKit source tree. // // #include #ifndef RD_MMFFPARAMS_H #define RD_MMFFPARAMS_H #include #include #include #include #include #include #include #include #ifndef M_PI #define M_PI 3.14159265358979323846 #endif // binary searches are slightly faster than std::map; // however when I moved to binary searches I had already // written the code for std::map, so the two methods // can be toggled defining RDKIT_MMFF_PARAMS_USE_STD_MAP // #define RDKIT_MMFF_PARAMS_USE_STD_MAP 1 namespace ForceFields { namespace MMFF { constexpr double DEG2RAD = M_PI / 180.0; constexpr double RAD2DEG = 180.0 / M_PI; constexpr double MDYNE_A_TO_KCAL_MOL = 143.9325; inline bool isDoubleZero(const double x) { return ((x < 1.0e-10) && (x > -1.0e-10)); } inline void clipToOne(double &x) { x = std::clamp(x, -1.0, 1.0); } //! class to store MMFF atom type equivalence levels class RDKIT_FORCEFIELD_EXPORT MMFFDef { public: std::uint8_t eqLevel[4]; }; //! class to store MMFF Properties class RDKIT_FORCEFIELD_EXPORT MMFFProp { public: std::uint8_t atno; std::uint8_t crd; std::uint8_t val; std::uint8_t pilp; std::uint8_t mltb; std::uint8_t arom; std::uint8_t linh; std::uint8_t sbmb; }; //! class to store MMFF Partial Bond Charge Increments class RDKIT_FORCEFIELD_EXPORT MMFFPBCI { public: double pbci; double fcadj; }; //! class to store MMFF bond-charge-increment parameters used to //! construct MMFF partial atomic charges class RDKIT_FORCEFIELD_EXPORT MMFFChg { public: double bci; }; //! class to store MMFF parameters for bond stretching class RDKIT_FORCEFIELD_EXPORT MMFFBond { public: double kb; double r0; }; //! class to store parameters for Herschbach-Laurie's version //! of Badger's rule class RDKIT_FORCEFIELD_EXPORT MMFFHerschbachLaurie { public: double a_ij; double d_ij; double dp_ij; }; //! class to store covalent radius and Pauling electronegativity //! values for MMFF bond stretching empirical rule class RDKIT_FORCEFIELD_EXPORT MMFFCovRadPauEle { public: double r0; double chi; }; //! class to store MMFF parameters for angle bending class RDKIT_FORCEFIELD_EXPORT MMFFAngle { public: double ka; double theta0; }; //! class to store MMFF parameters for stretch-bending class RDKIT_FORCEFIELD_EXPORT MMFFStbn { public: double kbaIJK; double kbaKJI; }; //! class to store MMFF parameters for out-of-plane bending class RDKIT_FORCEFIELD_EXPORT MMFFOop { public: double koop; }; //! class to store MMFF parameters for torsions class RDKIT_FORCEFIELD_EXPORT MMFFTor { public: double V1; double V2; double V3; }; //! class to store MMFF parameters for non-bonded Van der Waals class RDKIT_FORCEFIELD_EXPORT MMFFVdW { public: double alpha_i; double N_i; double A_i; double G_i; double R_star; std::uint8_t DA; }; class RDKIT_FORCEFIELD_EXPORT MMFFVdWRijstarEps { public: double R_ij_starUnscaled; double epsilonUnscaled; double R_ij_star; double epsilon; }; class RDKIT_FORCEFIELD_EXPORT MMFFAromCollection { public: //! Looks up the parameters for a particular key and returns them. /*! \return a pointer to the MMFFArom object, NULL on failure. */ bool isMMFFAromatic(const unsigned int atomType) const { return std::find(d_params.begin(), d_params.end(), atomType) != d_params.end(); } MMFFAromCollection(const std::vector *mmffArom = nullptr); std::vector d_params; //!< the aromatic type vector }; class RDKIT_FORCEFIELD_EXPORT MMFFDefCollection { public: //! Looks up the parameters for a particular key and returns them. /*! \return a pointer to the MMFFDef object, NULL on failure. */ const MMFFDef *operator()(const unsigned int atomType) const { #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP const auto res = d_params.find(atomType); return ((res != d_params.end()) ? &((*res).second) : NULL); #else return ((atomType && (atomType <= d_params.size())) ? &d_params[atomType - 1] : nullptr); #endif } MMFFDefCollection(std::string mmffDef = ""); #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP std::map d_params; //!< the parameter map #else std::vector d_params; //!< the parameter vector #endif }; class RDKIT_FORCEFIELD_EXPORT MMFFPropCollection { public: //! Looks up the parameters for a particular key and returns them. /*! \return a pointer to the MMFFProp object, NULL on failure. */ const MMFFProp *operator()(const unsigned int atomType) const { #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP const auto res = d_params.find(atomType); return ((res != d_params.end()) ? &((*res).second) : NULL); #else auto bounds = std::equal_range(d_iAtomType.begin(), d_iAtomType.end(), atomType); return ((bounds.first != bounds.second) ? &d_params[bounds.first - d_iAtomType.begin()] : nullptr); #endif } MMFFPropCollection(std::string mmffProp = ""); #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP std::map d_params; //!< the parameter map #else std::vector d_params; std::vector d_iAtomType; //!< the parameter vector #endif }; class RDKIT_FORCEFIELD_EXPORT MMFFPBCICollection { public: //! Looks up the parameters for a particular key and returns them. /*! \return a pointer to the MMFFPBCI object, NULL on failure. */ const MMFFPBCI *operator()(const unsigned int atomType) const { #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP const auto res = d_params.find(atomType); return ((res != d_params.end()) ? &((*res).second) : NULL); #else return ((atomType && (atomType <= d_params.size())) ? &d_params[atomType - 1] : nullptr); #endif } MMFFPBCICollection(std::string mmffPBCI = ""); #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP std::map d_params; //!< the parameter map #else std::vector d_params; //!< the parameter vector #endif }; class RDKIT_FORCEFIELD_EXPORT MMFFChgCollection { public: //! Looks up the parameters for a particular key and returns them. /*! \return a pointer to the MMFFChg object, NULL on failure. */ const std::pair getMMFFChgParams( const unsigned int bondType, const unsigned int iAtomType, const unsigned int jAtomType) const { int sign = -1; const MMFFChg *mmffChgParams = nullptr; unsigned int canIAtomType = iAtomType; unsigned int canJAtomType = jAtomType; if (iAtomType > jAtomType) { canIAtomType = jAtomType; canJAtomType = iAtomType; sign = 1; } #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP const auto res1 = d_params[bondType].find(canIAtomType); if (res1 != d_params[bondType].end()) { const auto res2 = ((*res1).second).find(canJAtomType); if (res2 != ((*res1).second).end()) { mmffChgParams = &((*res2).second); } } #else auto bounds = std::equal_range(d_iAtomType.begin(), d_iAtomType.end(), canIAtomType); if (bounds.first != bounds.second) { bounds = std::equal_range( d_jAtomType.begin() + (bounds.first - d_iAtomType.begin()), d_jAtomType.begin() + (bounds.second - d_iAtomType.begin()), canJAtomType); if (bounds.first != bounds.second) { bounds = std::equal_range( d_bondType.begin() + (bounds.first - d_jAtomType.begin()), d_bondType.begin() + (bounds.second - d_jAtomType.begin()), bondType); if (bounds.first != bounds.second) { mmffChgParams = &d_params[bounds.first - d_bondType.begin()]; } } } #endif return std::make_pair(sign, mmffChgParams); } MMFFChgCollection(std::string mmffChg = ""); //!< the parameter 3D-map #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP std::map>> d_params; //!< the parameter 3D-map #else std::vector d_params; //!< the parameter vector std::vector d_iAtomType; //!< atom type vector for atom i std::vector d_jAtomType; //!< atom type vector for atom j std::vector d_bondType; //!< bond type vector for bond i-j #endif }; class RDKIT_FORCEFIELD_EXPORT MMFFBondCollection { public: //! Looks up the parameters for a particular key and returns them. /*! \return a pointer to the MMFFBond object, NULL on failure. */ const MMFFBond *operator()(const unsigned int bondType, const unsigned int atomType, const unsigned int nbrAtomType) const { const MMFFBond *mmffBondParams = nullptr; unsigned int canAtomType = atomType; unsigned int canNbrAtomType = nbrAtomType; if (atomType > nbrAtomType) { canAtomType = nbrAtomType; canNbrAtomType = atomType; } #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP const auto res1 = d_params.find(bondType); std::map>::const_iterator res2; std::map::const_iterator res3; if (res1 != d_params.end()) { res2 = ((*res1).second).find(canAtomType); if (res2 != ((*res1).second).end()) { res3 = ((*res2).second).find(canNbrAtomType); if (res3 != ((*res2).second).end()) { mmffBondParams = &((*res3).second); } } } #else auto bounds = std::equal_range(d_iAtomType.begin(), d_iAtomType.end(), canAtomType); if (bounds.first != bounds.second) { bounds = std::equal_range( d_jAtomType.begin() + (bounds.first - d_iAtomType.begin()), d_jAtomType.begin() + (bounds.second - d_iAtomType.begin()), canNbrAtomType); if (bounds.first != bounds.second) { bounds = std::equal_range( d_bondType.begin() + (bounds.first - d_jAtomType.begin()), d_bondType.begin() + (bounds.second - d_jAtomType.begin()), bondType); if (bounds.first != bounds.second) { mmffBondParams = &d_params[bounds.first - d_bondType.begin()]; } } } #endif return mmffBondParams; } MMFFBondCollection(std::string mmffBond = ""); #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP std::map>> d_params; //!< the parameter 3D-map #else std::vector d_params; //!< the parameter vector std::vector d_iAtomType; //!< atom type vector for atom i std::vector d_jAtomType; //!< atom type vector for atom j std::vector d_bondType; //!< bond type vector for bond i-j #endif }; class RDKIT_FORCEFIELD_EXPORT MMFFBndkCollection { public: //! Looks up the parameters for a particular key and returns them. /*! \return a pointer to the MMFFBndk object, NULL on failure. */ const MMFFBond *operator()(const int atomicNum, const int nbrAtomicNum) const { const MMFFBond *mmffBndkParams = nullptr; unsigned int canAtomicNum = atomicNum; unsigned int canNbrAtomicNum = nbrAtomicNum; if (atomicNum > nbrAtomicNum) { canAtomicNum = nbrAtomicNum; canNbrAtomicNum = atomicNum; } #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP const auto res1 = d_params.find(canAtomicNum); std::map::const_iterator res2; if (res1 != d_params.end()) { res2 = ((*res1).second).find(canNbrAtomicNum); if (res2 != ((*res1).second).end()) { mmffBndkParams = &((*res2).second); } } #else auto bounds = std::equal_range(d_iAtomicNum.begin(), d_iAtomicNum.end(), canAtomicNum); if (bounds.first != bounds.second) { bounds = std::equal_range( d_jAtomicNum.begin() + (bounds.first - d_iAtomicNum.begin()), d_jAtomicNum.begin() + (bounds.second - d_iAtomicNum.begin()), canNbrAtomicNum); if (bounds.first != bounds.second) { mmffBndkParams = &d_params[bounds.first - d_jAtomicNum.begin()]; } } #endif return mmffBndkParams; } MMFFBndkCollection(std::string mmffBndk = ""); #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP std::map> d_params; //!< the parameter 2D-map #else std::vector d_params; //!< the parameter vector std::vector d_iAtomicNum; //!< atomic number vector for atom i std::vector d_jAtomicNum; //!< atomic number vector for atom j #endif }; class RDKIT_FORCEFIELD_EXPORT MMFFHerschbachLaurieCollection { public: //! Looks up the parameters for a particular key and returns them. /*! \return a pointer to the MMFFHerschbachLaurie object, NULL on failure. */ const MMFFHerschbachLaurie *operator()(const int iRow, const int jRow) const { const MMFFHerschbachLaurie *mmffHerschbachLaurieParams = nullptr; unsigned int canIRow = iRow; unsigned int canJRow = jRow; if (iRow > jRow) { canIRow = jRow; canJRow = iRow; } #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP const auto res1 = d_params.find(canIRow); std::map::const_iterator res2; if (res1 != d_params.end()) { res2 = ((*res1).second).find(canJRow); if (res2 != ((*res1).second).end()) { mmffHerschbachLaurieParams = &((*res2).second); } } #else auto bounds = std::equal_range(d_iRow.begin(), d_iRow.end(), canIRow); if (bounds.first != bounds.second) { bounds = std::equal_range( d_jRow.begin() + (bounds.first - d_iRow.begin()), d_jRow.begin() + (bounds.second - d_iRow.begin()), canJRow); if (bounds.first != bounds.second) { mmffHerschbachLaurieParams = &d_params[bounds.first - d_jRow.begin()]; } } #endif return mmffHerschbachLaurieParams; } MMFFHerschbachLaurieCollection(std::string mmffHerschbachLaurie = ""); #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP std::map> d_params; //!< the parameter 2D-map #else std::vector d_params; //!< the parameter vector std::vector d_iRow; //!< periodic row number vector for atom i std::vector d_jRow; //!< periodic row number vector for atom j #endif }; class RDKIT_FORCEFIELD_EXPORT MMFFCovRadPauEleCollection { public: //! Looks up the parameters for a particular key and returns them. /*! \return a pointer to the MMFFCovRadPauEle object, NULL on failure. */ const MMFFCovRadPauEle *operator()(const unsigned int atomicNum) const { #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP const auto res = d_params.find(atomicNum); return ((res != d_params.end()) ? &((*res).second) : NULL); #else auto bounds = std::equal_range(d_atomicNum.begin(), d_atomicNum.end(), atomicNum); return ((bounds.first != bounds.second) ? &d_params[bounds.first - d_atomicNum.begin()] : nullptr); #endif } MMFFCovRadPauEleCollection(std::string mmffCovRadPauEle = ""); #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP std::map d_params; //!< the parameter map #else std::vector d_params; //!< the parameter vector std::vector d_atomicNum; //!< the atomic number vector #endif }; class RDKIT_FORCEFIELD_EXPORT MMFFAngleCollection { public: //! Looks up the parameters for a particular key and returns them. /*! \return a pointer to the MMFFAngle object, NULL on failure. */ const MMFFAngle *operator()(const MMFFDefCollection *mmffDef, const unsigned int angleType, const unsigned int iAtomType, const unsigned int jAtomType, const unsigned int kAtomType) const { const MMFFAngle *mmffAngleParams = nullptr; unsigned int iter = 0; // For bending of the i-j-k angle, a five-stage process based // in the level combinations 1-1-1,2-2-2,3-2-3,4-2-4, and // 5-2-5 is used. (MMFF.I, note 68, page 519) // We skip 1-1-1 since Level 2 === Level 1 #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP while ((iter < 4) && (!mmffAngleParams)) { unsigned int canIAtomType = (*mmffDef)(iAtomType)->eqLevel[iter]; unsigned int canKAtomType = (*mmffDef)(kAtomType)->eqLevel[iter]; if (canIAtomType > canKAtomType) { std::swap(canIAtomType, canKAtomType); } const auto res1 = d_params.find(angleType); if (res1 != d_params.end()) { const auto res2 = ((*res1).second).find(canIAtomType); if (res2 != ((*res1).second).end()) { const auto res3 = ((*res2).second).find(jAtomType); if (res3 != ((*res2).second).end()) { const auto res4 = ((*res3).second).find(canKAtomType); if (res4 != ((*res3).second).end()) { mmffAngleParams = &((*res4).second); } } } } ++iter; } #else auto jBounds = std::equal_range(d_jAtomType.begin(), d_jAtomType.end(), jAtomType); if (jBounds.first != jBounds.second) { while ((iter < 4) && (!mmffAngleParams)) { unsigned int canIAtomType = (*mmffDef)(iAtomType)->eqLevel[iter]; unsigned int canKAtomType = (*mmffDef)(kAtomType)->eqLevel[iter]; if (canIAtomType > canKAtomType) { std::swap(canIAtomType, canKAtomType); } auto bounds = std::equal_range( d_iAtomType.begin() + (jBounds.first - d_jAtomType.begin()), d_iAtomType.begin() + (jBounds.second - d_jAtomType.begin()), canIAtomType); if (bounds.first != bounds.second) { bounds = std::equal_range( d_kAtomType.begin() + (bounds.first - d_iAtomType.begin()), d_kAtomType.begin() + (bounds.second - d_iAtomType.begin()), canKAtomType); if (bounds.first != bounds.second) { bounds = std::equal_range( d_angleType.begin() + (bounds.first - d_kAtomType.begin()), d_angleType.begin() + (bounds.second - d_kAtomType.begin()), angleType); if (bounds.first != bounds.second) { mmffAngleParams = &d_params[bounds.first - d_angleType.begin()]; } } } ++iter; } } #endif return mmffAngleParams; } MMFFAngleCollection(std::string mmffAngle = ""); #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP std::map>>> d_params; //!< the parameter 4D-map #else std::vector d_params; //!< the parameter vector std::vector d_iAtomType; //!< atom type vector for atom i std::vector d_jAtomType; //!< atom type vector for atom j std::vector d_kAtomType; //!< atom type vector for atom k std::vector d_angleType; //!< angle type vector for angle i-j-k #endif }; class RDKIT_FORCEFIELD_EXPORT MMFFStbnCollection { public: //! Looks up the parameters for a particular key and returns them. /*! \return a pointer to the MMFFStbn object, NULL on failure. */ const std::pair getMMFFStbnParams( const unsigned int stretchBendType, const unsigned int bondType1, const unsigned int bondType2, const unsigned int iAtomType, const unsigned int jAtomType, const unsigned int kAtomType) const { const MMFFStbn *mmffStbnParams = nullptr; bool swap = false; unsigned int canIAtomType = iAtomType; unsigned int canKAtomType = kAtomType; unsigned int canStretchBendType = stretchBendType; if (iAtomType > kAtomType) { canIAtomType = kAtomType; canKAtomType = iAtomType; swap = true; } else if (iAtomType == kAtomType) { swap = (bondType1 < bondType2); } #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP const auto res1 = d_params.find(canStretchBendType); if (res1 != d_params.end()) { const auto res2 = ((*res1).second).find(canIAtomType); if (res2 != ((*res1).second).end()) { const auto res3 = ((*res2).second).find(jAtomType); if (res3 != ((*res2).second).end()) { const auto res4 = ((*res3).second).find(canKAtomType); if (res4 != ((*res3).second).end()) { mmffStbnParams = &((*res4).second); } } } } #else auto jBounds = std::equal_range(d_jAtomType.begin(), d_jAtomType.end(), jAtomType); if (jBounds.first != jBounds.second) { auto bounds = std::equal_range( d_iAtomType.begin() + (jBounds.first - d_jAtomType.begin()), d_iAtomType.begin() + (jBounds.second - d_jAtomType.begin()), canIAtomType); if (bounds.first != bounds.second) { bounds = std::equal_range( d_kAtomType.begin() + (bounds.first - d_iAtomType.begin()), d_kAtomType.begin() + (bounds.second - d_iAtomType.begin()), canKAtomType); if (bounds.first != bounds.second) { bounds = std::equal_range( d_stretchBendType.begin() + (bounds.first - d_kAtomType.begin()), d_stretchBendType.begin() + (bounds.second - d_kAtomType.begin()), canStretchBendType); if (bounds.first != bounds.second) { mmffStbnParams = &d_params[bounds.first - d_stretchBendType.begin()]; } } } } #endif return std::make_pair(swap, mmffStbnParams); } MMFFStbnCollection(std::string mmffStbn = ""); #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP std::map>>> d_params; //!< the parameter 4D-map #else std::vector d_params; //!< the parameter vector std::vector d_iAtomType; //!< atom type vector for atom i std::vector d_jAtomType; //!< atom type vector for atom j std::vector d_kAtomType; //!< atom type vector for atom k std::vector d_stretchBendType; //!< stretch-bend type vector for angle i-j-k #endif }; class RDKIT_FORCEFIELD_EXPORT MMFFDfsbCollection { public: //! Looks up the parameters for a particular key and returns them. /*! \return a pointer to the MMFFStbn object, NULL on failure. */ const std::pair getMMFFDfsbParams( const unsigned int periodicTableRow1, const unsigned int periodicTableRow2, const unsigned int periodicTableRow3) const { const MMFFStbn *mmffDfsbParams = nullptr; bool swap = false; unsigned int canPeriodicTableRow1 = periodicTableRow1; unsigned int canPeriodicTableRow3 = periodicTableRow3; if (periodicTableRow1 > periodicTableRow3) { canPeriodicTableRow1 = periodicTableRow3; canPeriodicTableRow3 = periodicTableRow1; swap = true; } const auto res1 = d_params.find(canPeriodicTableRow1); if (res1 != d_params.end()) { const auto res2 = ((*res1).second).find(periodicTableRow2); if (res2 != ((*res1).second).end()) { const auto res3 = ((*res2).second).find(canPeriodicTableRow3); if (res3 != ((*res2).second).end()) { mmffDfsbParams = &((*res3).second); } } } return std::make_pair(swap, mmffDfsbParams); } MMFFDfsbCollection(std::string mmffDfsb = ""); std::map>> d_params; //!< the parameter 3D-map }; class RDKIT_FORCEFIELD_EXPORT MMFFOopCollection { public: //! Looks up the parameters for a particular key and returns them. /*! \return a pointer to the MMFFOop object, NULL on failure. */ const MMFFOop *operator()(const MMFFDefCollection *mmffDef, const unsigned int iAtomType, const unsigned int jAtomType, const unsigned int kAtomType, const unsigned int lAtomType) const { const MMFFOop *mmffOopParams = nullptr; unsigned int iter = 0; std::vector canIKLAtomType(3); // For out-of-plane bending ijk; I , where j is the central // atom [cf. eq. (511, the five-stage protocol 1-1-1; 1, 2-2-2; 2, // 3-2-3;3, 4-2-4;4, 5-2-5;5 is used. The final stage provides // wild-card defaults for all except the central atom. #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP while ((iter < 4) && (!mmffOopParams)) { canIKLAtomType[0] = (*mmffDef)(iAtomType)->eqLevel[iter]; unsigned int canJAtomType = jAtomType; canIKLAtomType[1] = (*mmffDef)(kAtomType)->eqLevel[iter]; canIKLAtomType[2] = (*mmffDef)(lAtomType)->eqLevel[iter]; std::sort(canIKLAtomType.begin(), canIKLAtomType.end()); const auto res1 = d_params.find(canIKLAtomType[0]); if (res1 != d_params.end()) { const auto res2 = ((*res1).second).find(canJAtomType); if (res2 != ((*res1).second).end()) { const auto res3 = ((*res2).second).find(canIKLAtomType[1]); if (res3 != ((*res2).second).end()) { const auto res4 = ((*res3).second).find(canIKLAtomType[2]); if (res4 != ((*res3).second).end()) { mmffOopParams = &((*res4).second); } } } } ++iter; } #else auto jBounds = std::equal_range(d_jAtomType.begin(), d_jAtomType.end(), jAtomType); if (jBounds.first != jBounds.second) { while ((iter < 4) && (!mmffOopParams)) { canIKLAtomType[0] = (*mmffDef)(iAtomType)->eqLevel[iter]; canIKLAtomType[1] = (*mmffDef)(kAtomType)->eqLevel[iter]; canIKLAtomType[2] = (*mmffDef)(lAtomType)->eqLevel[iter]; std::sort(canIKLAtomType.begin(), canIKLAtomType.end()); auto bounds = std::equal_range( d_iAtomType.begin() + (jBounds.first - d_jAtomType.begin()), d_iAtomType.begin() + (jBounds.second - d_jAtomType.begin()), canIKLAtomType[0]); if (bounds.first != bounds.second) { bounds = std::equal_range( d_kAtomType.begin() + (bounds.first - d_iAtomType.begin()), d_kAtomType.begin() + (bounds.second - d_iAtomType.begin()), canIKLAtomType[1]); if (bounds.first != bounds.second) { bounds = std::equal_range( d_lAtomType.begin() + (bounds.first - d_kAtomType.begin()), d_lAtomType.begin() + (bounds.second - d_kAtomType.begin()), canIKLAtomType[2]); if (bounds.first != bounds.second) { mmffOopParams = &d_params[bounds.first - d_lAtomType.begin()]; } } } ++iter; } } #endif return mmffOopParams; } MMFFOopCollection(const bool isMMFFs, std::string mmffOop = ""); #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP std::map>>> d_params; //!< the parameter 4D-map #else std::vector d_params; //!< the parameter vector std::vector d_iAtomType; //!< atom type vector for atom i std::vector d_jAtomType; //!< atom type vector for atom j std::vector d_kAtomType; //!< atom type vector for atom k std::vector d_lAtomType; //!< atom type vector for atom l #endif }; class RDKIT_FORCEFIELD_EXPORT MMFFTorCollection { public: //! Looks up the parameters for a particular key and returns them. /*! \return a pointer to the MMFFTor object, NULL on failure. */ const std::pair getMMFFTorParams( const MMFFDefCollection *mmffDef, const std::pair torType, const unsigned int iAtomType, const unsigned int jAtomType, const unsigned int kAtomType, const unsigned int lAtomType) const { const MMFFTor *mmffTorParams = nullptr; unsigned int iter = 0; unsigned int iWildCard = 0; unsigned int lWildCard = 0; unsigned int canTorType = torType.first; unsigned int maxIter = 5; // For i-j-k-2 torsion interactions, a five-stage // process based on level combinations 1-1-1-1, 2-2-2-2, // 3-2-2-5, 5-2-2-3, and 5-2-2-5 is used, where stages 3 // and 4 correspond to "half-default" or "half-wild-card" entries. #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP #else #endif while (((iter < maxIter) && ((!mmffTorParams) || (maxIter == 4))) || ((iter == 4) && (torType.first == 5) && torType.second)) { // The rule of setting the torsion type to the value it had // before being set to 5 as a last resort in case parameters // could not be found is not mentioned in MMFF.IV; it was // empirically discovered due to a number of tests in the // MMFF validation suite otherwise failing if ((maxIter == 5) && (iter == 4)) { maxIter = 4; iter = 0; canTorType = torType.second; } iWildCard = iter; lWildCard = iter; if (iter == 1) { iWildCard = 1; lWildCard = 3; } else if (iter == 2) { iWildCard = 3; lWildCard = 1; } unsigned int canIAtomType = (*mmffDef)(iAtomType)->eqLevel[iWildCard]; unsigned int canJAtomType = jAtomType; unsigned int canKAtomType = kAtomType; unsigned int canLAtomType = (*mmffDef)(lAtomType)->eqLevel[lWildCard]; if (canJAtomType > canKAtomType) { unsigned int temp = canKAtomType; canKAtomType = canJAtomType; canJAtomType = temp; temp = canLAtomType; canLAtomType = canIAtomType; canIAtomType = temp; } else if ((canJAtomType == canKAtomType) && (canIAtomType > canLAtomType)) { unsigned int temp = canLAtomType; canLAtomType = canIAtomType; canIAtomType = temp; } #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP const auto res1 = d_params.find(canTorType); if (res1 != d_params.end()) { const auto res2 = ((*res1).second).find(canIAtomType); if (res2 != ((*res1).second).end()) { const auto res3 = ((*res2).second).find(canJAtomType); if (res3 != ((*res2).second).end()) { const auto res4 = ((*res3).second).find(canKAtomType); if (res4 != ((*res3).second).end()) { const auto res5 = ((*res4).second).find(canLAtomType); if (res5 != ((*res4).second).end()) { mmffTorParams = &((*res5).second); if (maxIter == 4) { break; } } } } } } #else auto jBounds = std::equal_range(d_jAtomType.begin(), d_jAtomType.end(), canJAtomType); if (jBounds.first != jBounds.second) { auto bounds = std::equal_range( d_kAtomType.begin() + (jBounds.first - d_jAtomType.begin()), d_kAtomType.begin() + (jBounds.second - d_jAtomType.begin()), canKAtomType); if (bounds.first != bounds.second) { bounds = std::equal_range( d_iAtomType.begin() + (bounds.first - d_kAtomType.begin()), d_iAtomType.begin() + (bounds.second - d_kAtomType.begin()), canIAtomType); if (bounds.first != bounds.second) { bounds = std::equal_range( d_lAtomType.begin() + (bounds.first - d_iAtomType.begin()), d_lAtomType.begin() + (bounds.second - d_iAtomType.begin()), canLAtomType); if (bounds.first != bounds.second) { bounds = std::equal_range( d_torType.begin() + (bounds.first - d_lAtomType.begin()), d_torType.begin() + (bounds.second - d_lAtomType.begin()), canTorType); if (bounds.first != bounds.second) { mmffTorParams = &d_params[bounds.first - d_torType.begin()]; if (maxIter == 4) { break; } } } } } } #endif ++iter; } return std::make_pair(canTorType, mmffTorParams); } MMFFTorCollection(const bool isMMFFs, std::string mmffTor = ""); #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP std::map< const unsigned int, std::map< const unsigned int, std::map>>>> d_params; //!< the parameter 5D-map #else std::vector d_params; //!< the parameter vector std::vector d_iAtomType; //!< atom type vector for atom i std::vector d_jAtomType; //!< atom type vector for atom j std::vector d_kAtomType; //!< atom type vector for atom k std::vector d_lAtomType; //!< atom type vector for atom l std::vector d_torType; //!< torsion type vector for angle i-j-k-l #endif }; class RDKIT_FORCEFIELD_EXPORT MMFFVdWCollection { public: //! gets a pointer to the singleton MMFFVdWCollection double power; double B; double Beta; double DARAD; double DAEPS; //! Looks up the parameters for a particular key and returns them. /*! \return a pointer to the MMFFVdW object, NULL on failure. */ const MMFFVdW *operator()(const unsigned int atomType) const { #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP const auto res = d_params.find(atomType); return (res != d_params.end() ? &((*res).second) : NULL); #else auto bounds = std::equal_range(d_atomType.begin(), d_atomType.end(), atomType); return ((bounds.first != bounds.second) ? &d_params[bounds.first - d_atomType.begin()] : nullptr); #endif } MMFFVdWCollection(std::string mmffVdW = ""); #ifdef RDKIT_MMFF_PARAMS_USE_STD_MAP std::map d_params; //!< the parameter map #else std::vector d_params; //!< the parameter vector std::vector d_atomType; //!< atom type vector #endif }; } // namespace MMFF } // namespace ForceFields #endif