diff --git a/Code/DistGeom/DistGeomUtils.cpp b/Code/DistGeom/DistGeomUtils.cpp index 59ee3a4b0..4e27d08f4 100644 --- a/Code/DistGeom/DistGeomUtils.cpp +++ b/Code/DistGeom/DistGeomUtils.cpp @@ -25,6 +25,7 @@ #include #include #include +#include namespace DistGeom { const double EIGVAL_TOL = 0.001; @@ -363,6 +364,25 @@ ForceFields::ForceField *construct3DForceField( return field; } // construct3DForceField +ForceFields::ForceField *construct3DForceField( + const BoundsMatrix &mmat, RDGeom::Point3DPtrVect &positions, + const ForceFields::CrystalFF::CrystalFFDetails &etkdgDetails, + const std::map, double> &CPCI) { + auto *field = construct3DForceField(mmat, positions, etkdgDetails); + + bool is1_4 = false; + // double dielConst = 1.0; + boost::uint8_t dielModel = 1; + for (const auto &charge : CPCI) { + auto *contrib = new ForceFields::MMFF::EleContrib( + field, charge.first.first, charge.first.second, charge.second, + dielModel, is1_4); + field->contribs().push_back(ForceFields::ContribPtr(contrib)); + } + + return field; +} + ForceFields::ForceField *constructPlain3DForceField( const BoundsMatrix &mmat, RDGeom::Point3DPtrVect &positions, const ForceFields::CrystalFF::CrystalFFDetails &etkdgDetails) { diff --git a/Code/DistGeom/DistGeomUtils.h b/Code/DistGeom/DistGeomUtils.h index dedeb86ea..cd49c8053 100644 --- a/Code/DistGeom/DistGeomUtils.h +++ b/Code/DistGeom/DistGeomUtils.h @@ -138,6 +138,24 @@ RDKIT_DISTGEOMETRY_EXPORT ForceFields::ForceField *construct3DForceField( const BoundsMatrix &mmat, RDGeom::Point3DPtrVect &positions, const ForceFields::CrystalFF::CrystalFFDetails &etkdgDetails); //! Force field with experimental torsion angle preferences and 1-2/1-3 distance +// constraints, as well as atom pairwise Columbic interactions +/*! + + \param mmat Distance bounds matrix + \param positions A vector of pointers to 3D Points to write out the + resulting coordinates + \param etkdgDetails Contains information about the ETKDG force field + \param CPCI Contains which atom pair(s) have what strength of + attractive/repulsive electrostatic interaction(s) + + NOTE: the caller is responsible for deleting this force field. + +*/ +RDKIT_DISTGEOMETRY_EXPORT ForceFields::ForceField *construct3DForceField( + const BoundsMatrix &mmat, RDGeom::Point3DPtrVect &positions, + const ForceFields::CrystalFF::CrystalFFDetails &etkdgDetails, + const std::map, double> &CPCI); +//! Force field with experimental torsion angle preferences and 1-2/1-3 distance // constraints /*! diff --git a/Code/GraphMol/DistGeomHelpers/BoundsMatrixBuilder.cpp b/Code/GraphMol/DistGeomHelpers/BoundsMatrixBuilder.cpp index e215892df..5acbd5ced 100644 --- a/Code/GraphMol/DistGeomHelpers/BoundsMatrixBuilder.cpp +++ b/Code/GraphMol/DistGeomHelpers/BoundsMatrixBuilder.cpp @@ -31,6 +31,7 @@ const double GEN_DIST_TOL = 0.06; // a general distance tolerance const double DIST15_TOL = 0.08; const double VDW_SCALE_15 = 0.7; const double MAX_UPPER = 1000.0; +static const double minMacrocycleRingSize = 9; #include namespace RDKit { @@ -91,12 +92,10 @@ class ComputedData { /*! These are mostly bond lengths obtained from UFF parameters and then adjusted by a small tolerance to set the upper and lower limits - \param mol The molecule of interest \param mmat Bounds matrix to which the bounds are written \param accumData Used to store the data that have been calculated so far about the molecule - */ void set12Bounds(const ROMol &mol, DistGeom::BoundsMatPtr mmat, ComputedData &accumData); @@ -107,12 +106,10 @@ void set12Bounds(const ROMol &mol, DistGeom::BoundsMatPtr mmat, cases here, in particular for 3, 4, and 5 membered rings. Special attention is also paid to fused ring ring systems, when setting bounds on atoms that have an atom between that is shared by multiple rings. - \param mol Molecule of interest \param mmat Bounds matrix to which the bounds are written \param accumData Used to store the data that have been calculated so far about the molecule - Procedure All 1-3 distances within all simple rings are first dealt with, while keeping track of @@ -133,12 +130,10 @@ void set13Bounds(const ROMol &mol, DistGeom::BoundsMatPtr mmat, and max. torsion angles. The special cases deal with ring systems, double bonds with cis-trans specifications, and a few special sub-structures - \param mol Molecule of interest \param mmat Bounds matrix to which the bounds are written \param accumData Used to store the data that have been calculated so far about the molecule - Procedure As in the case of 1-3 distances 1-4 distance that are part of simple rings are first dealt with. The remaining 1-4 cases are dealt with while paying @@ -146,12 +141,11 @@ void set13Bounds(const ROMol &mol, DistGeom::BoundsMatPtr mmat, to the special cases. */ void set14Bounds(const ROMol &mol, DistGeom::BoundsMatPtr mmat, - ComputedData &accumData); + ComputedData &accumData, bool useMacrocycle14config = false); //! Set 1-5 distance bounds for atoms in a molecule /*! This is an optional call that recognizes a variety of special cases. - \param mol Molecule of interest \param mmat Bounds matrix to which the bounds are written \param accumData Used to store the data that have been calculated so far @@ -164,7 +158,6 @@ void set15Bounds(const ROMol &mol, DistGeom::BoundsMatPtr mmat, // by //! other bounds (1-2, 1-3, 1-4, or 1-5) /*! - \param mol Molecule of interest \param mmat Bounds matrix to which the bounds are written \param useTopolScaling If true scale the sum of the vdW radii while setting @@ -175,8 +168,8 @@ void set15Bounds(const ROMol &mol, DistGeom::BoundsMatPtr mmat, */ void setLowerBoundVDW(const ROMol &mol, DistGeom::BoundsMatPtr mmat, bool useTopolScaling = true); -} -} +} // namespace DGeomHelpers +} // namespace RDKit namespace RDKit { namespace DGeomHelpers { @@ -288,7 +281,7 @@ bool isLargerSP2Atom(const Atom *atom) { return atom->getAtomicNum() > 13 && atom->getHybridization() == Atom::SP2 && atom->getOwningMol().getRingInfo()->numAtomRings(atom->getIdx()); } -} +} // namespace void _set13BoundsHelper(unsigned int aid1, unsigned int aid, unsigned int aid3, double angle, const ComputedData &accumData, DistGeom::BoundsMatPtr mmat, const ROMol &mol) { @@ -443,12 +436,12 @@ void set13Bounds(const ROMol &mol, DistGeom::BoundsMatPtr mmat, // system while (beg1 != end1) { - const Bond* bnd1 = mol[*beg1]; + const Bond *bnd1 = mol[*beg1]; bid1 = bnd1->getIdx(); aid1 = bnd1->getOtherAtomIdx(aid2); boost::tie(beg2, end2) = mol.getAtomBonds(atom); while (beg2 != beg1) { - const Bond* bnd2 = mol[*beg2]; + const Bond *bnd2 = mol[*beg2]; bid2 = bnd2->getIdx(); // invar = firstThousandPrimes[bid1]*firstThousandPrimes[bid2]; if (accumData.bondAngles->getVal(bid1, bid2) < 0.0) { @@ -499,12 +492,12 @@ void set13Bounds(const ROMol &mol, DistGeom::BoundsMatPtr mmat, } else if (visited[aid2] == 0) { // non-ring atoms - we will simply use angles based on hybridization while (beg1 != end1) { - const Bond* bnd1 = mol[*beg1]; + const Bond *bnd1 = mol[*beg1]; bid1 = bnd1->getIdx(); aid1 = bnd1->getOtherAtomIdx(aid2); boost::tie(beg2, end2) = mol.getAtomBonds(atom); while (beg2 != beg1) { - const Bond* bnd2 = mol[*beg2]; + const Bond *bnd2 = mol[*beg2]; bid2 = bnd2->getIdx(); if (ahyb == Atom::SP) { angle = M_PI; @@ -824,6 +817,62 @@ bool _checkAmideEster14(const Bond *bnd1, const Bond *bnd3, const Atom *atm1, return false; } +bool _checkMacrocycleAmideEster14(const ROMol &mol, const Bond *bnd1, + const Bond *bnd3, const Atom *atm1, + const Atom *atm2, const Atom *atm3, + const Atom *atm4) { + // This is a re-write of `_checkAmideEster14` with more explicit logic on + // the checks It is interesting that we find with this function we get + // better macrocycle sampling than `_checkAmideEster14` + unsigned int a1Num = atm1->getAtomicNum(); + unsigned int a2Num = atm2->getAtomicNum(); + unsigned int a3Num = atm3->getAtomicNum(); + unsigned int a4Num = atm4->getAtomicNum(); + + if (a3Num != 6) return false; + + ROMol::ADJ_ITER nbrIdx, endNbrs; + if (a2Num == 7 || a2Num == 8) { + if (mol.getAtomDegree(atm2) == 3 && mol.getAtomDegree(atm3) == 3) { + { + const Atom *res; + const Bond *resbnd; + boost::tie(nbrIdx, endNbrs) = mol.getAtomNeighbors(atm2); + while (nbrIdx != endNbrs) { + if (*nbrIdx != atm1->getIdx() && *nbrIdx != atm3->getIdx()) { + res = mol.getAtomWithIdx(*nbrIdx); + resbnd = mol.getBondBetweenAtoms(atm2->getIdx(), *nbrIdx); + break; + } + ++nbrIdx; + } + if ((res->getAtomicNum() != 6 && res->getAtomicNum() != 1) || + resbnd->getBondType() != Bond::SINGLE) + return false; + } + + { + const Atom *res; + const Bond *resbnd; + boost::tie(nbrIdx, endNbrs) = mol.getAtomNeighbors(atm3); + while (nbrIdx != endNbrs) { + if (*nbrIdx != atm2->getIdx() && *nbrIdx != atm4->getIdx()) { + res = mol.getAtomWithIdx(*nbrIdx); + resbnd = mol.getBondBetweenAtoms(atm3->getIdx(), *nbrIdx); + break; + } + ++nbrIdx; + } + if (res->getAtomicNum() != 8 || resbnd->getBondType() != Bond::DOUBLE) + return false; + } + + return true; + } + } + return false; +} + bool _isCarbonyl(const ROMol &mol, const Atom *at) { PRECONDITION(at, "bad atom"); if (at->getAtomicNum() == 6 && at->getDegree() > 2) { @@ -1027,21 +1076,21 @@ void _setChain14Bounds(const ROMol &mol, const Bond *bnd1, const Bond *bnd2, atm4)) || (_checkAmideEster15(mol, bnd3, bnd1, atm4, atm3, atm2, atm1))) { -// it's an amide or ester. -// -// 4 <- 4 is the O -// | <- That's the double bond -// 1 3 -// \ / \ T.S.I.Left Blank -// 2 5 <- 2 is oxygen or nitrogen -// -// we set the 1-4 contact above. + // it's an amide or ester. + // + // 4 <- 4 is the O + // | <- That's the double bond + // 1 3 + // \ / \ T.S.I.Left Blank + // 2 5 <- 2 is oxygen or nitrogen + // + // we set the 1-4 contact above. -// If we're going to have a hope of getting good geometries -// out of here we need to set some reasonably smart bounds between 1 -// and 5 (ref Issue355): + // If we're going to have a hope of getting good geometries + // out of here we need to set some reasonably smart bounds between 1 + // and 5 (ref Issue355): -// NOTE THAT WE REVERSE THE ORDER HERE: + // NOTE THAT WE REVERSE THE ORDER HERE: #ifdef FORCE_TRANS_AMIDES // amide is trans, we're cis: @@ -1115,8 +1164,201 @@ void _record14Path(const ROMol &mol, unsigned int bid1, unsigned int bid2, accumData.paths14.push_back(path14); } +void _setMacrocycle14Bounds(const ROMol &mol, const Bond *bnd1, + const Bond *bnd2, const Bond *bnd3, + ComputedData &accumData, + DistGeom::BoundsMatPtr mmat, double *dmat) { + // This is adapted from `_setChain14Bounds`, with changes on how trans amide + // is handled + RDUNUSED_PARAM(dmat); + PRECONDITION(bnd1, ""); + PRECONDITION(bnd2, ""); + PRECONDITION(bnd3, ""); + unsigned int bid1, bid2, bid3; + bid1 = bnd1->getIdx(); + bid2 = bnd2->getIdx(); + bid3 = bnd3->getIdx(); + const Atom *atm2 = mol.getAtomWithIdx(accumData.bondAdj->getVal(bid1, bid2)); + PRECONDITION(atm2, ""); + const Atom *atm3 = mol.getAtomWithIdx(accumData.bondAdj->getVal(bid2, bid3)); + PRECONDITION(atm3, ""); + + unsigned int aid1 = bnd1->getOtherAtomIdx(atm2->getIdx()); + unsigned int aid4 = bnd3->getOtherAtomIdx(atm3->getIdx()); + + const Atom *atm1 = mol.getAtomWithIdx(aid1); + const Atom *atm4 = mol.getAtomWithIdx(aid4); + + double bl1 = accumData.bondLengths[bid1]; + double bl2 = accumData.bondLengths[bid2]; + double bl3 = accumData.bondLengths[bid3]; + + double ba12 = accumData.bondAngles->getVal(bid1, bid2); + double ba23 = accumData.bondAngles->getVal(bid2, bid3); + CHECK_INVARIANT(ba12 > 0.0, ""); + CHECK_INVARIANT(ba23 > 0.0, ""); + bool setTheBound = true; + double dl = 0.0, du = 0.0; + + // if the middle bond is double + Path14Configuration path14; + path14.bid1 = bid1; + path14.bid2 = bid2; + path14.bid3 = bid3; + unsigned int nb = mol.getNumBonds(); + switch (bnd2->getBondType()) { + case Bond::DOUBLE: + // if any of the other bonds are double - the torsion angle is zero + // this is CC=C=C situation + if ((bnd1->getBondType() == Bond::DOUBLE) || + (bnd3->getBondType() == Bond::DOUBLE)) { + dl = RDGeom::compute14DistCis(bl1, bl2, bl3, ba12, ba23) - GEN_DIST_TOL; + du = dl + 2 * GEN_DIST_TOL; + path14.type = Path14Configuration::CIS; + accumData.cisPaths[bid1 * nb * nb + bid2 * nb + bid3] = 1; + accumData.cisPaths[bid3 * nb * nb + bid2 * nb + bid1] = 1; + // BOOST_LOG(rdDebugLog) << "Special 5 " << aid1 << " " << aid4 << + // "\n"; + } else if (bnd2->getStereo() > Bond::STEREOANY) { + Bond::BondStereo stype = _getAtomStereo(bnd2, aid1, aid4); + if (stype == Bond::STEREOZ || stype == Bond::STEREOCIS) { + dl = RDGeom::compute14DistCis(bl1, bl2, bl3, ba12, ba23) - + GEN_DIST_TOL; + du = dl + 2 * GEN_DIST_TOL; + path14.type = Path14Configuration::CIS; + // BOOST_LOG(rdDebugLog) << "Special 6 " << aid1 << " " << aid4 << + // "\n"; + accumData.cisPaths[bid1 * nb * nb + bid2 * nb + bid3] = 1; + accumData.cisPaths[bid3 * nb * nb + bid2 * nb + bid1] = 1; + } else { + // BOOST_LOG(rdDebugLog) << "Special 7 " << aid1 << " " << aid4 << + // "\n"; + du = RDGeom::compute14DistTrans(bl1, bl2, bl3, ba12, ba23); + dl = du; + dl -= GEN_DIST_TOL; + du += GEN_DIST_TOL; + path14.type = Path14Configuration::TRANS; + accumData.transPaths[bid1 * nb * nb + bid2 * nb + bid3] = 1; + accumData.transPaths[bid3 * nb * nb + bid2 * nb + bid1] = 1; + } + } else { + // double bond with no stereo setting can be 0 or 180 + dl = RDGeom::compute14DistCis(bl1, bl2, bl3, ba12, ba23); + du = RDGeom::compute14DistTrans(bl1, bl2, bl3, ba12, ba23); + if (fabs(du - dl) < DIST12_DELTA) { + dl -= GEN_DIST_TOL; + du += GEN_DIST_TOL; + } + path14.type = Path14Configuration::OTHER; + } + break; + case Bond::SINGLE: + +// Commenting out the following if block to fix issue 235, we may want to later +// provide +// the user with an option to invoke this special case +#if 0 + if ( (_checkNhChChNh(atm1, atm2, atm3, atm4)) || + ((bnd1->getBondType() == Bond::DOUBLE) && (bnd3->getBondType() == Bond::DOUBLE) ) ) { + // this is either + // 1. [!#1]~$ch!@$ch~[!#1] situation where ch = [CH2,NX3H1,OX2] or + // 2. *=*-*=* situation + // Both case cases we use 180 deg for torsion + du = RDGeom::compute14DistTrans(bl1, bl2, bl3, ba12, ba23); + dl = du; + dl -= GEN_DIST_TOL; + du += GEN_DIST_TOL; + path14.type = Path14Configuration::TRANS; + transPaths[bid1*nb*nb + bid2*nb + bid3] = 1; + transPaths[bid3*nb*nb + bid2*nb + bid1] = 1; + } else +#endif + + if ((atm2->getAtomicNum() == 16) && (atm3->getAtomicNum() == 16)) { + // this is *S-S* situation + // FIX: this cannot be right is sulfur has more than two coordinated + // the torsion angle is 90 deg + dl = RDGeom::compute14Dist3D(bl1, bl2, bl3, ba12, ba23, M_PI / 2) - + GEN_DIST_TOL; + du = dl + 2 * GEN_DIST_TOL; + path14.type = Path14Configuration::OTHER; + // BOOST_LOG(rdDebugLog) << "Special 9 " << aid1 << " " << aid4 << + // "\n"; + } else if ((_checkMacrocycleAmideEster14(mol, bnd1, bnd3, atm1, atm2, + atm3, atm4)) || + (_checkMacrocycleAmideEster14(mol, bnd3, bnd1, atm4, atm3, + atm2, atm1))) { + dl = + RDGeom::compute14DistTrans(bl1, bl2, bl3, ba12, ba23) + + 0.1; // we saw that the currently defined max distance for trans is + // still a bit too short, thus we add an additional 0.1, which + // is the max that works without triangular smoothing error + path14.type = Path14Configuration::TRANS; + accumData.transPaths[bid1 * nb * nb + bid2 * nb + bid3] = 1; + accumData.transPaths[bid3 * nb * nb + bid2 * nb + bid1] = 1; + + du = dl; + dl -= GEN_DIST_TOL; + du += GEN_DIST_TOL; + + // BOOST_LOG(rdDebugLog) << " amide: " << aid1 << " " << aid4 << ": " + // << dl << "->" << du << "\n"; + } else if ((_checkAmideEster15(mol, bnd1, bnd3, atm1, atm2, atm3, + atm4)) || + (_checkAmideEster15(mol, bnd3, bnd1, atm4, atm3, atm2, + atm1))) { +#ifdef FORCE_TRANS_AMIDES + // amide is trans, we're cis: + dl = RDGeom::compute14DistCis(bl1, bl2, bl3, ba12, ba23); + path14.type = Path14Configuration::CIS; + accumData.cisPaths[bid1 * nb * nb + bid2 * nb + bid3] = 1; + accumData.cisPaths[bid3 * nb * nb + bid2 * nb + bid1] = 1; +#else + // amide is cis, we're trans: + if (atm2->getAtomicNum() == 7 && atm2->getDegree() == 3 && + atm1->getAtomicNum() == 1 && atm2->getTotalNumHs(true) == 1) { + // secondary amide, this is the H + setTheBound = false; + } else { + dl = RDGeom::compute14DistTrans(bl1, bl2, bl3, ba12, ba23); + path14.type = Path14Configuration::TRANS; + accumData.transPaths[bid1 * nb * nb + bid2 * nb + bid3] = 1; + accumData.transPaths[bid3 * nb * nb + bid2 * nb + bid1] = 1; + } +#endif + du = dl; + dl -= GEN_DIST_TOL; + du += GEN_DIST_TOL; + // BOOST_LOG(rdDebugLog) << " amide neighbor: " << aid1 << " " << + // aid4 << ": " << dl << "->" << du << "\n"; + } else { + dl = RDGeom::compute14DistCis(bl1, bl2, bl3, ba12, ba23); + du = RDGeom::compute14DistTrans(bl1, bl2, bl3, ba12, ba23); + path14.type = Path14Configuration::OTHER; + } + break; + default: + // BOOST_LOG(rdDebugLog) << "Special 12 " << aid1 << " " << aid4 << + // "\n"; + dl = RDGeom::compute14DistCis(bl1, bl2, bl3, ba12, ba23); + du = RDGeom::compute14DistTrans(bl1, bl2, bl3, ba12, ba23); + + path14.type = Path14Configuration::OTHER; + } + if (setTheBound) { + if (fabs(du - dl) < DIST12_DELTA) { + dl -= GEN_DIST_TOL; + du += GEN_DIST_TOL; + } + // std::cerr<<"2: "<numRows(); CHECK_INVARIANT(npt == mol.getNumAtoms(), "Wrong size metric matrix"); @@ -1157,9 +1399,15 @@ void set14Bounds(const ROMol &mol, DistGeom::BoundsMatPtr mmat, donePaths[id2] = 1; if (rSize > 5) { - _setInRing14Bounds(mol, mol.getBondWithIdx(bid1), - mol.getBondWithIdx(bid2), mol.getBondWithIdx(bid3), - accumData, mmat, distMatrix, rSize); + if (useMacrocycle14config && rSize >= minMacrocycleRingSize) { + _setMacrocycle14Bounds( + mol, mol.getBondWithIdx(bid1), mol.getBondWithIdx(bid2), + mol.getBondWithIdx(bid3), accumData, mmat, distMatrix); + } else { + _setInRing14Bounds(mol, mol.getBondWithIdx(bid1), + mol.getBondWithIdx(bid2), mol.getBondWithIdx(bid3), + accumData, mmat, distMatrix, rSize); + } } else { _record14Path(mol, bid1, bid2, bid3, accumData); } @@ -1195,6 +1443,7 @@ void set14Bounds(const ROMol &mol, DistGeom::BoundsMatPtr mmat, // either (bid1, bid2) or (bid2, bid3) are in the // same ring (note all three cannot be in the same // ring; we dealt with that before) + _setTwoInSameRing14Bounds(mol, bnd1, (*bi), bnd3, accumData, mmat, distMatrix); } else if (((rinfo->numBondRings(bid1) > 0) && @@ -1215,6 +1464,7 @@ void set14Bounds(const ROMol &mol, DistGeom::BoundsMatPtr mmat, // the middle bond is a ring bond and the other // two do not belong to the same ring or are // non-ring bonds + _setShareRingBond14Bounds(mol, bnd1, (*bi), bnd3, accumData, mmat, distMatrix); } else { @@ -1249,7 +1499,8 @@ void initBoundsMat(DistGeom::BoundsMatPtr mmat, double defaultMin, }; void setTopolBounds(const ROMol &mol, DistGeom::BoundsMatPtr mmat, - bool set15bounds, bool scaleVDW) { + bool set15bounds, bool scaleVDW, + bool useMacrocycle14config) { PRECONDITION(mmat.get(), "bad pointer"); unsigned int nb = mol.getNumBonds(); unsigned int na = mol.getNumAtoms(); @@ -1263,7 +1514,7 @@ void setTopolBounds(const ROMol &mol, DistGeom::BoundsMatPtr mmat, set12Bounds(mol, mmat, accumData); set13Bounds(mol, mmat, accumData); - set14Bounds(mol, mmat, accumData, distMatrix); + set14Bounds(mol, mmat, accumData, distMatrix, useMacrocycle14config); if (set15bounds) { set15Bounds(mol, mmat, accumData, distMatrix); @@ -1273,25 +1524,27 @@ void setTopolBounds(const ROMol &mol, DistGeom::BoundsMatPtr mmat, } void collectBondsAndAngles(const ROMol &mol, - std::vector > &bonds, - std::vector > &angles){ + std::vector> &bonds, + std::vector> &angles) { bonds.resize(0); angles.resize(0); bonds.reserve(mol.getNumBonds()); for (const auto bondi : mol.bonds()) { - bonds.push_back(std::make_pair(bondi->getBeginAtomIdx(), bondi->getEndAtomIdx())); + bonds.push_back( + std::make_pair(bondi->getBeginAtomIdx(), bondi->getEndAtomIdx())); - for(unsigned int j=bondi->getIdx()+1;jgetIdx() + 1; j < mol.getNumBonds(); ++j) { const Bond *bondj = mol.getBondWithIdx(j); int aid11 = bondi->getBeginAtomIdx(); int aid12 = bondi->getEndAtomIdx(); int aid21 = bondj->getBeginAtomIdx(); int aid22 = bondj->getEndAtomIdx(); - if( aid11!=aid21 && aid11!=aid22 && aid12!=aid21 && aid12!=aid22 ){ + if (aid11 != aid21 && aid11 != aid22 && aid12 != aid21 && + aid12 != aid22) { continue; } std::vector tmp(4, - 0); // elements: aid1, aid2, flag for triple bonds + 0); // elements: aid1, aid2, flag for triple bonds if ((bondi->getBondType() == Bond::TRIPLE) || (bondj->getBondType() == Bond::TRIPLE)) { tmp[3] = 1; @@ -1320,9 +1573,9 @@ void collectBondsAndAngles(const ROMol &mol, } void setTopolBounds(const ROMol &mol, DistGeom::BoundsMatPtr mmat, - std::vector > &bonds, - std::vector > &angles, bool set15bounds, - bool scaleVDW) { + std::vector> &bonds, + std::vector> &angles, bool set15bounds, + bool scaleVDW, bool useMacrocycle14config) { PRECONDITION(mmat.get(), "bad pointer"); bonds.clear(); angles.clear(); @@ -1337,7 +1590,7 @@ void setTopolBounds(const ROMol &mol, DistGeom::BoundsMatPtr mmat, set12Bounds(mol, mmat, accumData); set13Bounds(mol, mmat, accumData); - set14Bounds(mol, mmat, accumData, distMatrix); + set14Bounds(mol, mmat, accumData, distMatrix, useMacrocycle14config); if (set15bounds) { set15Bounds(mol, mmat, accumData, distMatrix); @@ -1345,7 +1598,7 @@ void setTopolBounds(const ROMol &mol, DistGeom::BoundsMatPtr mmat, setLowerBoundVDW(mol, mmat, scaleVDW, distMatrix); - collectBondsAndAngles(mol,bonds,angles); + collectBondsAndAngles(mol, bonds, angles); } // some helper functions to set 15 distances @@ -1398,12 +1651,9 @@ double _compute15DistsCisCis(double d1, double d2, double d3, double d4, four atoms are in cis configuration. The 15 limits are computed assuming the following configuration - - 1 4-5 \ / 2-3 - ARGUMENTS: d1 - distance between 1 and 2 d2 - distance between 2 and 3 @@ -1440,14 +1690,11 @@ double _compute15DistsCisTrans(double d1, double d2, double d3, double d4, the following configuration - 1 \ 2-3 \ 4-5 - - ARGUMENTS: d1 - distance between 1 and 2 d2 - distance between 2 and 3 @@ -1484,7 +1731,6 @@ double _compute15DistsTransTrans(double d1, double d2, double d3, double d4, the following configuration - 1 \ 2-3 @@ -1654,5 +1900,5 @@ void set15Bounds(const ROMol &mol, DistGeom::BoundsMatPtr mmat, distMatrix); } } -} -} +} // namespace DGeomHelpers +} // namespace RDKit diff --git a/Code/GraphMol/DistGeomHelpers/BoundsMatrixBuilder.h b/Code/GraphMol/DistGeomHelpers/BoundsMatrixBuilder.h index 5eb31a601..3ee8f6249 100644 --- a/Code/GraphMol/DistGeomHelpers/BoundsMatrixBuilder.h +++ b/Code/GraphMol/DistGeomHelpers/BoundsMatrixBuilder.h @@ -21,7 +21,6 @@ namespace DGeomHelpers { \param mmat pointer to the bounds matrix to be altered \param defaultMin default value for the lower distance bounds \param defaultMax default value for the upper distance bounds - */ RDKIT_DISTGEOMHELPERS_EXPORT void initBoundsMat(DistGeom::BoundsMatrix *mmat, double defaultMin = 0.0, @@ -38,10 +37,8 @@ RDKIT_DISTGEOMHELPERS_EXPORT void initBoundsMat(DistGeom::BoundsMatPtr mmat, This consists of setting 1-2, 1-3 and 1-4 distance based on bond lengths, bond angles and torsion angle ranges. Optionally 1-5 bounds can also be set, in particular, for path that contain rigid 1-4 paths. - The final step involves setting lower bound to the sum of the vdW radii for the remaining atom pairs. - \param mol The molecule of interest \param mmat Bounds matrix to the bounds are written \param set15bounds If true try to set 1-5 bounds also based on topology @@ -50,17 +47,15 @@ RDKIT_DISTGEOMHELPERS_EXPORT void initBoundsMat(DistGeom::BoundsMatPtr mmat, so that a smaller value (0.7*(vdw1 + vdw2) ) is used for paths that are less five bonds apart. - - Note - For some strained systems the bounds matrix resulting from setting 1-5 bounds - may - fail triangle smoothing. In these cases it is recommended to back out and - recompute the bounds matrix with no 1-5 bounds and with vdW scaling. + \param useMacrocycle14config If 1-4 distances bound heuristics for + macrocycles is used Note For some strained systems the bounds matrix + resulting from setting 1-5 bounds may fail triangle smoothing. In these cases + it is recommended to back out and recompute the bounds matrix with no 1-5 + bounds and with vdW scaling. */ -RDKIT_DISTGEOMHELPERS_EXPORT void setTopolBounds(const ROMol &mol, - DistGeom::BoundsMatPtr mmat, - bool set15bounds = true, - bool scaleVDW = false); +RDKIT_DISTGEOMHELPERS_EXPORT void setTopolBounds( + const ROMol &mol, DistGeom::BoundsMatPtr mmat, bool set15bounds = true, + bool scaleVDW = false, bool useMacrocycle14config = false); /*! \overload for experimental torsion angle preferences */ @@ -68,12 +63,11 @@ RDKIT_DISTGEOMHELPERS_EXPORT void setTopolBounds( const ROMol &mol, DistGeom::BoundsMatPtr mmat, std::vector> &bonds, std::vector> &angles, bool set15bounds = true, - bool scaleVDW = false); + bool scaleVDW = false, bool useMacrocycle14config = false); //! generate the vectors of bonds and angles used by (ET)KDG RDKIT_DISTGEOMHELPERS_EXPORT void collectBondsAndAngles( - const ROMol &mol, - std::vector> &bonds, + const ROMol &mol, std::vector> &bonds, std::vector> &angles); } // namespace DGeomHelpers diff --git a/Code/GraphMol/DistGeomHelpers/Embedder.cpp b/Code/GraphMol/DistGeomHelpers/Embedder.cpp index b17292789..9d617e0d2 100644 --- a/Code/GraphMol/DistGeomHelpers/Embedder.cpp +++ b/Code/GraphMol/DistGeomHelpers/Embedder.cpp @@ -74,7 +74,13 @@ const EmbedParameters KDG(0, // maxIterations 5.0, // basinThresh -1.0, // pruneRmsThresh true, // onlyHeavyAtomsForRMS - 1 // ETversion + 1, // ETversion + nullptr, // boundsMat + true, // embedFragmentsSeparately + false, // useSmallRingTorsions + false, // useMacrocycleTorsions + false, // useMacrocycle14config + nullptr // CPCI ); //! Parameters corresponding to Sereina Riniker's ETDG approach @@ -96,7 +102,13 @@ const EmbedParameters ETDG(0, // maxIterations 5.0, // basinThresh -1.0, // pruneRmsThresh true, // onlyHeavyAtomsForRMS - 1 // ETversion + 1, // ETversion + nullptr, // boundsMat + true, // embedFragmentsSeparately + false, // useSmallRingTorsions + false, // useMacrocycleTorsions + false, // useMacrocycle14config + nullptr // CPCI ); //! Parameters corresponding to Sereina Riniker's ETKDG approach const EmbedParameters ETKDG(0, // maxIterations @@ -117,7 +129,13 @@ const EmbedParameters ETKDG(0, // maxIterations 5.0, // basinThresh -1.0, // pruneRmsThresh true, // onlyHeavyAtomsForRMS - 1 // ETversion + 1, // ETversion + nullptr, // boundsMat + true, // embedFragmentsSeparately + false, // useSmallRingTorsions + false, // useMacrocycleTorsions + false, // useMacrocycle14config + nullptr // CPCI ); //! Parameters corresponding to Sereina Riniker's ETKDG approach - version 2 @@ -139,7 +157,71 @@ const EmbedParameters ETKDGv2(0, // maxIterations 5.0, // basinThresh -1.0, // pruneRmsThresh true, // onlyHeavyAtomsForRMS - 2 // ETversion + 2, // ETversion + nullptr, // boundsMat + true, // embedFragmentsSeparately + false, // useSmallRingTorsions + false, // useMacrocycleTorsions + false, // useMacrocycle14config + nullptr // CPCI +); + +//! Parameters corresponding improved ETKDG by Wang, Witek, Landrum and Riniker +//! (10.1021/acs.jcim.0c00025) - the macrocycle part +const EmbedParameters ETKDGv3(0, // maxIterations + 1, // numThreads + -1, // randomSeed + true, // clearConfs + false, // useRandomCoords + 2.0, // boxSizeMult + true, // randNegEig + 1, // numZeroFail + nullptr, // coordMap + 1e-3, // optimizerForceTol + false, // ignoreSmoothingFailures + true, // enforceChirality + true, // useExpTorsionAnglePrefs + true, // useBasicKnowledge + false, // verbose + 5.0, // basinThresh + -1.0, // pruneRmsThresh + true, // onlyHeavyAtomsForRMS + 2, // ETversion + nullptr, // boundsMat + true, // embedFragmentsSeparately + false, // useSmallRingTorsions + true, // useMacrocycleTorsions + true, // useMacrocycle14config + nullptr // CPCI +); + +//! Parameters corresponding improved ETKDG by Wang, Witek, Landrum and Riniker +//! (10.1021/acs.jcim.0c00025) - the small ring part +const EmbedParameters srETKDGv3(0, // maxIterations + 1, // numThreads + -1, // randomSeed + true, // clearConfs + false, // useRandomCoords + 2.0, // boxSizeMult + true, // randNegEig + 1, // numZeroFail + nullptr, // coordMap + 1e-3, // optimizerForceTol + false, // ignoreSmoothingFailures + true, // enforceChirality + true, // useExpTorsionAnglePrefs + true, // useBasicKnowledge + false, // verbose + 5.0, // basinThresh + -1.0, // pruneRmsThresh + true, // onlyHeavyAtomsForRMS + 2, // ETversion + nullptr, // boundsMat + true, // embedFragmentsSeparately + true, // useSmallRingTorsions + false, // useMacrocycleTorsions + false, // useMacrocycle14config + nullptr // CPCI ); namespace detail { @@ -488,8 +570,13 @@ bool minimizeWithExpTorsions(RDGeom::PointPtrVect &positions, // create the force field std::unique_ptr field; if (embedParams.useBasicKnowledge) { // ETKDG or KDG - field.reset(DistGeom::construct3DForceField(*eargs.mmat, positions3D, - *eargs.etkdgDetails)); + if (embedParams.CPCI != nullptr) { + field.reset(DistGeom::construct3DForceField( + *eargs.mmat, positions3D, *eargs.etkdgDetails, *embedParams.CPCI)); + } else { + field.reset(DistGeom::construct3DForceField(*eargs.mmat, positions3D, + *eargs.etkdgDetails)); + } } else { // plain ETDG field.reset(DistGeom::constructPlain3DForceField(*eargs.mmat, positions3D, *eargs.etkdgDetails)); @@ -766,6 +853,7 @@ void initETKDG(ROMol *mol, const EmbedParameters ¶ms, if (params.useExpTorsionAnglePrefs || params.useBasicKnowledge) { ForceFields::CrystalFF::getExperimentalTorsions( *mol, etkdgDetails, params.useExpTorsionAnglePrefs, + params.useSmallRingTorsions, params.useMacrocycleTorsions, params.useBasicKnowledge, params.ETversion, params.verbose); etkdgDetails.atomNums.resize(nAtoms); for (unsigned int i = 0; i < nAtoms; ++i) { @@ -783,9 +871,9 @@ bool setupInitialBoundsMatrix( unsigned int nAtoms = mol->getNumAtoms(); if (params.useExpTorsionAnglePrefs || params.useBasicKnowledge) { setTopolBounds(*mol, mmat, etkdgDetails.bonds, etkdgDetails.angles, true, - false); + false, params.useMacrocycle14config); } else { - setTopolBounds(*mol, mmat, true, false); + setTopolBounds(*mol, mmat, true, false, params.useMacrocycle14config); } double tol = 0.0; if (coordMap) { @@ -796,7 +884,7 @@ bool setupInitialBoundsMatrix( // ok this bound matrix failed to triangle smooth - re-compute the // bounds matrix without 15 bounds and with VDW scaling initBoundsMat(mmat); - setTopolBounds(*mol, mmat, false, true); + setTopolBounds(*mol, mmat, false, true, params.useMacrocycle14config); if (coordMap) { adjustBoundsMatFromCoordMap(mmat, nAtoms, coordMap); @@ -808,7 +896,7 @@ bool setupInitialBoundsMatrix( if (params.ignoreSmoothingFailures) { // proceed anyway with the more relaxed bounds matrix initBoundsMat(mmat); - setTopolBounds(*mol, mmat, false, true); + setTopolBounds(*mol, mmat, false, true, params.useMacrocycle14config); if (coordMap) { adjustBoundsMatFromCoordMap(mmat, nAtoms, coordMap); @@ -1003,7 +1091,8 @@ void EmbedMultipleConfs(ROMol &mol, INT_VECT &res, unsigned int numConfs, "does not work with molecules that have multiple fragments. The " "boundsMat will be ignored." << std::endl; - coordMap = nullptr; + coordMap = nullptr; // FIXME not directly related to ETKDG, but here I + // think it should be params.boundsMat = nullptr } // we will generate conformations for each fragment in the molecule diff --git a/Code/GraphMol/DistGeomHelpers/Embedder.h b/Code/GraphMol/DistGeomHelpers/Embedder.h index 025005dd7..33824f042 100644 --- a/Code/GraphMol/DistGeomHelpers/Embedder.h +++ b/Code/GraphMol/DistGeomHelpers/Embedder.h @@ -24,39 +24,30 @@ namespace DGeomHelpers { //! Parameter object for controlling embedding /*! numConfs Number of conformations to be generated - numThreads Sets the number of threads to use (more than one thread will only be used if the RDKit was build with multithread support) If set to zero, the max supported by the system will be used. - maxIterations Max. number of times the embedding will be tried if coordinates are not obtained successfully. The default value is 10x the number of atoms. - randomSeed provides a seed for the random number generator (so that the same coordinates can be obtained for a molecule on multiple runs) If -1, the RNG will not be seeded. - clearConfs Clear all existing conformations on the molecule - useRandomCoords Start the embedding from random coordinates instead of using eigenvalues of the distance matrix. - boxSizeMult Determines the size of the box that is used for random coordinates. If this is a positive number, the side length will equal the largest element of the distance matrix times \c boxSizeMult. If this is a negative number, the side length will equal \c -boxSizeMult (i.e. independent of the elements of the distance matrix). - randNegEig Picks coordinates at random when a embedding process produces negative eigenvalues - numZeroFail Fail embedding if we find this many or more zero eigenvalues (within a tolerance) - pruneRmsThresh Retain only the conformations out of 'numConfs' after embedding that are at least this far apart from each other. RMSD is computed on the heavy atoms. @@ -66,7 +57,6 @@ namespace DGeomHelpers { retained conformations are kept. The pruning is done after embedding and bounds violation minimization. No pruning by default. - coordMap a map of int to Point3D, between atom IDs and their locations their locations. If this container is provided, the coordinates are used to set distance constraints on the @@ -75,28 +65,29 @@ namespace DGeomHelpers { points in \c coordMap. Because the embedding produces a molecule in an arbitrary reference frame, an alignment step is required to actually reproduce the provided coordinates. - optimizerForceTol set the tolerance on forces in the DGeom optimizer (this shouldn't normally be altered in client code). - ignoreSmoothingFailures try to embed the molecule even if triangle bounds smoothing fails - enforceChirality enforce the correct chirality if chiral centers are present - useExpTorsionAnglePrefs impose experimental torsion-angle preferences - useBasicKnowledge impose "basic knowledge" terms such as flat aromatic rings, ketones, etc. - ETversion version of the experimental torsion-angle preferences - verbose print output of experimental torsion-angle preferences - basinThresh set the basin threshold for the DGeom force field, (this shouldn't normally be altered in client code). - onlyHeavyAtomsForRMS only use the heavy atoms when doing RMS filtering + boundsMat custom bound matrix to specify upper and lower bounds of atom + pairs embedFragmentsSeparately embed each fragment of molecule in turn + useSmallRingTorsions optional torsions to improve small ring conformer + sampling + + useMacrocycleTorsions optional torsions to improve macrocycle conformer + sampling useMacrocycle14config If 1-4 distances bound heuristics for + macrocycles is used + + CPCI custom columbic interactions between atom pairs */ struct RDKIT_DISTGEOMHELPERS_EXPORT EmbedParameters { unsigned int maxIterations; @@ -120,6 +111,10 @@ struct RDKIT_DISTGEOMHELPERS_EXPORT EmbedParameters { unsigned int ETversion; boost::shared_ptr boundsMat; bool embedFragmentsSeparately; + bool useSmallRingTorsions; + bool useMacrocycleTorsions; + bool useMacrocycle14config; + std::shared_ptr, double>> CPCI; EmbedParameters() : maxIterations(0), numThreads(1), @@ -141,18 +136,25 @@ struct RDKIT_DISTGEOMHELPERS_EXPORT EmbedParameters { onlyHeavyAtomsForRMS(false), ETversion(1), boundsMat(nullptr), - embedFragmentsSeparately(true){}; - EmbedParameters(unsigned int maxIterations, int numThreads, int randomSeed, - bool clearConfs, bool useRandomCoords, double boxSizeMult, - bool randNegEig, unsigned int numZeroFail, - const std::map *coordMap, - double optimizerForceTol, bool ignoreSmoothingFailures, - bool enforceChirality, bool useExpTorsionAnglePrefs, - bool useBasicKnowledge, bool verbose, double basinThresh, - double pruneRmsThresh, bool onlyHeavyAtomsForRMS, - unsigned int ETversion = 1, - const DistGeom::BoundsMatrix *boundsMat = nullptr, - bool embedFragmentsSeparately = true) + embedFragmentsSeparately(true), + useSmallRingTorsions(false), + useMacrocycleTorsions(false), + useMacrocycle14config(false), + CPCI(nullptr){}; + EmbedParameters( + unsigned int maxIterations, int numThreads, int randomSeed, + bool clearConfs, bool useRandomCoords, double boxSizeMult, + bool randNegEig, unsigned int numZeroFail, + const std::map *coordMap, double optimizerForceTol, + bool ignoreSmoothingFailures, bool enforceChirality, + bool useExpTorsionAnglePrefs, bool useBasicKnowledge, bool verbose, + double basinThresh, double pruneRmsThresh, bool onlyHeavyAtomsForRMS, + unsigned int ETversion = 1, + const DistGeom::BoundsMatrix *boundsMat = nullptr, + bool embedFragmentsSeparately = true, bool useSmallRingTorsions = false, + bool useMacrocycleTorsions = false, bool useMacrocycle14config = false, + std::shared_ptr, double>> + CPCI = nullptr) : maxIterations(maxIterations), numThreads(numThreads), randomSeed(randomSeed), @@ -173,7 +175,11 @@ struct RDKIT_DISTGEOMHELPERS_EXPORT EmbedParameters { onlyHeavyAtomsForRMS(onlyHeavyAtomsForRMS), ETversion(ETversion), boundsMat(boundsMat), - embedFragmentsSeparately(embedFragmentsSeparately){}; + embedFragmentsSeparately(embedFragmentsSeparately), + useSmallRingTorsions(useSmallRingTorsions), + useMacrocycleTorsions(useMacrocycleTorsions), + useMacrocycle14config(useMacrocycle14config), + CPCI(CPCI){}; }; //*! Embed multiple conformations for a molecule @@ -217,11 +223,9 @@ inline int EmbedMolecule(ROMol &mol, const EmbedParameters ¶ms) { successful -# Adjust initial coordinates by minimizing a Distance Violation error function - **NOTE**: if the molecule has multiple fragments, they will be embedded separately, this means that they will likely occupy the same region of space. - \param mol Molecule of interest \param maxIterations Max. number of times the embedding will be tried if coordinates are not obtained successfully. The default @@ -261,32 +265,37 @@ inline int EmbedMolecule(ROMol &mol, const EmbedParameters ¶ms) { \param useBasicKnowledge impose "basic knowledge" terms such as flat aromatic rings, ketones, etc. \param verbose print output of experimental torsion-angle preferences - \param basinThresh set the basin threshold for the DGeom force field, (this shouldn't normally be altered in client code). - \param onlyHeavyAtomsForRMS only use the heavy atoms when doing RMS filtering + \param ETversion version of torsion preferences to use + \param useSmallRingTorsions optional torsions to improve small ring + conformer sampling - \return ID of the conformations added to the molecule, -1 if the emdedding - failed + \param useMacrocycleTorsions optional torsions to improve macrocycle + conformer sampling \param useMacrocycle14config If 1-4 distances bound + heuristics for macrocycles is used \return ID of the conformations added to + the molecule, -1 if the emdedding failed */ -inline int EmbedMolecule(ROMol &mol, unsigned int maxIterations = 0, - int seed = -1, bool clearConfs = true, - bool useRandomCoords = false, double boxSizeMult = 2.0, - bool randNegEig = true, unsigned int numZeroFail = 1, - const std::map *coordMap = 0, - double optimizerForceTol = 1e-3, - bool ignoreSmoothingFailures = false, - bool enforceChirality = true, - bool useExpTorsionAnglePrefs = false, - bool useBasicKnowledge = false, bool verbose = false, - double basinThresh = 5.0, - bool onlyHeavyAtomsForRMS = false) { +inline int EmbedMolecule( + ROMol &mol, unsigned int maxIterations = 0, int seed = -1, + bool clearConfs = true, bool useRandomCoords = false, + double boxSizeMult = 2.0, bool randNegEig = true, + unsigned int numZeroFail = 1, + const std::map *coordMap = 0, + double optimizerForceTol = 1e-3, bool ignoreSmoothingFailures = false, + bool enforceChirality = true, bool useExpTorsionAnglePrefs = false, + bool useBasicKnowledge = false, bool verbose = false, + double basinThresh = 5.0, bool onlyHeavyAtomsForRMS = false, + unsigned int ETversion = 1, bool useSmallRingTorsions = false, + bool useMacrocycleTorsions = false, bool useMacrocycle14config = false) { EmbedParameters params( maxIterations, 1, seed, clearConfs, useRandomCoords, boxSizeMult, randNegEig, numZeroFail, coordMap, optimizerForceTol, ignoreSmoothingFailures, enforceChirality, useExpTorsionAnglePrefs, - useBasicKnowledge, verbose, basinThresh, -1.0, onlyHeavyAtomsForRMS); + useBasicKnowledge, verbose, basinThresh, -1.0, onlyHeavyAtomsForRMS, + ETversion, nullptr, true, useSmallRingTorsions, useMacrocycleTorsions, + useMacrocycle14config); return EmbedMolecule(mol, params); }; @@ -295,12 +304,9 @@ inline int EmbedMolecule(ROMol &mol, unsigned int maxIterations = 0, This is kind of equivalent to calling EmbedMolecule multiple times - just that the bounds matrix is computed only once from the topology - **NOTE**: if the molecule has multiple fragments, they will be embedded separately, this means that they will likely occupy the same region of space. - - \param mol Molecule of interest \param res Used to return the resulting conformer ids \param numConfs Number of conformations to be generated @@ -360,6 +366,13 @@ inline int EmbedMolecule(ROMol &mol, unsigned int maxIterations = 0, \param basinThresh set the basin threshold for the DGeom force field, (this shouldn't normally be altered in client code). \param onlyHeavyAtomsForRMS only use the heavy atoms when doing RMS filtering + \param ETversion version of torsion preferences to use + \param useSmallRingTorsions optional torsions to improve small ring + conformer sampling + + \param useMacrocycleTorsions optional torsions to improve macrocycle + conformer sampling \param useMacrocycle14config If 1-4 distances bound + heuristics for macrocycles is used */ inline void EmbedMultipleConfs( @@ -372,13 +385,16 @@ inline void EmbedMultipleConfs( double optimizerForceTol = 1e-3, bool ignoreSmoothingFailures = false, bool enforceChirality = true, bool useExpTorsionAnglePrefs = false, bool useBasicKnowledge = false, bool verbose = false, - double basinThresh = 5.0, bool onlyHeavyAtomsForRMS = false) { - EmbedParameters params(maxIterations, numThreads, seed, clearConfs, - useRandomCoords, boxSizeMult, randNegEig, numZeroFail, - coordMap, optimizerForceTol, ignoreSmoothingFailures, - enforceChirality, useExpTorsionAnglePrefs, - useBasicKnowledge, verbose, basinThresh, - pruneRmsThresh, onlyHeavyAtomsForRMS); + double basinThresh = 5.0, bool onlyHeavyAtomsForRMS = false, + unsigned int ETversion = 1, bool useSmallRingTorsions = false, + bool useMacrocycleTorsions = false, bool useMacrocycle14config = false) { + EmbedParameters params( + maxIterations, numThreads, seed, clearConfs, useRandomCoords, boxSizeMult, + randNegEig, numZeroFail, coordMap, optimizerForceTol, + ignoreSmoothingFailures, enforceChirality, useExpTorsionAnglePrefs, + useBasicKnowledge, verbose, basinThresh, pruneRmsThresh, + onlyHeavyAtomsForRMS, ETversion, nullptr, true, useSmallRingTorsions, + useMacrocycleTorsions, useMacrocycle14config); EmbedMultipleConfs(mol, res, numConfs, params); }; //! \overload @@ -391,13 +407,16 @@ inline INT_VECT EmbedMultipleConfs( double optimizerForceTol = 1e-3, bool ignoreSmoothingFailures = false, bool enforceChirality = true, bool useExpTorsionAnglePrefs = false, bool useBasicKnowledge = false, bool verbose = false, - double basinThresh = 5.0, bool onlyHeavyAtomsForRMS = false) { - EmbedParameters params(maxIterations, 1, seed, clearConfs, useRandomCoords, - boxSizeMult, randNegEig, numZeroFail, coordMap, - optimizerForceTol, ignoreSmoothingFailures, - enforceChirality, useExpTorsionAnglePrefs, - useBasicKnowledge, verbose, basinThresh, - pruneRmsThresh, onlyHeavyAtomsForRMS); + double basinThresh = 5.0, bool onlyHeavyAtomsForRMS = false, + unsigned int ETversion = 1, bool useSmallRingTorsions = false, + bool useMacrocycleTorsions = false, bool useMacrocycle14config = false) { + EmbedParameters params( + maxIterations, 1, seed, clearConfs, useRandomCoords, boxSizeMult, + randNegEig, numZeroFail, coordMap, optimizerForceTol, + ignoreSmoothingFailures, enforceChirality, useExpTorsionAnglePrefs, + useBasicKnowledge, verbose, basinThresh, pruneRmsThresh, + onlyHeavyAtomsForRMS, ETversion, nullptr, true, useSmallRingTorsions, + useMacrocycleTorsions, useMacrocycle14config); INT_VECT res; EmbedMultipleConfs(mol, res, numConfs, params); return res; @@ -411,6 +430,12 @@ RDKIT_DISTGEOMHELPERS_EXPORT extern const EmbedParameters ETDG; RDKIT_DISTGEOMHELPERS_EXPORT extern const EmbedParameters ETKDG; //! Parameters corresponding to Sereina Riniker's ETKDG approach - version 2 RDKIT_DISTGEOMHELPERS_EXPORT extern const EmbedParameters ETKDGv2; +//! Parameters corresponding improved ETKDG by Wang, Witek, Landrum and Riniker +//! (10.1021/acs.jcim.0c00025) - the macrocycle part +RDKIT_DISTGEOMHELPERS_EXPORT extern const EmbedParameters ETKDGv3; +//! Parameters corresponding improved ETKDG by Wang, Witek, Landrum and Riniker +//! (10.1021/acs.jcim.0c00025) - the small ring part +RDKIT_DISTGEOMHELPERS_EXPORT extern const EmbedParameters srETKDGv3; } // namespace DGeomHelpers } // namespace RDKit diff --git a/Code/GraphMol/DistGeomHelpers/Wrap/rdDistGeom.cpp b/Code/GraphMol/DistGeomHelpers/Wrap/rdDistGeom.cpp index c60b8d1ed..e69293856 100644 --- a/Code/GraphMol/DistGeomHelpers/Wrap/rdDistGeom.cpp +++ b/Code/GraphMol/DistGeomHelpers/Wrap/rdDistGeom.cpp @@ -29,7 +29,8 @@ int EmbedMolecule(ROMol &mol, unsigned int maxAttempts, int seed, python::dict &coordMap, double forceTol, bool ignoreSmoothingFailures, bool enforceChirality, bool useExpTorsionAnglePrefs, bool useBasicKnowledge, - bool printExpTorsionAngles) { + bool printExpTorsionAngles, bool useSmallRingTorsions, + bool useMacrocycleTorsions, unsigned int ETversion) { std::map pMap; python::list ks = coordMap.keys(); unsigned int nKeys = python::extract(ks.attr("__len__")()); @@ -51,7 +52,8 @@ int EmbedMolecule(ROMol &mol, unsigned int maxAttempts, int seed, maxAttempts, numThreads, seed, clearConfs, useRandomCoords, boxSizeMult, randNegEig, numZeroFail, pMapPtr, forceTol, ignoreSmoothingFailures, enforceChirality, useExpTorsionAnglePrefs, useBasicKnowledge, verbose, - basinThresh, pruneRmsThresh, onlyHeavyAtomsForRMS); + basinThresh, pruneRmsThresh, onlyHeavyAtomsForRMS, ETversion, nullptr, + true, useSmallRingTorsions, useMacrocycleTorsions); int res; { @@ -76,7 +78,8 @@ INT_VECT EmbedMultipleConfs( unsigned int numZeroFail, double pruneRmsThresh, python::dict &coordMap, double forceTol, bool ignoreSmoothingFailures, bool enforceChirality, int numThreads, bool useExpTorsionAnglePrefs, bool useBasicKnowledge, - bool printExpTorsionAngles) { + bool printExpTorsionAngles, bool useSmallRingTorsions, + bool useMacrocycleTorsions, unsigned int ETversion) { std::map pMap; python::list ks = coordMap.keys(); unsigned int nKeys = python::extract(ks.attr("__len__")()); @@ -95,7 +98,8 @@ INT_VECT EmbedMultipleConfs( maxAttempts, numThreads, seed, clearConfs, useRandomCoords, boxSizeMult, randNegEig, numZeroFail, pMapPtr, forceTol, ignoreSmoothingFailures, enforceChirality, useExpTorsionAnglePrefs, useBasicKnowledge, verbose, - basinThresh, pruneRmsThresh, onlyHeavyAtomsForRMS); + basinThresh, pruneRmsThresh, onlyHeavyAtomsForRMS, ETversion, nullptr, + true, useSmallRingTorsions, useMacrocycleTorsions); INT_VECT res; { @@ -141,6 +145,18 @@ DGeomHelpers::EmbedParameters *getETKDG() { // ET version 1 DGeomHelpers::EmbedParameters *getETKDGv2() { // ET version 2 return new DGeomHelpers::EmbedParameters(DGeomHelpers::ETKDGv2); } +DGeomHelpers::EmbedParameters * +getETKDGv3() { //! Parameters corresponding improved ETKDG by Wang, Witek, + //! Landrum and Riniker (10.1021/acs.jcim.0c00025) - the + //! macrocycle part + return new DGeomHelpers::EmbedParameters(DGeomHelpers::ETKDGv3); +} +DGeomHelpers::EmbedParameters * +getsrETKDGv3() { //! Parameters corresponding improved ETKDG by Wang, Witek, + //! Landrum and Riniker (10.1021/acs.jcim.0c00025) - the + //! macrocycle part + return new DGeomHelpers::EmbedParameters(DGeomHelpers::srETKDGv3); +} DGeomHelpers::EmbedParameters *getKDG() { return new DGeomHelpers::EmbedParameters(DGeomHelpers::KDG); } @@ -148,6 +164,24 @@ DGeomHelpers::EmbedParameters *getETDG() { return new DGeomHelpers::EmbedParameters(DGeomHelpers::ETDG); } +void setCPCI(DGeomHelpers::EmbedParameters *self, python::dict &CPCIdict) { + // CPCI has the atom pair tuple as key and charge product as value + std::shared_ptr, double>> CPCI( + new std::map, double>); + + python::list ks = CPCIdict.keys(); + unsigned int nKeys = python::extract(ks.attr("__len__")()); + + for (unsigned int i = 0; i < nKeys; ++i) { + python::tuple id = python::extract(ks[i]); + unsigned int a = python::extract(id[0]); + unsigned int b = python::extract(id[1]); + (*CPCI)[std::make_pair(a, b)] = python::extract(CPCIdict[id]); + } + + self->CPCI = CPCI; +} + void setBoundsMatrix(DGeomHelpers::EmbedParameters *self, python::object boundsMatArg) { PyObject *boundsMatObj = boundsMatArg.ptr(); @@ -240,7 +274,10 @@ BOOST_PYTHON_MODULE(rdDistGeom) { python::arg("enforceChirality") = true, python::arg("useExpTorsionAnglePrefs") = true, python::arg("useBasicKnowledge") = true, - python::arg("printExpTorsionAngles") = false), + python::arg("printExpTorsionAngles") = false, + python::arg("useSmallRingTorsions") = false, + python::arg("useMacrocycleTorsions") = false, + python::arg("ETversion") = 1), docString.c_str()); docString = @@ -306,7 +343,10 @@ BOOST_PYTHON_MODULE(rdDistGeom) { python::arg("enforceChirality") = true, python::arg("numThreads") = 1, python::arg("useExpTorsionAnglePrefs") = true, python::arg("useBasicKnowledge") = true, - python::arg("printExpTorsionAngles") = false), + python::arg("printExpTorsionAngles") = false, + python::arg("useSmallRingTorsions") = false, + python::arg("useMacrocycleTorsions") = false, + python::arg("ETversion") = 1), docString.c_str()); python::class_( @@ -375,9 +415,20 @@ BOOST_PYTHON_MODULE(rdDistGeom) { "embedFragmentsSeparately", &RDKit::DGeomHelpers::EmbedParameters::embedFragmentsSeparately, "split the molecule into fragments and embed them separately") + .def_readwrite( + "useSmallRingTorsions", + &RDKit::DGeomHelpers::EmbedParameters::useSmallRingTorsions, + "impose small ring torsion angle preferences") + .def_readwrite( + "useMacrocycleTorsions", + &RDKit::DGeomHelpers::EmbedParameters::useMacrocycleTorsions, + "impose macrocycle torsion angle preferences") .def("SetBoundsMat", &RDKit::setBoundsMatrix, "set the distance-bounds matrix to be used (no triangle smoothing " - "will be done on this) from a Numpy array"); + "will be done on this) from a Numpy array") + .def("SetCPCI", &RDKit::setCPCI, + "set the customised pairwise Columb-like interaction to atom pairs." + "used during structural minimisation stage"); docString = "Use distance geometry to obtain multiple sets of \n\ coordinates for a molecule\n\ @@ -395,7 +446,7 @@ BOOST_PYTHON_MODULE(rdDistGeom) { docString.c_str()); docString = - "Use distance geometry to obtain initial \n\ + "Use distance geometry to obtain intial \n\ coordinates for a molecule\n\n\ \n\ ARGUMENTS:\n\n\ @@ -415,6 +466,14 @@ BOOST_PYTHON_MODULE(rdDistGeom) { "ETKDGv2", RDKit::getETKDGv2, "Returns an EmbedParameters object for the ETKDG method - version 2.", python::return_value_policy()); + python::def("srETKDGv3", RDKit::getsrETKDGv3, + "Returns an EmbedParameters object for the ETKDG method - " + "version 3 (small rings).", + python::return_value_policy()); + python::def("ETKDGv3", RDKit::getETKDGv3, + "Returns an EmbedParameters object for the ETKDG method - " + "version 3 (macrocycles).", + python::return_value_policy()); python::def("ETDG", RDKit::getETDG, "Returns an EmbedParameters object for the ETDG method.", python::return_value_policy()); diff --git a/Code/GraphMol/DistGeomHelpers/Wrap/testDistGeom.py b/Code/GraphMol/DistGeomHelpers/Wrap/testDistGeom.py index 09f473e04..917a14bf8 100644 --- a/Code/GraphMol/DistGeomHelpers/Wrap/testDistGeom.py +++ b/Code/GraphMol/DistGeomHelpers/Wrap/testDistGeom.py @@ -555,6 +555,33 @@ class TestCase(unittest.TestCase): self.assertAlmostEqual((conf.GetAtomPosition(3)-conf.GetAtomPosition(2)).Length(),1.2,delta=0.05) self.assertAlmostEqual((conf.GetAtomPosition(3)-conf.GetAtomPosition(4)).Length(),1.2,delta=0.05) + def testProvidingCPCI(self): + """ + test for a ring molecule, repeated generating a conformer with and without enforcing + an additional +ve interaction between a pair of non-bonded atoms (termed CPCI, + custom pairwise charge-like interaciton), in every iteration, applying CPCI should + yield a conformer where this pair of atoms are further apart. + """ + for i in range(5): + ps = rdDistGeom.EmbedParameters() + ps.randomSeed = i + ps.useBasicKnowledge = True + ps.useRandomCoords = False + m1 = Chem.MolFromSmiles("C1CCCC1C") + self.assertEqual(rdDistGeom.EmbedMolecule(m1,ps),0) + + m2 = Chem.MolFromSmiles("C1CCCC1C") + ps = rdDistGeom.EmbedParameters() + ps.randomSeed = i + ps.useRandomCoords = False + ps.useBasicKnowledge = True + ps.SetCPCI({ (0,3) : 0.9 } ) + self.assertEqual(rdDistGeom.EmbedMolecule(m2,ps),0) + + conf1 = m1.GetConformer() + conf2 = m2.GetConformer() + self.assertTrue((conf2.GetAtomPosition(3)-conf2.GetAtomPosition(0)).Length() > (conf1.GetAtomPosition(3)-conf1.GetAtomPosition(0)).Length()) + diff --git a/Code/GraphMol/DistGeomHelpers/testDgeomHelpers.cpp b/Code/GraphMol/DistGeomHelpers/testDgeomHelpers.cpp index 911afe538..9fb88340d 100644 --- a/Code/GraphMol/DistGeomHelpers/testDgeomHelpers.cpp +++ b/Code/GraphMol/DistGeomHelpers/testDgeomHelpers.cpp @@ -572,9 +572,10 @@ void testMultipleConfs() { void testMultipleConfsExpTors() { std::string smi = "CC(C)(C)c(cc1)ccc1c(cc23)n[n]3C(=O)/C(=C\\N2)C(=O)OCC"; ROMol *m = SmilesToMol(smi, 0, 1); - INT_VECT cids = DGeomHelpers::EmbedMultipleConfs( - *m, 10, 30, 100, true, false, -1, true, 1, -1.0, nullptr, 1e-3, false, - true, true, true); + INT_VECT cids = DGeomHelpers::EmbedMultipleConfs(*m, 10, 30, 100, true, false, + -1, true, 1, -1.0, nullptr, 1e-3, + false, true, false, false, false, 5.0, false, 1, false, false); + INT_VECT_CI ci; // SDWriter writer("junk.sdf"); double energy; @@ -1879,6 +1880,72 @@ void testEmbedParameters() { // std::cerr << fname << std::endl; compareConfs(ref, mol); + delete ref; + delete mol; + } + //small ring torsions improvement test + { + std::string fname = + rdbase + + "/Code/GraphMol/DistGeomHelpers/test_data/simple_torsion.smallring.etkdgv3.mol"; + RWMol *ref = MolFileToMol(fname, true, false); + TEST_ASSERT(ref); + RWMol *mol = SmilesToMol("C1CCCCC1"); + TEST_ASSERT(mol); + MolOps::addHs(*mol); + TEST_ASSERT(ref->getNumAtoms() == mol->getNumAtoms()); + DGeomHelpers::EmbedParameters params(DGeomHelpers::srETKDGv3); + params.randomSeed = 42; + TEST_ASSERT(DGeomHelpers::EmbedMolecule(*mol, params) == 0); + // std::cerr << MolToMolBlock(*ref) << std::endl; + // std::cerr << MolToMolBlock(*mol) << std::endl; + // std::cerr << fname << std::endl; + compareConfs(ref, mol); + + delete ref; + delete mol; + } + //macrocycles torsions backward compatibility test + { + std::string fname = + rdbase + + "/Code/GraphMol/DistGeomHelpers/test_data/simple_torsion.macrocycle.etkdg.mol"; + RWMol *ref = MolFileToMol(fname, true, false); + TEST_ASSERT(ref); + RWMol *mol = SmilesToMol("O=C1NCCCCCCCCC1"); + TEST_ASSERT(mol); + MolOps::addHs(*mol); + TEST_ASSERT(ref->getNumAtoms() == mol->getNumAtoms()); + DGeomHelpers::EmbedParameters params(DGeomHelpers::ETKDG); + params.randomSeed = 42; + TEST_ASSERT(DGeomHelpers::EmbedMolecule(*mol, params) == 0); + // std::cerr << MolToMolBlock(*ref) << std::endl; + // std::cerr << MolToMolBlock(*mol) << std::endl; + // std::cerr << fname << std::endl; + compareConfs(ref, mol); + + delete ref; + delete mol; + } + //macrocycles torsions improvement test + { + std::string fname = + rdbase + + "/Code/GraphMol/DistGeomHelpers/test_data/simple_torsion.macrocycle.etkdgv3.mol"; + RWMol *ref = MolFileToMol(fname, true, false); + TEST_ASSERT(ref); + RWMol *mol = SmilesToMol("C1NCCCCCCCCC1"); + TEST_ASSERT(mol); + MolOps::addHs(*mol); + TEST_ASSERT(ref->getNumAtoms() == mol->getNumAtoms()); + DGeomHelpers::EmbedParameters params(DGeomHelpers::ETKDGv3); + params.randomSeed = 42; + TEST_ASSERT(DGeomHelpers::EmbedMolecule(*mol, params) == 0); + // std::cerr << MolToMolBlock(*ref) << std::endl; + // std::cerr << MolToMolBlock(*mol) << std::endl; + // std::cerr << fname << std::endl; + compareConfs(ref, mol); + delete ref; delete mol; } diff --git a/Code/GraphMol/DistGeomHelpers/test_data/simple_torsion.macrocycle.etkdg.mol b/Code/GraphMol/DistGeomHelpers/test_data/simple_torsion.macrocycle.etkdg.mol new file mode 100644 index 000000000..e0291d2c5 --- /dev/null +++ b/Code/GraphMol/DistGeomHelpers/test_data/simple_torsion.macrocycle.etkdg.mol @@ -0,0 +1,67 @@ + + RDKit 3D + + 31 31 0 0 0 0 0 0 0 0999 V2000 + -2.0690 2.0225 -1.6761 O 0 0 0 0 0 0 0 0 0 0 0 0 + -1.3563 1.6387 -0.6860 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0353 1.8733 -0.7168 N 0 0 0 0 0 0 0 0 0 0 0 0 + 0.8410 2.2132 0.4235 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.0805 1.4093 0.5570 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.0432 0.0554 -0.0571 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.2304 -0.9500 0.7106 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.8743 -2.0928 -0.1849 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.6190 -2.3057 -0.3170 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.3422 -1.0927 -0.8123 C 0 0 0 0 0 0 0 0 0 0 0 0 + -2.2752 -0.5002 0.1978 C 0 0 0 0 0 0 0 0 0 0 0 0 + -2.0759 0.9736 0.4151 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.5188 1.7941 -1.6392 H 0 0 0 0 0 0 0 0 0 0 0 0 + 1.1234 3.3001 0.2938 H 0 0 0 0 0 0 0 0 0 0 0 0 + 0.2819 2.1761 1.3747 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.9312 1.9705 0.0747 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.3697 1.3066 1.6230 H 0 0 0 0 0 0 0 0 0 0 0 0 + 1.7569 0.1143 -1.1349 H 0 0 0 0 0 0 0 0 0 0 0 0 + 3.1018 -0.3310 -0.0706 H 0 0 0 0 0 0 0 0 0 0 0 0 + 1.8838 -1.2908 1.5671 H 0 0 0 0 0 0 0 0 0 0 0 0 + 0.3308 -0.5326 1.1736 H 0 0 0 0 0 0 0 0 0 0 0 0 + 1.2702 -3.0415 0.2852 H 0 0 0 0 0 0 0 0 0 0 0 0 + 1.3832 -2.0500 -1.1790 H 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7453 -3.1292 -1.0666 H 0 0 0 0 0 0 0 0 0 0 0 0 + -1.0163 -2.6957 0.6321 H 0 0 0 0 0 0 0 0 0 0 0 0 + -0.5928 -0.3750 -1.1807 H 0 0 0 0 0 0 0 0 0 0 0 0 + -1.9718 -1.3515 -1.7144 H 0 0 0 0 0 0 0 0 0 0 0 0 + -2.1718 -1.0454 1.1783 H 0 0 0 0 0 0 0 0 0 0 0 0 + -3.3547 -0.6379 -0.0769 H 0 0 0 0 0 0 0 0 0 0 0 0 + -3.0267 1.4931 0.6667 H 0 0 0 0 0 0 0 0 0 0 0 0 + -1.4392 1.0814 1.3392 H 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 2 0 + 2 3 1 0 + 3 4 1 0 + 4 5 1 0 + 5 6 1 0 + 6 7 1 0 + 7 8 1 0 + 8 9 1 0 + 9 10 1 0 + 10 11 1 0 + 11 12 1 0 + 12 2 1 0 + 3 13 1 0 + 4 14 1 0 + 4 15 1 0 + 5 16 1 0 + 5 17 1 0 + 6 18 1 0 + 6 19 1 0 + 7 20 1 0 + 7 21 1 0 + 8 22 1 0 + 8 23 1 0 + 9 24 1 0 + 9 25 1 0 + 10 26 1 0 + 10 27 1 0 + 11 28 1 0 + 11 29 1 0 + 12 30 1 0 + 12 31 1 0 +M END diff --git a/Code/GraphMol/DistGeomHelpers/test_data/simple_torsion.macrocycle.etkdgv3.mol b/Code/GraphMol/DistGeomHelpers/test_data/simple_torsion.macrocycle.etkdgv3.mol new file mode 100644 index 000000000..4d188d4fe --- /dev/null +++ b/Code/GraphMol/DistGeomHelpers/test_data/simple_torsion.macrocycle.etkdgv3.mol @@ -0,0 +1,69 @@ + + RDKit 3D + + 32 32 0 0 0 0 0 0 0 0999 V2000 + 2.0868 -0.9608 -0.3786 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7614 -1.1676 0.1701 N 0 0 0 0 0 0 0 0 0 0 0 0 + -0.0578 -2.2025 -0.3710 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.5084 -1.9853 0.1116 C 0 0 0 0 0 0 0 0 0 0 0 0 + -2.2651 -0.9178 -0.5296 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.8738 0.4810 -0.5950 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.7459 1.3468 0.5909 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.4830 2.3331 0.3470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.6229 1.3309 0.2797 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.0470 1.5762 0.0545 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.7808 0.2101 0.2996 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.6713 -1.8501 -0.0618 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.1291 -0.9454 -1.4655 H 0 0 0 0 0 0 0 0 0 0 0 0 + 0.8849 -1.3334 1.2309 H 0 0 0 0 0 0 0 0 0 0 0 0 + 0.2606 -3.2012 0.0045 H 0 0 0 0 0 0 0 0 0 0 0 0 + -0.0516 -2.2492 -1.4721 H 0 0 0 0 0 0 0 0 0 0 0 0 + -2.0802 -2.9278 0.1059 H 0 0 0 0 0 0 0 0 0 0 0 0 + -1.4217 -1.7199 1.2106 H 0 0 0 0 0 0 0 0 0 0 0 0 + -3.3351 -1.0014 -0.1275 H 0 0 0 0 0 0 0 0 0 0 0 0 + -2.4386 -1.2387 -1.6154 H 0 0 0 0 0 0 0 0 0 0 0 0 + -1.2025 0.7312 -1.4762 H 0 0 0 0 0 0 0 0 0 0 0 0 + -2.8520 0.9553 -1.1040 H 0 0 0 0 0 0 0 0 0 0 0 0 + -2.5508 2.0675 0.7950 H 0 0 0 0 0 0 0 0 0 0 0 0 + -1.4968 0.8191 1.5067 H 0 0 0 0 0 0 0 0 0 0 0 0 + -0.6066 2.8176 -0.6089 H 0 0 0 0 0 0 0 0 0 0 0 0 + -0.4720 3.0346 1.1743 H 0 0 0 0 0 0 0 0 0 0 0 0 + 0.5937 0.9232 1.2920 H 0 0 0 0 0 0 0 0 0 0 0 0 + 0.2926 0.5567 -0.5083 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.5096 2.3111 0.7532 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.2422 1.8551 -0.9924 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.7317 0.0387 1.3851 H 0 0 0 0 0 0 0 0 0 0 0 0 + 3.8269 0.3129 -0.0051 H 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 0 + 2 3 1 0 + 3 4 1 0 + 4 5 1 0 + 5 6 1 0 + 6 7 1 0 + 7 8 1 0 + 8 9 1 0 + 9 10 1 0 + 10 11 1 0 + 11 1 1 0 + 1 12 1 0 + 1 13 1 0 + 2 14 1 0 + 3 15 1 0 + 3 16 1 0 + 4 17 1 0 + 4 18 1 0 + 5 19 1 0 + 5 20 1 0 + 6 21 1 0 + 6 22 1 0 + 7 23 1 0 + 7 24 1 0 + 8 25 1 0 + 8 26 1 0 + 9 27 1 0 + 9 28 1 0 + 10 29 1 0 + 10 30 1 0 + 11 31 1 0 + 11 32 1 0 +M END diff --git a/Code/GraphMol/DistGeomHelpers/test_data/simple_torsion.smallring.etkdgv3.mol b/Code/GraphMol/DistGeomHelpers/test_data/simple_torsion.smallring.etkdgv3.mol new file mode 100644 index 000000000..389d87023 --- /dev/null +++ b/Code/GraphMol/DistGeomHelpers/test_data/simple_torsion.smallring.etkdgv3.mol @@ -0,0 +1,41 @@ + + RDKit 3D + + 18 18 0 0 0 0 0 0 0 0999 V2000 + 0.0738 -1.4331 -0.4002 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.1856 -0.2985 -0.1163 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.8118 1.2126 0.3215 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.2038 1.3088 -0.6638 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.1836 0.3011 0.1225 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.6661 -1.0917 0.7620 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.3400 -1.2106 -1.3596 H 0 0 0 0 0 0 0 0 0 0 0 0 + 0.6827 -2.3367 -0.3219 H 0 0 0 0 0 0 0 0 0 0 0 0 + 1.8000 -0.6642 0.6905 H 0 0 0 0 0 0 0 0 0 0 0 0 + 1.7184 -0.2384 -1.0605 H 0 0 0 0 0 0 0 0 0 0 0 0 + 1.7501 1.7289 0.0882 H 0 0 0 0 0 0 0 0 0 0 0 0 + 0.6142 1.2198 1.3696 H 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7922 2.2250 -0.6311 H 0 0 0 0 0 0 0 0 0 0 0 0 + -0.0677 0.8785 -1.6265 H 0 0 0 0 0 0 0 0 0 0 0 0 + -1.8852 -0.0066 -0.6535 H 0 0 0 0 0 0 0 0 0 0 0 0 + -1.6954 0.8577 0.9025 H 0 0 0 0 0 0 0 0 0 0 0 0 + -0.2140 -0.7858 1.6854 H 0 0 0 0 0 0 0 0 0 0 0 0 + -1.5888 -1.6668 0.8909 H 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 0 + 2 3 1 0 + 3 4 1 0 + 4 5 1 0 + 5 6 1 0 + 6 1 1 0 + 1 7 1 0 + 1 8 1 0 + 2 9 1 0 + 2 10 1 0 + 3 11 1 0 + 3 12 1 0 + 4 13 1 0 + 4 14 1 0 + 5 15 1 0 + 5 16 1 0 + 6 17 1 0 + 6 18 1 0 +M END diff --git a/Code/GraphMol/ForceFieldHelpers/CrystalFF/TorsionPreferences.cpp b/Code/GraphMol/ForceFieldHelpers/CrystalFF/TorsionPreferences.cpp index 61aa05334..cbc9a3c68 100644 --- a/Code/GraphMol/ForceFieldHelpers/CrystalFF/TorsionPreferences.cpp +++ b/Code/GraphMol/ForceFieldHelpers/CrystalFF/TorsionPreferences.cpp @@ -44,6 +44,8 @@ using namespace RDKit; */ #include "torsionPreferences_v1.in" #include "torsionPreferences_v2.in" +#include "torsionPreferences_smallrings.in" +#include "torsionPreferences_macrocycles.in" //! A structure used to the experimental torsion patterns struct ExpTorsionAngle { @@ -59,7 +61,7 @@ class ExpTorsionAngleCollection { public: typedef std::vector ParamsVect; static const ExpTorsionAngleCollection *getParams( - unsigned int version, const std::string ¶mData = ""); + unsigned int version, bool useSmallRingTorsions, bool useMacrocycleTorsions, const std::string ¶mData = ""); ParamsVect::const_iterator begin() const { return d_params.begin(); }; ParamsVect::const_iterator end() const { return d_params.end(); }; ExpTorsionAngleCollection(const std::string ¶mData); @@ -74,7 +76,7 @@ typedef boost::flyweight< param_flyweight; const ExpTorsionAngleCollection *ExpTorsionAngleCollection::getParams( - unsigned int version, const std::string ¶mData) { + unsigned int version, bool useSmallRingTorsions, bool useMacrocycleTorsions, const std::string ¶mData) { std::string params; if (paramData == "") { switch (version) { @@ -90,6 +92,12 @@ const ExpTorsionAngleCollection *ExpTorsionAngleCollection::getParams( } else { params = paramData; } + if (useSmallRingTorsions) + params += torsionPreferencesSmallRings; + + if (useMacrocycleTorsions) + params += torsionPreferencesMacrocycles; + const ExpTorsionAngleCollection *res = &(param_flyweight(params).get()); return res; } @@ -135,7 +143,9 @@ ExpTorsionAngleCollection::ExpTorsionAngleCollection( } void getExperimentalTorsions(const RDKit::ROMol &mol, CrystalFFDetails &details, - bool useExpTorsions, bool useBasicKnowledge, + bool useExpTorsions, + bool useSmallRingTorsions,bool useMacrocycleTorsions, + bool useBasicKnowledge, unsigned int version, bool verbose) { unsigned int nb = mol.getNumBonds(); unsigned int na = mol.getNumAtoms(); @@ -151,12 +161,43 @@ void getExperimentalTorsions(const RDKit::ROMol &mol, CrystalFFDetails &details, unsigned int aid1, aid2, aid3, aid4; unsigned int bid2; + // exclude bonds in bridged ring systems + boost::dynamic_bitset<> excludedBonds(nb); + const RingInfo *rinfo = mol.getRingInfo(); + const VECT_INT_VECT &bondRings = rinfo->bondRings(); + VECT_INT_VECT_CI rii, rjj; + for (rii = bondRings.begin(); rii != bondRings.end(); ++rii) { + boost::dynamic_bitset<> rs1(nb); // bitset for ring 1 + for (unsigned int i = 0; i < rii->size(); i++) { + rs1[(*rii)[i]] = 1; + } + for (rjj = rii+1; rjj != bondRings.end(); ++rjj) { + unsigned int nInCommon = 0; + for (auto rjj_i : *rjj) { + if (rs1[rjj_i]) { + ++nInCommon; + if (nInCommon > 1) { + break; + } + } + } + if (nInCommon > 1) { // more than one bond in common + for (unsigned int i = 0; i < rii->size(); i++) { + excludedBonds[(*rii)[i]] = 1; // exclude all bonds of ring 1 + } + for (unsigned int i = 0; i < rjj->size(); i++) { + excludedBonds[(*rjj)[i]] = 1; // exclude all bonds of ring 2 + } + } + } + } + boost::dynamic_bitset<> doneBonds(nb); if (useExpTorsions) { // we set the torsion angles with experimental data const ExpTorsionAngleCollection *params = - ExpTorsionAngleCollection::getParams(version); + ExpTorsionAngleCollection::getParams(version, useSmallRingTorsions, useMacrocycleTorsions); // loop over patterns for (const auto ¶m : *params) { @@ -173,6 +214,10 @@ void getExperimentalTorsions(const RDKit::ROMol &mol, CrystalFFDetails &details, aid4 = (*matchIt)[param.idx[3]].second; // FIX: check if bond is NULL bid2 = mol.getBondBetweenAtoms(aid2, aid3)->getIdx(); + // check that a bond is part of maximum one ring + if (mol.getRingInfo()->numBondRings(bid2) > 1 || excludedBonds[bid2] == 1) { + doneBonds[bid2] = 1; + } if (!doneBonds[bid2]) { doneBonds[bid2] = 1; std::vector atoms(4); diff --git a/Code/GraphMol/ForceFieldHelpers/CrystalFF/TorsionPreferences.h b/Code/GraphMol/ForceFieldHelpers/CrystalFF/TorsionPreferences.h index 567ebeda2..3ae0902cb 100644 --- a/Code/GraphMol/ForceFieldHelpers/CrystalFF/TorsionPreferences.h +++ b/Code/GraphMol/ForceFieldHelpers/CrystalFF/TorsionPreferences.h @@ -31,7 +31,9 @@ struct CrystalFFDetails { //! Get the experimental torsional angles in a molecule RDKIT_FORCEFIELDHELPERS_EXPORT void getExperimentalTorsions( const RDKit::ROMol &mol, CrystalFFDetails &details, - bool useExpTorsions = false, bool useBasicKnowledge = false, + bool useExpTorsions = false, + bool useSmallRingTorsions = false, bool useMacrocycleTorsions = false, + bool useBasicKnowledge = false, unsigned int version = 1, bool verbose = false); } // namespace CrystalFF } // namespace ForceFields diff --git a/Code/GraphMol/ForceFieldHelpers/CrystalFF/testCrystalFF.cpp b/Code/GraphMol/ForceFieldHelpers/CrystalFF/testCrystalFF.cpp index b5629f10f..1fdbfba07 100644 --- a/Code/GraphMol/ForceFieldHelpers/CrystalFF/testCrystalFF.cpp +++ b/Code/GraphMol/ForceFieldHelpers/CrystalFF/testCrystalFF.cpp @@ -123,7 +123,7 @@ void testTorsionPrefs() { TEST_ASSERT(mol); ForceFields::CrystalFF::CrystalFFDetails details; - ForceFields::CrystalFF::getExperimentalTorsions(*mol, details, true, false, 1, + ForceFields::CrystalFF::getExperimentalTorsions(*mol, details, true, false, false, false, 1, false); TEST_ASSERT(details.expTorsionAtoms.size() == 1); TEST_ASSERT(details.expTorsionAngles.size() == 1); @@ -136,16 +136,90 @@ void testTorsionPrefs() { mol = SmilesToMol("CCCCC"); TEST_ASSERT(mol); - ForceFields::CrystalFF::getExperimentalTorsions(*mol, details, true, false, 1, + ForceFields::CrystalFF::getExperimentalTorsions(*mol, details, true, false, false, false, 1, false); TEST_ASSERT(details.expTorsionAtoms.size() == 2); TEST_ASSERT(details.expTorsionAngles.size() == 2); delete mol; } +void testTorsionPrefsSmallRings() { + ROMol *mol; + ForceFields::CrystalFF::CrystalFFDetails details; + mol = SmilesToMol("C1COCC1"); + TEST_ASSERT(mol); + + //small ring torsion turned off + ForceFields::CrystalFF::getExperimentalTorsions(*mol, details, true, false, false, + false, 1, false); + TEST_ASSERT(details.expTorsionAtoms.size() == 0); + TEST_ASSERT(details.expTorsionAngles.size() == 0); + + //small ring torsion turned on + ForceFields::CrystalFF::getExperimentalTorsions(*mol, details, true, true, false, + false, 1, false); + TEST_ASSERT(details.expTorsionAtoms.size() > 0); + TEST_ASSERT(details.expTorsionAngles.size() > 0); + delete mol; +} + +void testTorsionPrefsBridgedSmallRings() { + // test bridged system does not trigger any small ring torsion + ROMol *mol; + ForceFields::CrystalFF::CrystalFFDetails details; + + mol = SmilesToMol("O[C@H]1C[C@H]2CC[C@]1(C)C2(C)C"); + TEST_ASSERT(mol); + + //small ring torsion turned off + ForceFields::CrystalFF::getExperimentalTorsions(*mol, details, true, true, false, + false, 1, false); + TEST_ASSERT(details.expTorsionAtoms.size() == 0); + TEST_ASSERT(details.expTorsionAngles.size() == 0); + delete mol; +} + +void testTorsionPrefsMacrocycles() { + ROMol *mol; + ForceFields::CrystalFF::CrystalFFDetails details; + mol = SmilesToMol("C1COCCCCCCC1"); + TEST_ASSERT(mol); + + // macrocycle ring torsion turned off + ForceFields::CrystalFF::getExperimentalTorsions(*mol, details, true, false, false, + false, 1, false); + TEST_ASSERT(details.expTorsionAtoms.size() == 0); + TEST_ASSERT(details.expTorsionAngles.size() == 0); + + // macrocycle ring torsion turned on + ForceFields::CrystalFF::getExperimentalTorsions(*mol, details, true, false, true, + false, 1, false); + TEST_ASSERT(details.expTorsionAtoms.size() > 0); + TEST_ASSERT(details.expTorsionAngles.size() > 0); + delete mol; +} + int main() { + RDLog::InitLogs(); + BOOST_LOG(rdInfoLog) + << "********************************************************\n"; + BOOST_LOG(rdInfoLog) << "Testing Crystal ForceField\n"; + + BOOST_LOG(rdInfoLog) << "\t---------------------------------\n"; + BOOST_LOG(rdInfoLog) << "\t SMARTS parsing\n"; testTorsionAngleM6(); + + BOOST_LOG(rdInfoLog) << "\t---------------------------------\n"; + BOOST_LOG(rdInfoLog) << "\t Seeing if non-ring torsions are applied\n"; testTorsionPrefs(); + BOOST_LOG(rdInfoLog) << "\t---------------------------------\n"; + BOOST_LOG(rdInfoLog) << "\t Seeing if small ring torsions are applied\n"; + testTorsionPrefsSmallRings(); + + BOOST_LOG(rdInfoLog) << "\t---------------------------------\n"; + BOOST_LOG(rdInfoLog) << "\t Seeing if macrocycle ring torsions are applied\n"; + testTorsionPrefsMacrocycles(); + return 0; } diff --git a/Code/GraphMol/ForceFieldHelpers/CrystalFF/torsionPreferences_macrocycles.in b/Code/GraphMol/ForceFieldHelpers/CrystalFF/torsionPreferences_macrocycles.in new file mode 100644 index 000000000..60b721a30 --- /dev/null +++ b/Code/GraphMol/ForceFieldHelpers/CrystalFF/torsionPreferences_macrocycles.in @@ -0,0 +1,379 @@ +/* SMARTS patterns for experimental torsion angle preferences + * taken from J. Chem. Inf. Model. (2020), doi: 10.1021/acs.jcim.0c00025 + * + * torsion-angle potential form: + * V = V1*(1 + s1*cos(1x)) + V2*(1 + s2*cos(2x)) + V3*(1 + s3*cos(1x)) + * + V4*(1 + s4*cos(1x)) + V5*(1 + s5*cos(1x)) + V6*(1 + s6*cos(1x)) + * + * format: [SMARTS, s1, V1, s2, V2, s3, V3, s4, V4, s5, V5, s6, V6] + */ +const std::string torsionPreferencesMacrocycles = + // ----- experimental ring amide bond patterns + "[C:1][C;r{9-}:2](=O)@;-[NX3H0;r{9-}:3][CX4H1:4] 1 0.0 -1 8.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[C:1][C;r{9-}:2](=O)@;-[NX3H1;r{9-}:3][CX4H1:4] 1 0.0 -1 8.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[C:1][C;r{9-}:2](=O)@;-[NX3H0;r{9-}:3][CX4H2:4] 1 0.0 -1 8.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + // ---------- adapted chain torsions for macrocycle rings + "[O:1]=[C;r{9-}:2]@;-[O;r{9-}:3]~[CH0:4] -1 78.2 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[C;r{9-}:2]([N])@;-[O;r{9-}:3]~[C:4] -1 79.1 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[C;r{9-}:2]@;-[O;r{9-}:3]~[C:4] -1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[C;r{9-}:2]@;-[O;r{9-}:3]~[!#1:4] -1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][O;r{9-}:2]@;-[c;r{9-}:3]~[*:4] 1 0.0 1 0.8 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][O;r{9-}:2]@;-[CX3;r{9-}:3]~[*:4] 1 0.0 1 0.0 1 2.5 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][O;r{9-}:2]@;-[CH1;r{9-}:3][H:4] -1 20.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][O;r{9-}:2]@;-[CH2;r{9-}:3]~[C:4] 1 0.0 1 0.0 1 2.5 1 0.0 1 0.0 1 0.0\n" + "[H:1][CX4H1;r{9-}:2]@;-[O;r{9-}:3][CX4:4] -1 20.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[C:1][CH2;r{9-}:2]@;-[O;r{9-}:3][CX4:4] 1 0.0 1 0.0 1 2.5 1 0.0 1 0.0 1 0.0\n" + "[*:1][CX4;r{9-}:2]@;-[O;r{9-}:3][$([CX3](=[!O])):4] 1 2.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1][CX4;r{9-}:2]@;-[O;r{9-}:3][CX4:4] 1 0.0 1 0.0 1 8.8 1 0.0 1 0.0 1 0.0\n" + "[*:1][CX4;r{9-}:2]@;-[O;r{9-}:3][CX4:4] 1 0.0 1 0.0 1 2.5 1 0.0 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2]([cH1])@;-[O;r{9-}:3][S:4] 1 0.0 1 3.2 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2]([cH0])@;-[O;r{9-}:3][S:4] 1 0.0 1 8.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([cH0])@;-[O;r{9-}:3][S:4] 1 0.0 1 11.5 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2]([cH1])@;-[O;r{9-}:3][c:4] 1 0.0 1 0.0 1 0.0 -1 0.5 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2]([cH0])@;-[O;r{9-}:3][c:4] 1 0.0 1 0.0 -1 3.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([cH0])@;-[O;r{9-}:3][c:4] 1 0.0 1 2.7 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([cH0])@;-[O;r{9-}:3][P:4] 1 0.0 1 2.7 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([cH0])@;-[O;r{9-}:3][p:4] 1 0.0 1 11.5 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH:1][c;r{9-}:2]([cH])@;-[O;r{9-}:3][$(C([F])([F])[F]):4] 1 0.0 1 30.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([cH0])@;-[O;r{9-}:3][CX4H0:4] 1 0.0 1 30.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[a:1][c;r{9-}:2]([a])@;-[O;r{9-}:3][CX4H0:4] 1 0.0 1 0.0 1 0.0 -1 2.0 1 0.0 1 0.0\n" + "[cH1,n:1][c;r{9-}:2]@;-[O;r{9-}:3][CRH1:4] 1 0.0 -1 5.4 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH1,n:1][c;r{9-}:2]@;-[O;r{9-}:3][CH1:4] 1 0.0 -1 7.2 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[nX2H0:1][c;r{9-}:2]([cH0])@;-[O;r{9-}:3][CX4H0:4] -1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([nX2])@;-[O;r{9-}:3][C:4] 1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[nX2:1][c;r{9-}:2]([nX2])@;-[O;r{9-}:3][C:4] 1 0.0 -1 44.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[nX2:1][c;r{9-}:2]([nX3])@;-[O;r{9-}:3][C:4] -1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2]([nX3])@;-[O;r{9-}:3][C:4] -1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2]([nX2])@;-[O;r{9-}:3][C:4] 1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$([cH0]([CX3])):1][c;r{9-}:2]([cH1])@;-[O;r{9-}:3][C:4] 1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2](cO)@;-[O;r{9-}:3][C:4] -1 61.9 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(cO):1][c;r{9-}:2](cO)@;-[O;r{9-}:3][C:4] 1 0.0 1 3.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([cH0])@;-[O;r{9-}:3][C:4] 1 0.0 1 6.6 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([cH1])@;-[O;r{9-}:3][C:4] 1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2]([cH1])@;-[O;r{9-}:3][C:4] 1 0.0 -1 19.5 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[a:1][c;r{9-}:2]@;-[O;r{9-}:3][CX3H0:4] 1 0.0 1 1.9 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[aH0:1][c;r{9-}:2]@;-[OX2;r{9-}:3][!#1:4] 1 0.0 -1 7.2 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][CX4H0;r{9-}:2]@;-[OX2;r{9-}:3][!#1:4] 1 0.0 1 0.0 1 4.0 1 0.0 1 0.0 1 0.0\n" + "[H:1][CX4H1;r{9-}:2]@;-[OX2;r{9-}:3][!#1:4] -1 5.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[C:1][CX4H2;r{9-}:2]@;-[OX2;r{9-}:3][c:4] 1 0.0 1 0.0 1 4.0 1 0.0 1 0.0 1 0.0\n" + "[c:1][CX4H2;r{9-}:2]@;-[OX2;r{9-}:3][C:4] 1 0.0 1 0.0 1 4.0 1 0.0 1 0.0 1 0.0\n" + "[C:1][CX4H2;r{9-}:2]@;-[OX2;r{9-}:3][C:4] 1 0.0 1 0.0 1 4.0 1 0.0 1 0.0 1 0.0\n" + "[c:1][CX4H2;r{9-}:2]@;-[OX2;r{9-}:3][c:4] 1 0.0 1 0.0 1 4.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][CX4H2;r{9-}:2]@;-[OX2;r{9-}:3][c:4] 1 0.0 1 0.0 1 4.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][CX4H2;r{9-}:2]@;-[OX2;r{9-}:3][C:4] 1 0.0 1 0.0 1 4.0 1 0.0 1 0.0 1 0.0\n" + "[c:1][CX4H2;r{9-}:2]@;-[OX2;r{9-}:3][!#1:4] 1 0.0 1 0.0 1 4.0 1 0.0 1 0.0 1 0.0\n" + "[C:1][CX4H2;r{9-}:2]@;-[OX2;r{9-}:3][!#1:4] 1 2.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][CX4H2;r{9-}:2]@;-[OX2;r{9-}:3][!#1:4] 1 0.0 1 0.0 1 4.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][CX4;r{9-}:2]@;-[OX2;r{9-}:3][!#1:4] 1 0.0 1 8.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$([CX3]=O):1][NX3H0;r{9-}:2](C)@;-[CX4H2;r{9-}:3][C:4] 1 0.0 1 8.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$([CX3]=O):1][NX3H1;r{9-}:2]@;-[CX4H2;r{9-}:3][C:4] 1 0.0 1 0.0 1 4.0 1 0.0 1 0.0 1 0.0\n" + "[$(S(=O)(=O)):1][NX3H0;r{9-}:2]@;-[CX4H2;r{9-}:3][!#1:4] 1 0.0 1 1.9 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(S(=O)(=O)):1][NX3H1;r{9-}:2]@;-[CX4H2;r{9-}:3][!#1:4] 1 17.9 -1 -13.3 1 9.2 1 4.7 -1 -2.3 -1 -0.9\n" + "[$(S(=O)(=O)):1][NX3H0;r{9-}:2]@;-[CX4H1;r{9-}:3][H:4] 1 0.0 -1 15.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(S(=O)(=O)):1][NX3H1;r{9-}:2]@;-[CX4H1;r{9-}:3][H:4] -1 20.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(S(=O)(=O)):1][NH1;r{9-}:2]@;-[c;r{9-}:3][nX2:4] 1 0.0 -1 15.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(S(=O)(=O)):1][NH0;r{9-}:2]@;-[c;r{9-}:3]([cH1])[cH1:4] 1 0.0 1 13.3 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(S(=O)(=O)):1][NH1;r{9-}:2]@;-[c;r{9-}:3]([cH1])[cH1:4] 1 0.0 1 0.0 1 0.0 1 0.9 1 0.0 1 0.0\n" + "[$(S(=O)(=O)):1][NH0;r{9-}:2]@;-[c;r{9-}:3]([cH1])[cH0:4] 1 0.0 1 50.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(S(=O)(=O)):1][NH1;r{9-}:2]@;-[c;r{9-}:3]([cH1])[cH0:4] 1 1.9 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(S(=O)(=O)):1][NH0;r{9-}:2]@;-[c;r{9-}:3]([cH0])[cH0:4] 1 0.0 1 17.8 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(S(=O)(=O)):1][NH1;r{9-}:2]@;-[c;r{9-}:3]([cH0])[cH0:4] 1 0.0 1 10.6 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(S(=O)(=O)):1][N;r{9-}:2]@;-[c;r{9-}:3][a:4] 1 0.0 1 0.0 1 0.0 -1 2.0 1 0.0 1 0.0\n" + "[O-:1][N+;r{9-}:2](=O)@;-[c;r{9-}:3]([cH,nX2H0])[cH,nX2H0:4] 1 0.0 -1 5.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O-:1][N+;r{9-}:2](=O)@;-[c;r{9-}:3]([cH0])[cH,nX2H0:4] -1 -0.2 1 -5.7 1 -0.2 -1 -3.2 1 0.1 1 -1.3\n" + "[O-:1][N+;r{9-}:2](=O)@;-[c;r{9-}:3]([cH0])[cH0:4] -1 -0.4 1 0.3 1 -0.1 -1 0.6 1 -0.1 -1 0.2\n" + "[O-:1][N+;r{9-}:2](=O)@;-[c;r{9-}:3][a:4] 1 0.0 -1 11.8 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([cH0])@;-[NX3H1;r{9-}:3][C,c:4](~[N,n])(~[N,n]) 1 0.0 1 2.7 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([cH1])@;-[NX3H1;r{9-}:3][C,c:4](~[N,n])(~[N,n]) 1 15.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([nX2H0])@;-[NX3H1;r{9-}:3][C,c:4](~[N,n])(~[N,n]) 1 40.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2]([cH1])@;-[NX3H1;r{9-}:3][C,c:4](~[N,n])(~[N,n]) 1 0.0 -1 1.4 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[nX2H0:1][c;r{9-}:2]([nX2H0])@;-[NX3H1;r{9-}:3][C,c:4](~[N,n])(~[N,n]) 1 0.0 -1 15.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[nX2H0:1][c;r{9-}:2]([nX3H1])@;-[NX3H1;r{9-}:3][C,c:4](~[N,n])(~[N,n]) 1 0.0 -1 27.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[a:1][a;r{9-}:2]@;-[NH1;r{9-}:3][C,c:4](~[N,n])(~[N,n]) 1 0.0 -1 6.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[C:1][NH;r{9-}:2]@;-[C;r{9-}:3](=[NH2:4])[NH2] 1 0.0 -1 100.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[NH2][C:1](=[NH2])[NH;r{9-}:2]@;-[CH2;r{9-}:3][C:4] 1 0.0 1 0.0 1 2.5 1 0.0 1 0.0 1 0.0\n" + "[a:1][c;r{9-}:2]@;-[NX2;r{9-}:3]=[$(C([NX3])n):4] -1 -0.1 1 1.9 -1 -0.1 -1 -1.9 -1 0.1 1 0.0\n" + "[nX2:1][c;r{9-}:2]@;-[NX2;r{9-}:3]=[$(C([NX3])N):4] 1 0.0 -1 6.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]@;-[NX2;r{9-}:3]=[$(C([NX3])N):4] -1 -0.1 1 1.9 -1 -0.1 -1 -1.9 -1 0.1 1 0.0\n" + "[cH1:1][c;r{9-}:2]@;-[NX2;r{9-}:3]=[$(C([NX3])N):4] 1 -0.4 -1 -0.9 1 -0.4 1 1.1 1 -0.2 1 -0.1\n" + "[O:1]=[C;r{9-}:2]([NH1])@;-[NX3H1;r{9-}:3](C=O)[H:4] -1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[C;r{9-}:2]@;-[NX3H1;r{9-}:3](C=O)[H:4] 1 0.0 -1 10.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[C;r{9-}:2]@;-[NX3;r{9-}:3](C=O)[*:4] 1 0.0 -1 10.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H1;r{9-}:2]@;-[CX3;r{9-}:3]=[NX2:4] 1 0.0 -1 8.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H0;r{9-}:2]@;-[CX3;r{9-}:3]=[*H0:4] 1 0.0 -1 8.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H0;r{9-}:2]@;-[CX3;r{9-}:3]=[*H1:4] 1 0.0 1 0.0 1 2.5 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H1;r{9-}:2]@;-[CX3;r{9-}:3]=[*H2:4] 1 0.0 -1 68.5 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H1;r{9-}:2]@;-[CX3;r{9-}:3]=[*H1:4] 1 0.0 1 0.0 -1 2.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H1;r{9-}:2]@;-[CX3;r{9-}:3]=[*H0:4] 1 0.0 -1 39.4 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H0;r{9-}:2]@;-[CX3H1;r{9-}:3]=[*:4] 1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H1;r{9-}:2]@;-[CX3H1;r{9-}:3]=[*:4] 1 84.1 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$([C](=O)):1][NX3H0;r{9-}:2]@;-[CX4H2;r{9-}:3][$([c]([cH,nX2H0])[cH,nX2H0]):4] 1 0.0 1 3.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H1;r{9-}:2]@;-[CX4H2;r{9-}:3][$([c]([cH,nX2H0])[cH,nX2H0]):4] -1 -1.3 1 1.6 -1 -0.6 -1 0.6 1 -0.1 -1 0.3\n" + "[$(C=O):1][NX3H0;r{9-}:2]@;-[CX4H2;r{9-}:3][!#1:4] 1 0.0 1 15.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H1;r{9-}:2]@;-[CX4H2;r{9-}:3][!#1:4] 1 0.0 1 0.0 1 2.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H0;r{9-}:2]@;-[CX4H1;r{9-}:3][H:4] 1 0.0 -1 8.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H1;r{9-}:2]@;-[CX4H1;r{9-}:3][H:4] -1 5.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H0;r{9-}:2]@;-[CX4H0;r{9-}:3][C:4] 1 0.0 1 0.0 1 2.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H1;r{9-}:2]@;-[CX4H0;r{9-}:3][C:4] 1 0.0 1 0.0 1 2.5 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3;r{9-}:2]@;-[!#1;r{9-}:3][!#1:4] 1 0.0 1 0.0 1 0.0 -1 0.8 1 0.0 1 0.0\n" + "[$([C](=O)([$([NX3H1]),$([NX3H2])])[NX3H1]):1][NX3H1;r{9-}:2]@;-[c;r{9-}:3]([nH1])[nH0:4] 1 84.1 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$([C](=O)([$([NX3H1]),$([NX3H2])])[NX3H1]):1][NX3H1;r{9-}:2]@;-[c;r{9-}:3]([nH0])[cH1:4] 1 84.1 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$([C](=O)):1][NX3H1;r{9-}:2]@;-[$([a]([nH0,o]));r{9-}:3][cH1:4] -1 53.3 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$([C](=O)([$([NX3H1]),$([NX3H2])])[NX3H1]):1][NX3H1;r{9-}:2]@;-[c&r6;r{9-}:3][nH0&r6:4] 1 0.0 -1 39.4 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$([C](=O)):1][NX3H1;r{9-}:2]@;-[c;r{9-}:3]([cH])[nX2H0:4] 1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H0;r{9-}:2]@;-[c;r{9-}:3]([s,o])[n:4] 1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H1;r{9-}:2]@;-[c;r{9-}:3]([s,o])[n:4] 1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$([C](=O)):1][NX3;r{9-}:2]@;-[a;r{9-}:3](s)[a:4] 1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3;r{9-}:2]@;-[a;r{9-}:3][nH:4] -1 53.3 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H1;r{9-}:2]@;-[c;r{9-}:3]([cH0]Cl)[cH:4] -1 20.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H1;r{9-}:2]@;-[c;r{9-}:3]([cH0]F)[cH:4] -1 11.4 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3;r{9-}:2]@;-[$([a]([cH1]));r{9-}:3][$([aH0](!@O)):4] 1 38.2 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3;r{9-}:2]@;-[a;r{9-}:3][aH0:4] 1 0.0 1 0.0 1 0.8 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H1;r{9-}:2]@;-[c;r{9-}:3]([cH1])[cH1:4] 1 0.0 -1 2.1 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H0;r{9-}:2]@;-[c;r{9-}:3]([cH1])[cH1:4] 1 0.0 1 2.9 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H0;r{9-}:2]@;-[c;r{9-}:3]([cH0])[cH:4] 1 0.0 1 2.4 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H1;r{9-}:2]@;-[c;r{9-}:3]([cH0])[cH:4] -1 9.7 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H0;r{9-}:2]@;-[c;r{9-}:3]([cH0])[cH0:4] 1 0.0 1 2.9 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(C=O):1][NX3H1;r{9-}:2]@;-[c;r{9-}:3]([cH0])[cH0:4] 1 0.0 1 2.9 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O,S:1]=[C;r{9-}:2]([$([NX3H1]),$([NX3H2])])@;-[$([NX3]c[nH0]);r{9-}:3][H:4] 1 0.0 -1 39.4 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[C;r{9-}:2]@;-[$([NX3](c([nH1])n));r{9-}:3][H:4] 1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[C;r{9-}:2](c)@;-[$([NX3](c([nX2H0])([nX2H0])));r{9-}:3][H:4] 1 0.0 -1 39.4 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[CX3;r{9-}:2]([$([NX3H1]C)])@;-[NX3H1;r{9-}:3][!#1:4] -1 51.7 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[C;r{9-}:2]([!$([NH1])])@;-[NX3H1;r{9-}:3]([H:4])[$(c([nX2H0])([nX2H0]))] 1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O,S:1]=[C;r{9-}:2]([$([NX3H1]),$([NX3H2])])@;-[$([NX3](cn));r{9-}:3][H:4] 1 0.0 -1 50.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[C;r{9-}:2]@;-[NX3H0;r{9-}:3]([a:4])[A] 1 0.0 -1 4.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[CX3;r{9-}:2](a)@;-[NX3H0;r{9-}:3][!#1:4] 1 0.0 -1 13.9 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[CX3;r{9-}:2]@;-[NX3H0;r{9-}:3][!#1:4] 1 0.0 -1 8.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[CX3;r{9-}:2]@;-[NX3H1;r{9-}:3][!#1:4] -1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[CH0:1][NX3;r{9-}:2]([CH0])@;-[c;r{9-}:3][a:4] 1 0.0 1 4.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[CH0:1][NX3;r{9-}:2]([CH1])@;-[c;r{9-}:3][a:4] 1 0.0 1 1.3 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH1,nX2H0:1][c;r{9-}:2]([cH1,nX2H0])@;-[NX3&r;r{9-}:3][*:4] 1 0.0 -1 0.9 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[a:1][c;r{9-}:2]@;-[NX3H1;r{9-}:3][$([CX4&r]([C;r])([C;r])):4] 1 0.0 -1 6.8 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2]([cH1])@;-[NX3;r{9-}:3][CX4:4] 1 0.0 -1 6.8 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([cH,nX2H0])@;-[NX3H1;r{9-}:3][CX4:4] 1 73.1 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([cH,nX2H0])@;-[NX3H0;r{9-}:3][CX4:4] 1 0.0 1 0.0 1 0.8 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([cH0])@;-[NX3;r{9-}:3][CX4:4] 1 0.0 1 0.0 1 0.0 -1 2.0 1 0.0 1 0.0\n" + "[c:1][c;r{9-}:2](c)@;-[NX3;r{9-}:3][CX4:4] 1 0.0 -1 0.5 1 0.0 -1 0.8 1 0.0 1 -0.6\n" + "[cH1:1][c;r{9-}:2]([cH1])@;-[NX3;r{9-}:3][a:4] 1 0.0 -1 0.9 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2]([cH0])@;-[NX3;r{9-}:3][a:4] 1 0.0 1 0.0 -1 3.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([cH0])@;-[NX3;r{9-}:3][a:4] 1 0.0 1 1.3 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][a;r{9-}:2]@;-[NX3H0;r{9-}:3][$([CX3]=O):4] 1 0.0 1 2.3 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][a;r{9-}:2]@;-[NX3H1;r{9-}:3][$([CX3]=O):4] -1 -1.6 -1 -0.6 1 0.6 1 0.0 -1 0.1 1 -0.5\n" + "[nX2H0:1][a;r{9-}:2]([nX2H0])@;-[NX3H0;r{9-}:3][$([CX3]=O):4] 1 72.8 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[nX2H0:1][$(a([!nX2H0])([nX2H0])@;-[NX3H1]);r{9-}:2]!@[NX3H1;r{9-}:3][$([CX3](a)=O):4] 1 72.8 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[nX2H0:1][a;r{9-}:2]@;-[NX3H1;r{9-}:3][$([CX3]=O):4] 1 0.0 -1 34.4 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[a:1][a;r{9-}:2]@;-[NX3H1;r{9-}:3][$([CX3]=O):4] 1 0.0 -1 3.1 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[a:1][a;r{9-}:2]@;-[NX3;r{9-}:3][CX4H0:4] 1 0.0 1 0.0 1 0.0 -1 4.0 1 0.0 1 0.0\n" + "[a:1][a;r{9-}:2]@;-[NX3;r{9-}:3][!#1:4] 1 0.0 1 -0.7 1 0.0 1 -0.5 1 0.0 1 -0.6\n" + "[O:1]=[CX3;r{9-}:2]@;-[nX3;r{9-}:3]([aH0:4])([aH0]) 1 0.0 -1 8.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[CX3;r{9-}:2]@;-[nX3;r{9-}:3][aH1:4] 1 0.0 -1 18.7 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[a:1][CX3;r{9-}:2](=S)@;-[NX3;r{9-}:3][a:4] 1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][CX3;r{9-}:2](=S)@;-[NX3H0;r{9-}:3][!#1:4] 1 0.0 -1 22.5 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][CX3;r{9-}:2](=S)@;-[NX3H1;r{9-}:3][!#1:4] 1 0.0 -1 20.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][CH2;r{9-}:2]@;-[n;r{9-}:3][cH0:4] 1 0.0 1 6.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][CH2;r{9-}:2]@;-[n;r{9-}:3][a:4] 1 0.0 1 8.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][n;r{9-}:2]@;-[CX3H0;r{9-}:3]~[$([n,N](-a)):4] 1 0.0 1 0.0 1 0.0 -1 4.0 1 0.0 1 0.0\n" + "[CX4:1][CX4H2;r{9-}:2]@;-[NX3;r{9-}:3][CX4:4] 1 4.0 1 3.1 1 3.9 -1 -0.8 1 0.0 1 0.7\n" + "[C:1][CX4H2;r{9-}:2]@;-[NX3;r{9-}:3][C:4] 1 4.0 1 3.1 1 3.9 -1 -0.8 1 0.0 1 0.7\n" + "[C:1][CX4;r{9-}:2]@;-[NX3;r{9-}:3][C:4] 1 0.0 1 0.0 1 1.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][CX4H2;r{9-}:2]@;-[NX3H1;r{9-}:3][!#1:4] 1 0.0 1 0.0 1 1.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][CX4H2;r{9-}:2]@;-[NX3;r{9-}:3][!#1:4] 1 0.0 1 0.0 1 1.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][CX4H1;r{9-}:2]@;-[NX3;r{9-}:3][!#1:4] 1 0.0 1 0.0 1 1.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][CX4;r{9-}:2]@;-[NX3;r{9-}:3][!#1:4] 1 0.0 1 0.0 1 1.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][$(S(=O)=O);r{9-}:2]@;-[nX3;r{9-}:3]([aH1])[aH1:4] 1 0.0 1 20.5 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][$(S(=O)=O);r{9-}:2]@;-[nX3;r{9-}:3][aH0:4] 1 0.0 1 16.0 1 5.0 1 7.0 1 0.0 1 0.0\n" + "[c:1][S;r{9-}:2](=O)(=O)@;-[NX2H0-;r{9-}:3]-[*:4] 1 0.0 1 16.0 1 5.0 1 7.0 1 0.0 1 0.0\n" + "[*:1][$(S(=O)=O);r{9-}:2]@;-[NX3H0&r;r{9-}:3][*:4] 1 0.0 1 16.0 1 5.0 1 7.0 1 0.0 1 0.0\n" + "[C:1][$(S(=O)=O);r{9-}:2]@;-[NX3H1;r{9-}:3][c:4] 1 0.0 1 16.0 1 5.0 1 7.0 1 0.0 1 0.0\n" + "[C:1][$(S(=O)=O);r{9-}:2]@;-[NX3H0;r{9-}:3][c:4] 1 0.0 1 16.0 1 5.0 1 7.0 1 0.0 1 0.0\n" + "[c:1][$(S(=O)=O);r{9-}:2]@;-[NX3H1;r{9-}:3][C:4] 1 0.0 1 16.0 1 5.0 1 7.0 1 0.0 1 0.0\n" + "[c:1][$(S(=O)=O);r{9-}:2]@;-[NX3H0;r{9-}:3][C:4] 1 0.0 1 16.0 1 5.0 1 7.0 1 0.0 1 0.0\n" + "[c:1][$(S(=O)=O);r{9-}:2]@;-[NX3H1;r{9-}:3][c:4] 1 0.0 1 16.0 1 5.0 1 7.0 1 0.0 1 0.0\n" + "[c:1][$(S(=O)=O);r{9-}:2]@;-[NX3H0;r{9-}:3][c:4] 1 0.0 1 4.1 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[C:1][$(S(=O)=O);r{9-}:2]@;-[NX3H1;r{9-}:3][C:4] 1 0.0 1 16.0 1 5.0 1 7.0 1 0.0 1 0.0\n" + "[C:1][$(S(=O)=O);r{9-}:2]@;-[NX3H0;r{9-}:3][C:4] 1 0.0 1 16.0 1 5.0 1 7.0 1 0.0 1 0.0\n" + "[*:1][$(S(=O)=O);r{9-}:2]@;-[NX3H1;r{9-}:3][*:4] 1 0.0 1 16.0 1 5.0 1 7.0 1 0.0 1 0.0\n" + "[*:1][$(S(=O)=O);r{9-}:2]@;-[NX3H0;r{9-}:3][*:4] 1 0.0 1 3.7 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][CX3;r{9-}:2]@;-[SX2;r{9-}:3][!#1:4] 1 0.0 -1 2.5 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][CX4;r{9-}:2]@;-[SX2;r{9-}:3][!#1:4] -1 -0.8 -1 -0.8 -1 -1.5 -1 0.4 1 -0.1 -1 0.3\n" + "[!#1:1][CX3;r{9-}:2]@;-[SX3;r{9-}:3][!#1:4] 1 0.0 1 16.0 1 5.0 1 7.0 1 0.0 1 0.0\n" + "[!#1:1][CX4;r{9-}:2]@;-[SX3;r{9-}:3][!#1:4] 1 0.0 1 0.0 1 10.4 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][CX3;r{9-}:2]@;-[SX4;r{9-}:3][!#1:4] 1 0.0 1 3.8 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[H:1][CX4H1;r{9-}:2]@;-[SX4;r{9-}:3][!#1:4] 1 0.0 1 0.0 1 2.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][CX4;r{9-}:2]@;-[SX4;r{9-}:3][!#1:4] 1 0.0 1 0.0 1 5.0 1 0.0 1 0.0 1 0.0\n" + "[aH1:1][c;r{9-}:2]([aH1])@;-[SX2;r{9-}:3][!#1:4] 1 0.0 1 0.0 1 0.0 -1 0.9 1 0.0 1 0.0\n" + "[aH1:1][c;r{9-}:2]([aH0])@;-[SX2;r{9-}:3][*R:4] 1 0.0 1 0.0 1 0.0 -1 0.9 1 0.0 1 0.0\n" + "[aH1:1][c;r{9-}:2]([aH0])@;-[SX2;r{9-}:3][!#1:4] 1 0.0 1 0.0 1 0.0 -1 0.9 1 0.0 1 0.0\n" + "[aH0:1][c;r{9-}:2]([aH0])@;-[SX2;r{9-}:3][!#1:4] 1 -0.2 1 0.4 1 0.0 -1 1.9 1 0.0 1 -1.1\n" + "[!#1:1][c;r{9-}:2]@;-[SX2;r{9-}:3][!#1:4] 1 0.0 -1 39.4 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][c;r{9-}:2]@;-[SX3;r{9-}:3][!#1:4] 1 0.0 1 1.3 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[aH1:1][c;r{9-}:2]([aH1])@;-[SX4;r{9-}:3][!#1:4] 1 0.0 1 1.5 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[aH0:1][c;r{9-}:2]([aH1])@;-[SX4;r{9-}:3][!#1:4] 1 0.0 1 0.0 1 2.0 1 0.0 1 0.0 1 0.0\n" + "[aH0:1][c;r{9-}:2]([aH0])@;-[SX4;r{9-}:3][!#1:4] 1 0.0 1 3.3 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[CX3;r{9-}:2]([NH1])@;-[CH2;r{9-}:3][CX3:4]=O 1 0.0 1 0.0 1 2.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[CX3;r{9-}:2]([NH1])@;-[CH2;r{9-}:3][C:4] -1 8.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$([CX3]([C])([H])):1]=[CX3;r{9-}:2]([C])@;-[CH2;r{9-}:3][C:4] 1 0.0 1 0.0 -1 5.0 1 0.0 1 0.0 1 0.0\n" + "[$([CX3]([C])([H])):1]=[CX3;r{9-}:2]([H])@;-[CH1;r{9-}:3](C)[C:4] 1 0.0 1 0.0 -1 5.0 1 0.0 1 0.0 1 0.0\n" + "[$([CX3]([C])([H])):1]=[CX3;r{9-}:2]([H])@;-[CH2;r{9-}:3][C:4] 1 0.0 1 0.0 -1 5.0 1 0.0 1 0.0 1 0.0\n" + "[N:1][C;r{9-}:2](=O)@;-[CX4H2;r{9-}:3][CX4H2:4] 1 4.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "N[C;r{9-}:2](=[O:1])@;-[CH2;r{9-}:3][N:4] 1 0.0 -1 10.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[C;r{9-}:2]([O-])@;-[CX4H1;r{9-}:3][H:4] 1 0.0 1 0.0 1 0.0 1 2.0 1 0.0 1 0.0\n" + "[CX3H2:1]=[CX3;r{9-}:2]@;-[CX3;r{9-}:3]=[C:4] 1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[CX3:1]=[CX3;r{9-}:2]@;-[CH2;r{9-}:3][OX2:4] 1 0.0 1 0.0 -1 20.0 1 0.0 1 0.0 1 0.0\n" + "[CX3:1]=[CX3;r{9-}:2]@;-[CH1;r{9-}:3](C)[C:4] 1 0.0 1 0.0 -1 4.0 1 0.0 1 0.0 1 0.0\n" + "[CX3:1]=[CX3;r{9-}:2]@;-[CH2;r{9-}:3][C:4] 1 0.0 1 0.0 -1 1.5 1 0.0 1 0.0 1 0.0\n" + "[CX3:1]=[CX3;r{9-}:2]@;-[CH2;r{9-}:3][c:4] 1 0.0 1 0.0 -1 1.5 1 0.0 1 0.0 1 0.0\n" + "[CX3:1]=[CX3;r{9-}:2]@;-[CH2;r{9-}:3][!#1:4] 1 0.0 1 0.0 -1 4.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[CX3;r{9-}:2](O)@;-[CX3;r{9-}:3]([$([NH1,NH2,CH2])])=[O:4] 1 0.0 -1 39.4 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[CX3;r{9-}:2]@;-[CX3;r{9-}:3]=[O:4] 1 20.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[CX3R:1]=[CX3R;r{9-}:2]@;-[CX3;r{9-}:3]=[CX3:4] 1 0.0 -1 39.4 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[CX3H0:1]=[CX3H0;r{9-}:2]@;-[CX3;r{9-}:3]=[CX3H0:4] 1 0.0 1 0.0 1 2.0 1 0.0 1 0.0 1 0.0\n" + "[CX3H0:1]=[CX3H0;r{9-}:2]@;-[CX3H0;r{9-}:3]=[CX3:4] 1 0.0 1 1.5 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[CX3H0:1]=[CX3;r{9-}:2]@;-[CX3H0;r{9-}:3]=[CX3:4] 1 20.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[CX3H0:1]=[CX3H0;r{9-}:2]@;-[CX3;r{9-}:3]=[CX3:4] 1 20.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[CX3:1]=[CX3;r{9-}:2]@;-[CX3;r{9-}:3]=[CX3:4] 1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[*^2:1]~[C^2;r{9-}:2]([!H])@;-[C^2;r{9-}:3]~[*^2:4] 1 0.0 -1 15.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[*^2:1]~[C^2;r{9-}:2]@;-[C^2;r{9-}:3]~[*^2:4] 1 0.0 -1 30.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[CX3;r{9-}:2]@;-[CX4&r3;r{9-}:3]!@[!#1:4] -1 -0.7 -1 0.5 1 -0.3 -1 0.3 -1 -0.2 -1 0.2\n" + "[O:1]=[CX3;r{9-}:2]@;-[CX4H1&r3;r{9-}:3][H:4] 1 0.0 -1 3.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[OX2:1][CX4H2;r{9-}:2]@;-[CX4H2;r{9-}:3][N&r:4] 1 0.0 1 0.0 1 5.0 1 0.0 1 0.0 1 0.0\n" + "[OX2:1][CX4H2;r{9-}:2]@;-[CX4H2;r{9-}:3][N:4] 1 0.0 1 0.0 1 10.0 1 0.0 1 0.0 1 0.0\n" + "[OX2:1][CX4;r{9-}:2]@;-[CX4;r{9-}:3][N:4] 1 0.0 1 0.0 1 4.0 1 0.0 1 0.0 1 0.0\n" + "[OX2:1][CX4H2;r{9-}:2]@;-[CX4H2;r{9-}:3][OX2:4] 1 0.0 1 0.0 1 10.0 1 0.0 1 0.0 1 0.0\n" + "[OX2:1][CX4;r{9-}:2]@;-[CX4;r{9-}:3][OX2:4] 1 0.0 1 0.0 1 3.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][CX4&r;r{9-}:2]@;-[CX4&r;r{9-}:3][!#1:4] 1 0.0 1 0.0 1 2.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][CX4H2;r{9-}:2]@;-[CX4H2;r{9-}:3][!#1:4] 1 0.0 1 0.0 1 4.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][CX4;r{9-}:2]@;-[CX4;r{9-}:3][!#1:4] 1 0.0 1 0.0 1 7.0 1 0.0 1 0.0 1 0.0\n" + "[OX2:1][CX4H2;r{9-}:2]@;-[CX3;r{9-}:3]([$([NX3H1,NX3H2])])=[O:4] 1 0.0 -1 39.4 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[OH1:1][CX4;r{9-}:2]@;-[CX3;r{9-}:3]=[O:4] 1 0.0 -1 2.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[NH1:1][CX4;r{9-}:2]@;-[CX3;r{9-}:3]=[O:4] 1 0.0 -1 3.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1][CX4;r{9-}:2]@;-[CX3;r{9-}:3]=[O:4] 1 0.0 -1 3.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[N:1][CX4;r{9-}:2]@;-[CX3;r{9-}:3]=[O:4] 1 0.0 -1 1.4 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[C:1][CX4H2;r{9-}:2]@;-[CX3;r{9-}:3]=[O:4] 1 -1.0 1 -0.5 1 -0.2 1 -0.3 1 0.0 1 -0.3\n" + "[c:1][CX4H2;r{9-}:2]@;-[CX3;r{9-}:3]=[O:4] -1 0.9 1 -0.3 1 -0.2 1 -0.5 -1 0.1 1 0.2\n" + "[!#1:1][CX4H2;r{9-}:2]@;-[CX3;r{9-}:3]=[O:4] 1 0.0 1 -0.7 1 0.0 1 -0.5 1 0.0 1 -0.6\n" + "[c:1][CX4;r{9-}:2]@;-[CX3;r{9-}:3]=[O:4] 1 0.0 1 0.0 -1 1.0 1 0.0 1 0.0 1 0.0\n" + "[C:1][CX4;r{9-}:2]@;-[CX3;r{9-}:3]=[O:4] 1 0.0 1 0.0 -1 1.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][CX4;r{9-}:2]@;-[CX3;r{9-}:3]=[O:4] 1 0.0 1 0.0 -1 1.0 1 0.0 1 0.0 1 0.0\n" + "[c:1][CX4;r{9-}:2]@;-[CX3;r{9-}:3][C:4] 1 0.0 1 0.0 1 1.9 1 0.0 1 0.0 1 0.0\n" + "[C:1][CX4;r{9-}:2]@;-[CX3;r{9-}:3][c:4] 1 0.0 1 0.0 1 2.0 1 0.0 1 0.0 1 0.0\n" + "[c:1][CX4;r{9-}:2]@;-[CX3;r{9-}:3][c:4] -1 -4.4 1 4.0 -1 -3.9 -1 -1.0 1 0.6 -1 -0.4\n" + "[C:1][CX4;r{9-}:2]@;-[CX3;r{9-}:3][C:4] 1 0.0 1 0.0 1 1.5 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][CX4;r{9-}:2]@;-[CX3H0;r{9-}:3][!#1:4] 1 0.0 1 0.0 1 0.6 1 0.0 1 0.0 1 0.0\n" + "[H:1][CX4H1;r{9-}:2]@;-[CX3;r{9-}:3][!#1:4] 1 0.0 -1 1.4 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1:1][CX4H2;r{9-}:2]@;-[CX3;r{9-}:3][!#1:4] 1 0.0 1 0.0 1 0.0 -1 0.8 1 0.0 1 0.0\n" + "[$([cH0]([$([NX3H2]),$([NX3H1])])):1][a;r{9-}:2]@;-[a;r{9-}:3][nX2:4] 1 0.0 -1 30.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[nH0:1][c&r6;r{9-}:2]([nH0])@;-[c&r6;r{9-}:3]([nH0])[nH0:4] 1 0.0 -1 4.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[nH0&r6:1][c&r6;r{9-}:2]([nH0&r6])@;-[c&r6;r{9-}:3]([cH1&r6])[nH0&r6:4] 1 0.0 -1 4.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[nH0&r6:1][c&r6;r{9-}:2]([nH0&r6])@;-[c&r6;r{9-}:3]([cH1&r6])[cH1&r6:4] 1 0.0 -1 4.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[c:1][c;r{9-}:2]@;-[c;r{9-}:3][$(c!@c):4] 1 0.1 1 0.9 1 0.1 -1 -0.4 1 0.0 -1 0.3\n" + "[cH0:1][c;r{9-}:2]([cH0])@;-[c;r{9-}:3]([cH0:4])[cH0] 1 0.0 1 3.6 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([cH0])@;-[c;r{9-}:3]([cH0:4])[cH1] 1 0.0 1 10.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([cH1])@;-[c;r{9-}:3]([cH0:4])[cH1] 1 0.0 1 3.6 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([cH0])@;-[c;r{9-}:3]([cH1:4])[cH1] 1 0.0 1 3.6 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([cH1])@;-[c;r{9-}:3]([cH1:4])[cH1] 1 0.0 1 0.0 1 0.0 1 0.6 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2]([cH1])@;-[c;r{9-}:3]([cH1:4])[cH1] -1 -0.7 1 -8.0 1 0.0 1 4.4 1 0.0 1 -1.5\n" + "[nX2H0:1][c;r{9-}:2]@;-[c;r{9-}:3][nX3H1:4] 1 0.0 -1 30.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[nX2H0:1][c;r{9-}:2]([!nX2H0])@;-[c;r{9-}:3]([!nX2H0])[nX2H0:4] 1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[nX2H0:1][$(c([nX2H0])(a(a)(a))@;-c[nX2H0]);r{9-}:2]!@[c;r{9-}:3][nX2H0:4] 1 30.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[nX2H0:1][$([c&r6](c[OH]));r{9-}:2]@;-[$([c&r6](c[OH]));r{9-}:3][nX2H0:4] 1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[c:1][c;r{9-}:2]@;-[c;r{9-}:3][s,o,nX3H1:4] 1 0.0 -1 4.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([cH0])@;-[c;r{9-}:3][nX2H0:4] 1 0.0 1 1.7 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]@;-[c;r{9-}:3]([cH0])[nX2H0:4] -1 0.9 -1 -1.0 1 -0.8 -1 0.2 -1 0.3 1 -0.2\n" + "[c:1][c;r{9-}:2]@;-[c;r{9-}:3]([cH0])[nX2H0:4] 1 0.0 1 0.0 1 0.0 1 1.1 1 0.0 1 0.0\n" + "[c:1][c;r{9-}:2]([cH0])@;-[c;r{9-}:3][nX2H0:4] 1 0.0 -1 3.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2]@;-[c;r{9-}:3]([cH1])[nX2H0:4] 1 0.0 -1 20.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[c:1][c&r5;r{9-}:2]@;-[c&r5;r{9-}:3][c:4] 1 0.0 -1 20.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[c:1][c&r6;r{9-}:2]@;-[c&r5;r{9-}:3][c:4] 1 0.0 1 0.0 1 0.0 1 1.1 1 0.0 1 0.0\n" + "[c:1][c&r6;r{9-}:2]@;-[c&r6;r{9-}:3][cH0:4] 1 0.0 1 3.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[c:1][c&r6;r{9-}:2]@;-[c&r6;r{9-}:3][c:4] 1 0.0 1 0.0 1 0.0 1 1.1 1 0.0 1 0.0\n" + "[c:1][c;r{9-}:2]@;-[c;r{9-}:3][c:4] 1 0.0 1 0.0 1 0.0 1 1.1 1 0.0 1 0.0\n" + "[nX2&r6:1][cH0&r6;r{9-}:2]([cH1&r6])@;-[CX4H2;r{9-}:3][O!H:4] 1 2.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]@;-[CX4H0;r{9-}:3][a:4] 1 0.0 1 0.0 1 8.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]@;-[CX4H0;r{9-}:3][N,O,S:4] 1 0.0 1 0.0 1 8.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]@;-[CX4H0;r{9-}:3][CX3:4] 1 0.0 1 0.0 1 12.5 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]@;-[CX4H0;r{9-}:3][CX4:4] 1 0.0 1 0.0 1 8.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]@;-[CX4H0;r{9-}:3][*:4] 1 0.0 1 0.0 1 3.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]@;-[CX4H2;r{9-}:3][a:4] -1 -1.3 1 1.6 -1 -0.6 -1 0.6 1 -0.1 -1 0.3\n" + "[cH0:1][c;r{9-}:2]@;-[CX4H2;r{9-}:3][CX3:4] -1 -1.3 1 1.6 -1 -0.6 -1 0.6 1 -0.1 -1 0.3\n" + "[cH1:1][c;r{9-}:2]([cH1])@;-[CX4H2;r{9-}:3][$([CX4H1]C(=O)O):4] 1 0.0 1 4.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2]([cH1])@;-[CX4H2;r{9-}:3][CX4:4] 1 0.0 1 3.6 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]@;-[CX4H2;r{9-}:3][CX4:4] -1 -1.3 1 1.6 -1 -0.6 -1 0.6 1 -0.1 -1 0.3\n" + "[cH0:1][c;r{9-}:2]@;-[CX4H2;r{9-}:3][N,O,S:4] -1 -1.3 1 1.6 -1 -0.6 -1 0.6 1 -0.1 -1 0.3\n" + "[cH0:1][c;r{9-}:2]@;-[CX4H2;r{9-}:3][!#1:4] -1 -1.3 1 1.6 -1 -0.6 -1 0.6 1 -0.1 -1 0.3\n" + "[cH0:1][c;r{9-}:2]@;-[CX4H1;r{9-}:3][a:4] 1 0.9 1 1.2 1 0.6 1 0.4 1 0.0 1 0.1\n" + "[cH0:1][c;r{9-}:2]@;-[CX4H1;r{9-}:3][CX4:4] 1 0.0 1 1.2 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]@;-[CX4H1;r{9-}:3][CX3:4] 1 0.0 1 0.0 1 0.0 1 1.5 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]@;-[CX4H1;r{9-}:3][N,O,S:4] 1 0.0 1 0.0 1 0.0 1 2.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]@;-[CX4H1;r{9-}:3][H:4] 1 0.0 -1 4.3 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[a:1][c;r{9-}:2]@;-[CX4H0;r{9-}:3][a:4] 1 0.0 -1 -0.3 -1 -0.1 1 0.1 1 0.0 -1 0.1\n" + "[a:1][c;r{9-}:2]@;-[CX4H0;r{9-}:3][CX3:4] 1 0.0 1 0.0 1 0.0 1 1.0 1 0.0 1 0.0\n" + "[a:1][c;r{9-}:2]@;-[CX4H0;r{9-}:3][CX4:4] 1 0.0 1 0.0 1 0.0 -1 0.5 1 0.0 1 0.0\n" + "[a:1][c;r{9-}:2]@;-[CX4H0;r{9-}:3][N,O:4] 1 0.0 -1 0.8 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[a:1][c;r{9-}:2]@;-[CX4H2;r{9-}:3][a:4] 1 0.0 1 1.2 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[a:1][c;r{9-}:2]@;-[CX4H2;r{9-}:3][CX3:4] 1 0.0 1 1.2 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[n,o,s:1][c;r{9-}:2]@;-[CX4H2;r{9-}:3][CX4:4] 1 0.0 1 0.0 1 0.0 -1 3.0 1 0.0 1 0.0\n" + "[a:1][c;r{9-}:2]@;-[CX4H2;r{9-}:3][!#1:4] 1 0.0 1 3.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[a:1][c;r{9-}:2]@;-[CX4H1;r{9-}:3][N,O:4] 1 0.0 1 0.0 1 0.0 1 0.5 1 0.0 1 0.0\n" + "[a:1][c;r{9-}:2]@;-[CX4H1;r{9-}:3][a:4] 1 0.0 1 0.6 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[a:1][c;r{9-}:2]@;-[CX4H1;r{9-}:3][H:4] 1 0.0 -1 0.7 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[nX2H0:1][c;r{9-}:2]@;-[C;r{9-}:3](=[N:4])(-[NH1,NH2]) 1 0.0 -1 15.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[a:1][c;r{9-}:2]@;-[C;r{9-}:3](=[$([N][CX4]):4])([$(N[CX4])]) 1 0.0 -1 0.6 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[a:1][c;r{9-}:2]@;-[C;r{9-}:3](=[$([NH0][CX4]):4])(-N) 1 0.0 -1 15.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[a:1][c;r{9-}:2]@;-[C;r{9-}:3](=[$([N][!#1]):4])([$(N(C)[!#1])]) 1 0.0 -1 0.6 1 0.0 1 0.3 1 0.0 -1 -0.1\n" + "[a:1][c;r{9-}:2]@;-[C;r{9-}:3](=[$([N][!#1]):4])([$(N(C)~[!#1])]) 1 0.0 -1 15.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[a:1][c;r{9-}:2]@;-[C;r{9-}:3](=[N:4])(-N) 1 0.0 -1 0.6 1 0.0 1 0.3 1 0.0 -1 -0.1\n" + "[O:1]=[C;r{9-}:2]([O-])@;-[c;r{9-}:3][$(aC(=O)(O)):4] 1 0.0 -1 0.6 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[C;r{9-}:2]([O-])@;-[c;r{9-}:3][nX3H1:4] 1 0.0 -1 30.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[C;r{9-}:2]([O-])@;-[c;r{9-}:3][nX2H0:4] 1 0.0 -1 30.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[C;r{9-}:2]([O-])@;-[c;r{9-}:3]([cH0])[cH0:4] 1 0.0 1 0.0 1 0.0 -1 3.0 1 0.0 1 0.0\n" + "[O:1]=[C;r{9-}:2]([O-])@;-[c;r{9-}:3]([cH1])[$([cH0][NH1,NH2]):4] 1 0.0 -1 30.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[C;r{9-}:2]([O-])@;-[c;r{9-}:3]([cH1])[cH0:4] 1 0.0 -1 7.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[C;r{9-}:2]([O-])@;-[c;r{9-}:3]([cH1])[cH1:4] 1 0.0 -1 7.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[O:1]=[C;r{9-}:2]([O-])@;-[c;r{9-}:3][a:4] 1 0.0 -1 25.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$([c]([NH1,NH2])):1][c;r{9-}:2]@;-[CX3;r{9-}:3]([!O])=[O:4] -1 14.8 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(a[OH1]):1][a;r{9-}:2]@;-[CX3;r{9-}:3]([NX3H0,CX4H0,c])=[O:4] -1 14.8 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$(a[NH1,NH2]):1][a;r{9-}:2]@;-[CX3;r{9-}:3]([NX3H0,CX4H0,c])=[O:4] -1 36.2 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([cH1])@;-[CX3;r{9-}:3](c)=[O:4] 1 0.0 1 0.0 1 0.0 1 1.5 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2]([cH1])@;-[CX3;r{9-}:3](c)=[O:4] -1 -0.1 -1 2.4 1 -0.4 -1 -1.0 1 0.1 -1 -0.5\n" + "[a:1][a;r{9-}:2]@;-[CX3;r{9-}:3](a)=[O:4] -1 8.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$([cH0](=O)):1][c;r{9-}:2]([cH1])@;-[CX3;r{9-}:3]([NX3H1,NX3H2])=[O:4] 1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[nH0&r6:1][c&r6;r{9-}:2]([cH1&r6])@;-[C;r{9-}:3]([NH1,NH2])=[O:4] 1 20.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[s:1][c;r{9-}:2]@;-[C;r{9-}:3]([NH1])=[O:4] 1 0.0 -1 36.8 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$([cH0]Cl):1][c;r{9-}:2]([cH1])@;-[CX3;r{9-}:3]([NX3H1])=[O:4] 1 0.1 1 0.9 1 0.1 -1 -0.4 1 0.0 -1 0.3\n" + "[$([cH0]F):1][c;r{9-}:2]([cH1])@;-[CX3;r{9-}:3]([NX3H1])=[O:4] 1 6.2 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$([cH0][OH0]):1][c;r{9-}:2]([cH1])@;-[C;r{9-}:3](=O)[NH1:4] -1 60.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$([cH0][OH1]):1][c;r{9-}:2]([cH1])@;-[C;r{9-}:3](=O)[NH1:4] 1 0.0 -1 15.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([cH1])@;-[CX3;r{9-}:3]([NX3H1])=[O:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 -1 1.2\n" + "[cH0:1][c;r{9-}:2]([cH1])@;-[CX3;r{9-}:3]([NX3H0])=[O:4] 1 0.0 1 5.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2]([cH1])@;-[C;r{9-}:3]([NH1,NH2])=[O:4] 1 0.0 -1 1.6 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[a:1][c;r{9-}:2]@;-[C;r{9-}:3]([NH0])=[O:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 -1 1.2\n" + "[a:1][c;r{9-}:2]@;-[C;r{9-}:3]([NH1,NH2])=[O:4] 1 0.0 -1 2.4 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[s:1][c;r{9-}:2]([aX2,cH1])@;-[CX3;r{9-}:3](O)=[O:4] 1 0.0 -1 10.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[s:1][c;r{9-}:2]([aX2,cH1])@;-[CX3;r{9-}:3]=[O:4] -1 60.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$([cH0](F)):1][c;r{9-}:2]([cH1])@;-[CX3;r{9-}:3]([O,N])=[O:4] 1 0.0 -1 1.8 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$([cH0]F):1][c;r{9-}:2]([cH1])@;-[CX3;r{9-}:3]=[O:4] 1 6.2 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$([cH0](Cl)):1][c;r{9-}:2]([cH1])@;-[CX3;r{9-}:3]([CX3H])=[O:4] 1 0.0 1 0.0 1 0.0 1 2.0 1 0.0 1 0.0\n" + "[$([cH0](Cl)):1][c;r{9-}:2]([cH1])@;-[CX3H;r{9-}:3]=[O:4] 1 6.2 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$([cH0](Cl)):1][c;r{9-}:2]([cH1])@;-[CX3;r{9-}:3](O)=[O:4] 1 0.0 -1 1.8 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[nX3H1:1][a;r{9-}:2]@;-[CX3;r{9-}:3]=[O:4] 1 0.0 -1 10.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[nX2H0:1][c;r{9-}:2]([cH1])@;-[CX3H1;r{9-}:3]=[O:4] 1 66.5 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[nX2H0&r6:1][c&r6;r{9-}:2]([c&r6])@;-[CX3;r{9-}:3]([!O])=[O:4] 1 6.2 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[nX2H0:1][a;r{9-}:2]([nX2H0])@;-[CX3;r{9-}:3]=[O:4] 1 0.0 -1 36.8 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[$([cH0]@;-[*^2]):1][c;r{9-}:2]([cH1])!@[CX3;r{9-}:3]=[O:4] 1 0.0 -1 8.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([cH1])@;-[CX3;r{9-}:3]=[O:4] 1 0.0 -1 10.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([cH0])@;-[CX3;r{9-}:3]=[O:4] 1 0.0 1 0.0 1 0.0 -1 3.0 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2]([cH1])@;-[CX3;r{9-}:3]([CX3H0])=[O:4] 1 0.0 -1 5.9 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2]([cH1])@;-[CX3;r{9-}:3]=[O:4] 1 0.0 -1 5.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[a:1][a;r{9-}:2]@;-[CX3;r{9-}:3]=[O:4] 1 0.0 -1 8.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2]([nX2])@;-[CX3;r{9-}:3]=[NX3:4] 1 0.0 -1 8.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2]([nX3H1])@;-[CX3;r{9-}:3]=[NX2:4] 1 97.4 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2]([nX2])@;-[CX3;r{9-}:3]=[NX2:4] 1 0.0 -1 8.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2]([$([cH0][OH1])])@;-[CX3;r{9-}:3]=[NX2:4] 1 100.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2]([cH0])@;-[CX3x0;r{9-}:3]=[NX2:4] 1 0.0 -1 36.8 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH1:1][c;r{9-}:2]([cH1])@;-[CX3;r{9-}:3]=[NX2:4] 1 0.0 -1 9.5 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[cH0:1][c;r{9-}:2]([cH0])@;-[CX3!r;r{9-}:3]=[NX2!r:4] 1 0.0 1 -0.7 1 0.0 1 -0.5 1 0.0 1 -0.6\n" + "[a:1][c;r{9-}:2]@;-[CX3;r{9-}:3]=[CX3H0:4] 1 0.0 -1 0.7 1 0.0 1 0.6 1 0.0 1 -0.5\n" + "[a:1][a;r{9-}:2]@;-[CX3;r{9-}:3]=[CX3H2:4] 1 0.0 -1 5.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[a:1][a;r{9-}:2]@;-[CX3;r{9-}:3]=[CX3H1:4] 1 0.0 -1 5.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[*:1][SX2;r{9-}:2]@;-[SX2;r{9-}:3][*:4] 1 0.0 1 12.9 1 0.0 1 0.0 1 0.0 1 0.0\n"; diff --git a/Code/GraphMol/ForceFieldHelpers/CrystalFF/torsionPreferences_smallrings.in b/Code/GraphMol/ForceFieldHelpers/CrystalFF/torsionPreferences_smallrings.in new file mode 100644 index 000000000..b896f0b6b --- /dev/null +++ b/Code/GraphMol/ForceFieldHelpers/CrystalFF/torsionPreferences_smallrings.in @@ -0,0 +1,116 @@ +/* SMARTS patterns for experimental torsion angle preferences + * taken from J. Chem. Inf. Model. (2020), doi: 10.1021/acs.jcim.0c00025 + * + * torsion-angle potential form: + * V = V1*(1 + s1*cos(1x)) + V2*(1 + s2*cos(2x)) + V3*(1 + s3*cos(1x)) + * + V4*(1 + s4*cos(1x)) + V5*(1 + s5*cos(1x)) + V6*(1 + s6*cos(1x)) + * + * format: [SMARTS, s1, V1, s2, V2, s3, V3, s4, V4, s5, V5, s6, V6] + */ +const std::string torsionPreferencesSmallRings = + // ring torsions + "[x3;r{-8}:1]@;~[A;x3;r3:2]@;-[A;x2;r3:3]@;~[!#1;r{-8}:4] 1 0.0 1 10.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{-8}:1]@;~[A;r3:2]@;-[A;r3:3]@;~[!#1;r{-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 -1 10.0\n" + "[!#1;r{-4}:1]1@[C;r{-4}:2]@;-[C;r{-4}:3]@[!#1;r{-4}:4]1 -1 30.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{-4}:1]@[A;r{-4}:2]@;-[!#1;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 -1 2.0\n" + "[!#1;r{5-8}:1]@[C^2;r{5-8}:2]@;-[C^2;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 -1 10.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r5:1]@;=,:[C^2;r5:2]@;-[C;r5:3]@[!#1;r5:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 -1 15.0\n" + "[!#1;r{5-6}:1]@;=,:[C^2;r{5-6}:2]@;-[C;r{5-6}:3]@[!#1;r{5-6}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 1 10.0\n" + "[!#1;r{5-8}:1]@;=,:[C^2;r{5-8}:2]@;-[C;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 -1 5.0\n" + "[!#1;r{5-8}:1]@[C^2;r5:2]@;-[C;r5:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 -1 10.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[C^2;r{5-6}:2]@;-[C;r{5-6}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 5.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[C^2;r{5-8}:2]@;-[C;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 5.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;R3;r{5-8}:1]@[CX4;R2;r{5-8}:2]@;-[CX4;R2;r{5-8}:3]@[!#1;R3;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 -1 10.0\n" + "[!#1;R2;r5:1]@[CX4;R1;r5:2]@;-[CX4;R1;r5:3]@[!#1;R2;r5:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 1 10.0\n" + "[!#1;R2;r{5-6}:1]@[CX4;R1;r{5-6}:2]@;-[CX4;R1;r{5-6}:3]@[!#1;R2;r{5-6}:4] 1 0.0 1 0.0 1 20.0 1 0.0 1 0.0 1 0.0\n" + "[!#1]1@[x3;r5:1]@[CX4;x2;r5:2]@;-[CX4;x3;r5:3]@[!#1;r5:4]1 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 1 10.0\n" + "[!#1]1@[x3;r5:1]@[CX4;r5:2]@;-[CX4;r5:3]@[x3;r5:4]1 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 1 10.0\n" + "[!#1]1@[x3;r{5-6}:1]@[CX4;r5:2]@;-[CX4;r5:3]@[x3;r{5-6}:4]@[!#1]1 1 0.0 1 0.0 1 5.0 1 0.0 1 0.0 1 0.0\n" + "[!#1]1@[x3;C^2,c,r3;r{5-6}:1]@[CX4;r{5-6}:2]@;-[CX4;r{5-6}:3]@[x3;r{5-6}:4]@[!#1]1 1 0.0 1 0.0 1 20.0 1 0.0 1 0.0 1 0.0\n" + "[!#1]1@[x3;r{5-6}:1]@[CX4;r{5-6}:2]@;-[CX4;r{5-6}:3]@[x3;r{5-6}:4]@[!#1]1 1 0.0 1 0.0 1 20.0 1 0.0 1 0.0 1 0.0\n" + "[CX4;r{5-7}:1]1@[CX4;r{5-7}:2]@;-[CX4;x3;r{5-7}:3]@[!#1;r{5-7}:4]@[!#1]@[!#1]@[!#1]1 1 0.0 1 0.0 1 5.0 1 0.0 1 0.0 1 0.0\n" + "[CX4;r{5-8}:1]1@[CX4;r{5-8}:2]@;-[CX4;x3;r{5-8}:3]@[!#1;r{5-8}:4]@[!#1]@[!#1]@[!#1]@[!#1]1 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 1 10.0\n" + "[C^2,a;r{5-8}:1]@[CX4;x2;r5:2]@;-[CX4;x2;r5:3]@[!#1;r{5-8}:4][C^2,a] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 1 10.0\n" + "[!#1;r{5-8}:1]@[CX4;x3;r{5-8}:2]@;-[CX4;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 10.0 1 0.0 1 0.0 1 0.0\n" + "[!#1]1@[!#1;R1;r5:1]@[CX4;R2;r5:2]@;-[CX4;R2;r5:3]@[!#1;R1;r5:4]1 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 1 10.0\n" + "[C^2,a;r{5-8}][C^2,a;r{5-8}:1]@[CX4;r{5-8}:2]@;-[CX4;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 10.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r5:1]@[CX4;r5:2]@;-[CX4;r5:3]@[!#1;r5:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 1 10.0\n" + "[C^2,c,x4;r{5-8}:1]@[CX4;r{5-8}:2]@;-[CX4;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 -1 10.0\n" + "[!#1;r{5-8}:1]@[CX4;r{5-8}:2]@;-[CX4;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 30.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[C;r{5-8}:2]@;-[C;r{5-8}:3]@[!#1;r{5-8}:4] -1 20.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[C;r5:2]@;-[a;r{5-6}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 -1 15.0\n" + "[!#1;r{5-8}:1]@[C;r{5-6}:2]@;-[a;r{5-6}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 -1 5.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[C;r{5-8}:2]@;-[a;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 3.0 1 0.0 1 0.0\n" + "[a;r5:1]@[c;r5:2]@;-[N;r{5-6}:3]@[!#1;r{5-8}:4] 1 0.0 -1 20.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[a;r{5-6}:1]@[c;r{5-6}:2]@;-[N;r{5-6}:3]@[!#1;r{5-8}:4] 1 0.0 -1 3.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[a;r{5-8}:1]@[c;r{5-8}:2]@;-[N;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 10.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[C^2;r{5-8}:2]@;-[N;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 -1 20.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[C;r{5-8}:2]@;-[NX2;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 -1 5.0\n" + "[!#1;r{5-8}:1]@[CX4;r5:2]@;-[ND3;r5:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 -1 5.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[CX4;r{5-6}:2]@;-[ND3;r{5-6}:3]@[C;r{5-8}:4]=O 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 1 5.0\n" + "[C^2,c,r5;r{5-8}:1]@[CX4;r{5-6}:2]@;-[ND3;r{5-6}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 -1 10.0\n" + "[!#1;r{5-8}:1]@[CX4;r{5-6}:2]@;-[ND3;r{5-6}:3]@[!#1;r{5-8}:4]@[C^2,c,r5;r{5-8}] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 -1 10.0\n" + "[!#1;r{5-8}:1]@[CX4;r{5-6}:2]@;-[ND3;r{5-6}:3]@[!#1;!#6;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 -1 10.0\n" + "[!#1;r{5-8}:1]@[CX4;r{5-6}:2]@;-[ND3;r{5-6}:3]@[C^2,c;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 1 10.0\n" + "[!#1;r{5-8}:1]@[CX4;r{5-6}:2]@;-[ND3;r{5-6}:3]([C^2,c])[!#1;r{5-8}:4] 1 0.0 1 0.0 1 30.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[CX4;r{5-6}:2]@;-[ND3;r{5-6}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 30.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[CX4;r{5-8}:2]@;-[ND3;r{5-8}:3]@[C;r{5-8}:4]=O 1 0.0 1 20.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[CX4;r{5-8}:2]@;-[ND3;r{5-8}:3](C=O)[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 1 5.0\n" + "[!#1;r{5-8}:1]@[CX4;r{5-8}:2]@;-[ND3;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 5.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[CX4;r{5-8}:2]@;-[N;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 -1 10.0\n" + "[!#1;r{5-8}:1]@[C;r{5-8}:2]@;-[N;r{5-8}:3]@[!#1;r{5-8}:4] -1 20.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[C^2,c;r{5-8}:2]@;-[O;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 -1 8.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[CX4;r5:2]@;-[O;r5:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 -1 3.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[CX4;r{5-6}:2]@;-[O;r{5-6}:3]@[C^2,c;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 1 5.0\n" + "[!#1;r{5-8}:1]@[CX4;r{5-6}:2]@;-[O;r{5-6}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 30.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[C;r{5-8}:2]@;-[O;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 -1 10.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[C^2,c;r{5-8}:2]@;-[S;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 -1 8.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[CX4;r5:2]@;-[S;r5:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 -1 5.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[CX4;r{5-6}:2]@;-[S;r{5-6}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 10.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[CX4;r{5-8}:2]@;-[S;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 1 5.0\n" + "[!#1;r{5-8}:1]@[C;r{5-8}:2]@;-[S;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 10.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[NX2;r{5-8}:2]@;-[N;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 -1 10.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1^2,a;r{5-8}:1]@[N;r{5-6}:2]@;-[N;r{5-6}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 -1 3.0\n" + "[!#1;R2,R3;r{5-8}:1]@[N;r{5-6}:2]@;-[N;r{5-6}:3]@[!#1;R2,R3;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 -1 10.0\n" + "[!#1;r{5-8}:1]@[N;r5:2]@;-[N;r5:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 -1 5.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[N;r{5-6}:2]@;-[N;r{5-6}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 20.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[N;r{5-8}:2]@;-[N;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 20.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[N;r{5-6}:2]@;-[a;r{5-6}:3]@[!#1;r{5-8}:4] 1 0.0 -1 10.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[N;r{5-8}:2]@;-[a;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 5.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[NX2;r{5-8}:2]@;-[O;r{5-8}:3]@[!#1;r{5-8}:4] -1 30.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;R2,R3;r{5-8}:1]@[N;r{5-6}:2]@;-[O;r{5-6}:3]@[!#1;R2,R3;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 -1 10.0\n" + "[!#1;r{5-8}:1]@[N;r5:2]@;-[O;r5:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 3.0 1 0.0\n" + "[!#1;r{5-8}:1]@[N;r{5-6}:2]@;-[O;r{5-6}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 10.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[N;r{5-8}:2]@;-[O;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 15.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[NX2;r{5-8}:2]@;-[S;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 -1 10.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[N;r5:2]@;-[S;r5:3]@[!#1;r{5-8}:4] -1 30.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[N;r{5-6}:2]@;-[S;r{5-6}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 20.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[N;r{5-8}:2]@;-[S;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 5.0 1 10.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[O;r{5-8}:2]@;-[O;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 -1 3.0\n" + "[!#1;r{5-8}:1]@[O;r{5-8}:2]@;-[S;r{5-8}:3]@;=,:[!#1;r{5-8}:4] -1 20.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[O;r5:2]@;-[S;r5:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 -1 5.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[O;r{5-6}:2]@;-[S;r{5-6}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 20.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[O;r{5-8}:2]@;-[S;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 10.0 1 10.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[O;r{5-6}:2]@;-[a;r{5-6}:3]@[!#1;r{5-8}:4] 1 0.0 -1 10.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[O;r{5-8}:2]@;-[a;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 5.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[S;r5:2]@;-[S;r5:3]@[!#1;r{5-8}:4] -1 20.0 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[S;r{5-6}:2]@;-[S;r{5-6}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 20.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[S;r{5-8}:2]@;-[S;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 20.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[S;r5:2]@;-[a;r{5-6}:3]@[!#1;r{5-8}:4] 1 0.0 -1 10.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[S;r{5-6}:2]@;-[a;r{5-6}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 1 5.0\n" + "[!#1;r{5-8}:1]@[S;r{5-8}:2]@;-[a;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 5.0 1 0.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[P;r{5-8}:2]@;-[C^2,c;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 -1 10.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[P;r5:2]@;-[CX4;r5:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 -1 5.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[P;r{5-6}:2]@;-[CX4;r{5-6}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 20.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[P;r{5-8}:2]@;-[C;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 1 5.0\n" + "[!#1;r{5-8}:1]@[P;r{5-8}:2]@;-[NX2;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 -1 15.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[P;r{5-8}:2]@;-[N;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 -1 10.0\n" + "[!#1;r{5-8}:1]@;=[P;r{5-8}:2]@;-[O;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 -1 20.0\n" + "[!#1;r{5-8}:1]@[P;r5:2]@;-[O;r5:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 -1 5.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[P;r{5-6}:2]@;-[O;r{5-6}:3]@[!#1;r{5-8}:4] -1 10.0 1 0.0 1 5.0 1 0.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[P;r{5-8}:2]@;-[O;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 5.0 1 0.0\n" + "[!#1;r{5-8}:1]@[P;r5:2]@;-[S,P;r5:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 -1 10.0 1 0.0 1 0.0\n" + "[!#1;r{5-8}:1]@[P;r{5-6}:2]@;-[S,P;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 1 5.0\n" + "[!#1;r{5-8}:1]@[P;r{5-8}:2]@;-[S,P;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 1 5.0\n" + "[!#1;r{5-8}:1]@[P;r{5-8}:2]@;-[a;r{5-8}:3]@[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 -1 10.0\n" + "[!#1;r{5-8}:1]@;~[A;r{5-8}:2]@;-[A,a;r{5-8}:3]@;~[!#1;r{5-8}:4] 1 0.0 1 0.0 1 0.0 1 0.0 1 0.0 -1 20.0\n"; diff --git a/Code/JavaWrappers/DistGeom.i b/Code/JavaWrappers/DistGeom.i index 251f07ef6..ca8dda87f 100644 --- a/Code/JavaWrappers/DistGeom.i +++ b/Code/JavaWrappers/DistGeom.i @@ -66,6 +66,8 @@ %ignore RDKit::DGeomHelpers::ETDG; %ignore RDKit::DGeomHelpers::ETKDG; %ignore RDKit::DGeomHelpers::ETKDGv2; +%ignore RDKit::DGeomHelpers::ETKDGv3; +%ignore RDKit::DGeomHelpers::srETKDGv3; %include @@ -74,6 +76,8 @@ %newobject RDKit::DGeomHelpers::getETDG; %newobject RDKit::DGeomHelpers::getETKDG; %newobject RDKit::DGeomHelpers::getETKDGv2; +%newobject RDKit::DGeomHelpers::getETKDGv3; +%newobject RDKit::DGeomHelpers::getsrETKDGv3; %inline { namespace RDKit{ namespace DGeomHelpers { @@ -89,6 +93,12 @@ EmbedParameters *getETKDGv2() { return new EmbedParameters(ETKDGv2); } + EmbedParameters *getETKDGv3() { + return new EmbedParameters(ETKDGv3); + } + EmbedParameters *getsrETKDGv3() { + return new EmbedParameters(srETKDGv3); + } } } }