void testUFFBuilderSpecialCases(){ BOOST_LOG(rdErrorLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdErrorLog) << " Testing UFF special cases." << std::endl; RWMol *mol; std::string key; int needMore; RDGeom::Point3D v1,v2; ForceFields::ForceField *field; std::string pathName=getenv("RDBASE"); pathName += "/Code/GraphMol/ForceFieldHelpers/UFF/test_data"; // ---------- // Trigonal bipyramid // ---------- mol = MolFileToMol(pathName+"/tbp.mol",false); TEST_ASSERT(mol); MolOps::sanitizeMol(*mol); const Conformer &conf = mol->getConformer(); field=UFF::constructForceField(*mol); TEST_ASSERT(field); field->initialize(); needMore = field->minimize(200,1e-8,1e-4); TEST_ASSERT(!needMore); v1 = conf.getAtomPos(0).directionVector(conf.getAtomPos(1)); v2 = conf.getAtomPos(0).directionVector(conf.getAtomPos(2)); TEST_ASSERT(feq(v1.dotProduct(v2),-1.0,1e-3)); v2 = conf.getAtomPos(0).directionVector(conf.getAtomPos(3)); TEST_ASSERT(feq(v1.dotProduct(v2),0.0,1e-3)); v2 = conf.getAtomPos(0).directionVector(conf.getAtomPos(4)); TEST_ASSERT(feq(v1.dotProduct(v2),0.0,1e-3)); v2 = conf.getAtomPos(0).directionVector(conf.getAtomPos(5)); TEST_ASSERT(feq(v1.dotProduct(v2),0.0,1e-3)); v1 = conf.getAtomPos(0).directionVector(conf.getAtomPos(2)); v2 = conf.getAtomPos(0).directionVector(conf.getAtomPos(3)); TEST_ASSERT(feq(v1.dotProduct(v2),0.0,1e-3)); v2 = conf.getAtomPos(0).directionVector(conf.getAtomPos(4)); TEST_ASSERT(feq(v1.dotProduct(v2),0.0,1e-3)); v2 = conf.getAtomPos(0).directionVector(conf.getAtomPos(5)); TEST_ASSERT(feq(v1.dotProduct(v2),0.0,1e-3)); v1 = conf.getAtomPos(0).directionVector(conf.getAtomPos(3)); v2 = conf.getAtomPos(0).directionVector(conf.getAtomPos(4)); TEST_ASSERT(feq(v1.dotProduct(v2),-0.5,1e-3)); v2 = conf.getAtomPos(0).directionVector(conf.getAtomPos(5)); TEST_ASSERT(feq(v1.dotProduct(v2),-0.5,1e-3)); v1 = conf.getAtomPos(0).directionVector(conf.getAtomPos(4)); v2 = conf.getAtomPos(0).directionVector(conf.getAtomPos(5)); TEST_ASSERT(feq(v1.dotProduct(v2),-0.5,1e-3)); delete mol; delete field; BOOST_LOG(rdErrorLog) << " done" << std::endl; }
void runMol(ROMol *mol,int checkEvery=10,bool verbose=true){ ForceFields::ForceField *field; std::cout << MolToMolBlock(*mol) << "$$$$" << std::endl; try{ field=UFF::constructForceField(*mol,2.5); } catch (...) { field=0; } if(field){ field->initialize(); int needMore=1; int nPasses=0; while(needMore){ #if 1 needMore = field->minimize(checkEvery); if(verbose) std::cerr << "\t" << ++nPasses << std::endl; #else needMore = field->minimize(1); std::cout << MolToMolBlock(mol) << "$$$$" << std::endl; #endif } std::cout << MolToMolBlock(*mol) << "$$$$" << std::endl; delete field; } else { std::cerr << "failed"; } }
void testIssue242() { // FIX: Changes to the forcefield (connected to Issue 408) have // made it so that this particular problem no longer manifests // in this molecule/embedding. A new test case is needed. BOOST_LOG(rdErrorLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdErrorLog) << " Testing Issue242." << std::endl; RWMol *mol, *mol2; int needMore; ForceFields::ForceField *field = 0, *field2 = 0; std::string mb1,mb2; double e1,e2; std::string pathName = getenv("RDBASE"); pathName += "/Code/GraphMol/ForceFieldHelpers/MMFF/test_data"; mol = MolFileToMol(pathName + "/Issue242-2.mol"); TEST_ASSERT(mol); mol2 = MolFileToMol(pathName + "/Issue242-2.mol"); TEST_ASSERT(mol2); TEST_ASSERT(DGeomHelpers::EmbedMolecule(*mol2, 30, 2370) >= 0); mb1 = MolToMolBlock(*mol); mb2 = MolToMolBlock(*mol2); //std::cout << mb1 << "------\n"; //std::cout << mb2 << "------\n"; field = MMFF::constructForceField(*mol); TEST_ASSERT(field); field->initialize(); field2 = MMFF::constructForceField(*mol2); TEST_ASSERT(field2); field2->initialize(); e1 = field->calcEnergy(); e2 = field2->calcEnergy(); BOOST_LOG(rdInfoLog) << "E1: " << e1 << std::endl; BOOST_LOG(rdInfoLog) << "E2: " << e2 << std::endl; //TEST_ASSERT(feq(e2,e1,0.1)); needMore = field->minimize(200,1.0e-4); needMore = field2->minimize(200,1.0e-4); e1 = field->calcEnergy(); e2 = field2->calcEnergy(); BOOST_LOG(rdInfoLog) << "E1: " << e1 << std::endl; BOOST_LOG(rdInfoLog) << "E2: " << e2 << std::endl; TEST_ASSERT(feq(e2, e1, 0.1)); delete mol; delete mol2; delete field; delete field2; BOOST_LOG(rdErrorLog) << " done" << std::endl; }
void testUFFMultiThread(){ BOOST_LOG(rdErrorLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdErrorLog) << " Test UFF multithreading" << std::endl; ForceFields::ForceField *field; std::string pathName = getenv("RDBASE"); pathName += "/Code/GraphMol/ForceFieldHelpers/UFF/test_data"; SDMolSupplier suppl(pathName + "/bulk.sdf"); std::vector<ROMol *> mols; while(!suppl.atEnd()&&mols.size()<100){ ROMol *mol=0; try{ mol=suppl.next(); } catch(...){ continue; } if(!mol) continue; mols.push_back(mol); } std::cerr<<"generating reference data"<<std::endl; std::vector<double> energies(mols.size(),0.0); for(unsigned int i=0;i<mols.size();++i){ ROMol mol(*mols[i]); ForceFields::ForceField *field = 0; try { field = UFF::constructForceField(mol); } catch (...) { field = 0; } TEST_ASSERT(field); field->initialize(); int failed = field->minimize(500); TEST_ASSERT(!failed); energies[i]=field->calcEnergy(); delete field; } boost::thread_group tg; std::cerr<<"processing"<<std::endl; unsigned int count=4; for(unsigned int i=0;i<count;++i){ std::cerr<<" launch :"<<i<<std::endl;std::cerr.flush(); tg.add_thread(new boost::thread(runblock_uff,mols,energies,count,i)); } tg.join_all(); BOOST_FOREACH(ROMol *mol,mols){ delete mol; } BOOST_LOG(rdErrorLog) << " done" << std::endl; }
ForceFields::ForceField *construct3DImproperForceField( const BoundsMatrix &mmat, RDGeom::Point3DPtrVect &positions, const std::vector<std::vector<int> > &improperAtoms, const std::vector<int> &atomNums) { (void)atomNums; unsigned int N = mmat.numRows(); CHECK_INVARIANT(N == positions.size(), ""); ForceFields::ForceField *field = new ForceFields::ForceField(positions[0]->dimension()); for (unsigned int i = 0; i < N; ++i) { field->positions().push_back(positions[i]); } // improper torsions / out-of-plane bend / inversion double oobForceScalingFactor = 10.0; for (unsigned int t = 0; t < improperAtoms.size(); ++t) { std::vector<int> n(4); for (unsigned int i = 0; i < 3; ++i) { n[1] = 1; switch (i) { case 0: n[0] = 0; n[2] = 2; n[3] = 3; break; case 1: n[0] = 0; n[2] = 3; n[3] = 2; break; case 2: n[0] = 2; n[2] = 3; n[3] = 0; break; } ForceFields::UFF::InversionContrib *contrib = new ForceFields::UFF::InversionContrib( field, improperAtoms[t][n[0]], improperAtoms[t][n[1]], improperAtoms[t][n[2]], improperAtoms[t][n[3]], improperAtoms[t][4], improperAtoms[t][5], oobForceScalingFactor); field->contribs().push_back(ForceFields::ContribPtr(contrib)); } } return field; } // construct3DImproperForceField
void testCrippenO3AConstraints() { ROMol *m = SmilesToMol("n1ccc(cc1)-c1ccccc1"); TEST_ASSERT(m); ROMol *m1 = MolOps::addHs(*m); delete m; TEST_ASSERT(m1); DGeomHelpers::EmbedMolecule(*m1); MMFF::sanitizeMMFFMol((RWMol &)(*m1)); MMFF::MMFFMolProperties mp(*m1); TEST_ASSERT(mp.isValid()); ForceFields::ForceField *field = MMFF::constructForceField(*m1, &mp); field->initialize(); field->minimize(); RWMol *patt = SmartsToMol("nccc-cccc"); MatchVectType matchVect; TEST_ASSERT(SubstructMatch(*m1, (ROMol &)*patt, matchVect)); unsigned int nIdx = matchVect[0].second; unsigned int cIdx = matchVect[matchVect.size() - 1].second; MolTransforms::setDihedralDeg(m1->getConformer(), matchVect[2].second, matchVect[3].second, matchVect[4].second, matchVect[5].second, 0.0); ROMol m2(*m1); MolAlign::randomTransform(m2); ROMol m3(m2); unsigned int prbNAtoms = m2.getNumAtoms(); std::vector<double> prbLogpContribs(prbNAtoms); std::vector<double> prbMRContribs(prbNAtoms); std::vector<unsigned int> prbAtomTypes(prbNAtoms); std::vector<std::string> prbAtomTypeLabels(prbNAtoms); Descriptors::getCrippenAtomContribs(m2, prbLogpContribs, prbMRContribs, true, &prbAtomTypes, &prbAtomTypeLabels); MolAlign::O3A *o3a = new MolAlign::O3A(m2, *m1, &prbLogpContribs, &prbLogpContribs, MolAlign::O3A::CRIPPEN); TEST_ASSERT(o3a); o3a->align(); delete o3a; double d = (m2.getConformer().getAtomPos(cIdx) - m1->getConformer().getAtomPos(cIdx)).length(); TEST_ASSERT(feq(d, 0.0, 1)); MatchVectType constraintMap; constraintMap.push_back(std::make_pair(cIdx, nIdx)); o3a = new MolAlign::O3A(m3, *m1, &prbLogpContribs, &prbLogpContribs, MolAlign::O3A::CRIPPEN, -1, -1, false, 50, 0, &constraintMap); TEST_ASSERT(o3a); o3a->align(); delete o3a; d = (m3.getConformer().getAtomPos(cIdx) - m1->getConformer().getAtomPos(cIdx)).length(); TEST_ASSERT(feq(d, 7.0, 1.0)); delete m1; }
void testGithub308() { BOOST_LOG(rdErrorLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdErrorLog) << " Testing github 308: crash during MMFF parameterization ." << std::endl; ROMol *mol = SmilesToMol("FF"); TEST_ASSERT(DGeomHelpers::EmbedMolecule(*mol) >= 0); int needMore; ForceFields::ForceField *field = 0; TEST_ASSERT(mol); MMFF::MMFFMolProperties mmffMolProperties(*mol); TEST_ASSERT(mmffMolProperties.isValid()); field = MMFF::constructForceField(*mol); TEST_ASSERT(field); field->initialize(); needMore = field->minimize(200, 1.0e-6, 1.0e-3); TEST_ASSERT(!needMore); }
int MMFFOptimizeMolecule(ROMol &mol, std::string mmffVariant = "MMFF94", int maxIters = 200, double nonBondedThresh = 100.0, int confId = -1, bool ignoreInterfragInteractions = true) { int res = -1; MMFF::MMFFMolProperties mmffMolProperties(mol, mmffVariant); if (mmffMolProperties.isValid()) { ForceFields::ForceField *ff = MMFF::constructForceField(mol, &mmffMolProperties, nonBondedThresh, confId, ignoreInterfragInteractions); ff->initialize(); res = ff->minimize(maxIters); delete ff; } return res; }
void testMMFFBatch() { BOOST_LOG(rdErrorLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdErrorLog) << " Testing bulk MMFF (regression to check that things run)." << std::endl; ROMol *mol; ForceFields::ForceField *field; std::string pathName = getenv("RDBASE"); pathName += "/Code/GraphMol/ForceFieldHelpers/MMFF/test_data"; SDMolSupplier suppl(pathName + "/bulk.sdf"); int count = 0; mol = suppl.next(); while (mol && (!(suppl.atEnd()))) { ++count; std::string origMolBlock = MolToMolBlock(*mol); BOOST_LOG(rdErrorLog) << "Mol:" << count << std::endl; try { field = MMFF::constructForceField(*mol); } catch (...) { field = 0; } if (field) { field->initialize(); int failed = field->minimize(500); if (failed) { BOOST_LOG(rdErrorLog) << " not converged (code = " << failed << ")" << std::endl; std::cout << origMolBlock << "$$$$" << std::endl; std::cout << MolToMolBlock(*mol) << "$$$$" << std::endl; } delete field; } delete mol; mol = suppl.next(); } BOOST_LOG(rdErrorLog) << " done" << std::endl; }
void testIssue239(){ BOOST_LOG(rdErrorLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdErrorLog) << " Testing Issue239." << std::endl; RWMol *mol; int needMore; ForceFields::ForceField *field; double e1,e2; std::string pathName=getenv("RDBASE"); pathName += "/Code/GraphMol/ForceFieldHelpers/UFF/test_data"; mol = MolFileToMol(pathName+"/Issue239.mol",false); TEST_ASSERT(mol); MolOps::sanitizeMol(*mol); field=UFF::constructForceField(*mol); TEST_ASSERT(field); field->initialize(); needMore = field->minimize(200,1e-6,1e-3); e1 = field->calcEnergy(); needMore = field->minimize(200,1e-6,1e-3); e2 = field->calcEnergy(); TEST_ASSERT(feq(e2,e1,0.1)); delete mol; delete field; BOOST_LOG(rdErrorLog) << " done" << std::endl; }
ForceFields::ForceField *constructForceField( const BoundsMatrix &mmat, RDGeom::PointPtrVect &positions, const VECT_CHIRALSET &csets, double weightChiral, double weightFourthDim, std::map<std::pair<int, int>, double> *extraWeights, double basinSizeTol) { unsigned int N = mmat.numRows(); CHECK_INVARIANT(N == positions.size(), ""); ForceFields::ForceField *field = new ForceFields::ForceField(positions[0]->dimension()); for (unsigned int i = 0; i < N; i++) { field->positions().push_back(positions[i]); } for (unsigned int i = 1; i < N; i++) { for (unsigned int j = 0; j < i; j++) { double w = 1.0; double l = mmat.getLowerBound(i, j); double u = mmat.getUpperBound(i, j); bool includeIt = false; if (extraWeights) { std::map<std::pair<int, int>, double>::const_iterator mapIt; mapIt = extraWeights->find(std::make_pair(i, j)); if (mapIt != extraWeights->end()) { w = mapIt->second; includeIt = true; } } if (u - l <= basinSizeTol) { includeIt = true; } if (includeIt) { DistViolationContrib *contrib = new DistViolationContrib(field, i, j, u, l, w); field->contribs().push_back(ForceFields::ContribPtr(contrib)); } } } // now add chiral constraints if (weightChiral > 1.e-8) { for (VECT_CHIRALSET::const_iterator csi = csets.begin(); csi != csets.end(); csi++) { ChiralViolationContrib *contrib = new ChiralViolationContrib(field, csi->get(), weightChiral); field->contribs().push_back(ForceFields::ContribPtr(contrib)); } } // finally the contribution from the fourth dimension if we need to if ((field->dimension() == 4) && (weightFourthDim > 1.e-8)) { for (unsigned int i = 1; i < N; i++) { FourthDimContrib *contrib = new FourthDimContrib(field, i, weightFourthDim); field->contribs().push_back(ForceFields::ContribPtr(contrib)); } } return field; } // constructForceField
void testGitHubIssue62() { BOOST_LOG(rdErrorLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdErrorLog) << " Testing GitHubIssue62." << std::endl; std::string pathName=getenv("RDBASE"); pathName += "/Code/GraphMol/ForceFieldHelpers/UFF/test_data"; { double energyValues[] = { 38.687, 174.698, 337.986, 115.248, 2.482, 1.918, 10.165, 98.469, 39.078, 267.236, 15.747, 202.121, 205.539, 20.044, 218.986, 79.627 }; SmilesMolSupplier smiSupplier(pathName + "/Issue62.smi"); SDWriter *sdfWriter = new SDWriter(pathName + "/Issue62.sdf"); for (unsigned int i = 0; i < smiSupplier.length(); ++i) { ROMol *mol = MolOps::addHs(*(smiSupplier[i])); TEST_ASSERT(mol); std::string molName = ""; if (mol->hasProp(common_properties::_Name)) { mol->getProp(common_properties::_Name, molName); } DGeomHelpers::EmbedMolecule(*mol); ForceFields::ForceField *field = UFF::constructForceField(*mol); TEST_ASSERT(field); field->initialize(); int needMore = field->minimize(200, 1.e-6, 1.e-3); TEST_ASSERT(!needMore); sdfWriter->write(*mol); double e = field->calcEnergy(); BOOST_LOG(rdErrorLog) << molName << " " << e << std::endl; TEST_ASSERT(fabs(e - energyValues[i]) < 1.); } sdfWriter->close(); BOOST_LOG(rdErrorLog) << " done" << std::endl; } }
void testSFIssue1653802(){ BOOST_LOG(rdErrorLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdErrorLog) << " Testing SFIssue1653802." << std::endl; RWMol *mol; int needMore; ForceFields::ForceField *field; std::string pathName=getenv("RDBASE"); pathName += "/Code/GraphMol/ForceFieldHelpers/UFF/test_data"; mol = MolFileToMol(pathName+"/cyclobutadiene.mol",false); TEST_ASSERT(mol); MolOps::sanitizeMol(*mol); UFF::AtomicParamVect types; bool foundAll; boost::shared_array<boost::uint8_t> nbrMat; boost::tie(types,foundAll)=UFF::getAtomTypes(*mol); TEST_ASSERT(foundAll); TEST_ASSERT(types.size()==mol->getNumAtoms()); field=new ForceFields::ForceField(); UFF::Tools::addBonds(*mol,types,field); TEST_ASSERT(field->contribs().size()==8); nbrMat = UFF::Tools::buildNeighborMatrix(*mol); UFF::Tools::addAngles(*mol,types,field); TEST_ASSERT(field->contribs().size()==20); UFF::Tools::addTorsions(*mol,types,field); //std::cout << field->contribs().size() << std::endl; TEST_ASSERT(field->contribs().size()==36); UFF::Tools::addNonbonded(*mol,0,types,field,nbrMat); delete field; field = UFF::constructForceField(*mol); field->initialize(); needMore = field->minimize(200,1e-6,1e-3); TEST_ASSERT(!needMore); delete mol; delete field; BOOST_LOG(rdErrorLog) << " done" << std::endl; }
void testSFIssue1653802() { BOOST_LOG(rdErrorLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdErrorLog) << " Testing SFIssue1653802." << std::endl; RWMol *mol; int needMore; ForceFields::ForceField *field; std::string pathName = getenv("RDBASE"); pathName += "/Code/GraphMol/ForceFieldHelpers/MMFF/test_data"; mol = MolFileToMol(pathName + "/cyclobutadiene.mol", false); TEST_ASSERT(mol); MolOps::sanitizeMol(*mol); MMFF::MMFFMolProperties *mmffMolProperties = new MMFF::MMFFMolProperties(*mol); TEST_ASSERT(mmffMolProperties); boost::shared_array<boost::uint8_t> nbrMat; field = new ForceFields::ForceField(); MMFF::Tools::addBonds(*mol, mmffMolProperties, field); TEST_ASSERT(field->contribs().size() == 8); nbrMat = MMFF::Tools::buildNeighborMatrix(*mol); MMFF::Tools::addAngles(*mol, mmffMolProperties, field); TEST_ASSERT(field->contribs().size() == 20); MMFF::Tools::addTorsions(*mol, mmffMolProperties, field); // std::cout << field->contribs().size() << std::endl; TEST_ASSERT(field->contribs().size() == 36); MMFF::Tools::addVdW(*mol, 0, mmffMolProperties, field, nbrMat); delete field; field = MMFF::constructForceField(*mol); field->initialize(); needMore = field->minimize(200, 1.0e-6, 1.0e-3); TEST_ASSERT(!needMore); delete mol; delete field; delete mmffMolProperties; BOOST_LOG(rdErrorLog) << " done" << std::endl; }
void testUFFBuilder2(){ BOOST_LOG(rdErrorLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdErrorLog) << " Testing UFF builder+minimization." << std::endl; RWMol *mol; std::string key; int needMore; ForceFields::ForceField *field; std::string pathName=getenv("RDBASE"); pathName += "/Code/GraphMol/ForceFieldHelpers/UFF/test_data"; mol = MolFileToMol(pathName+"/small1.mol",false); TEST_ASSERT(mol); MolOps::sanitizeMol(*mol); field=UFF::constructForceField(*mol); TEST_ASSERT(field); field->initialize(); needMore = field->minimize(); TEST_ASSERT(!needMore); //std::cout << MolToMolBlock(mol); delete mol; delete field; mol = MolFileToMol(pathName+"/small2.mol",false); TEST_ASSERT(mol); MolOps::sanitizeMol(*mol); field=UFF::constructForceField(*mol); TEST_ASSERT(field); field->initialize(); needMore = field->minimize(150); TEST_ASSERT(!needMore); //std::cout << MolToMolBlock(mol); delete mol; delete field; mol = MolFileToMol(pathName+"/benzene.mol",false); TEST_ASSERT(mol); MolOps::sanitizeMol(*mol); field=UFF::constructForceField(*mol); TEST_ASSERT(field); field->initialize(); needMore = field->minimize(); TEST_ASSERT(!needMore); //std::cout << MolToMolBlock(mol); delete mol; delete field; mol = MolFileToMol(pathName+"/toluene.mol",false); TEST_ASSERT(mol); MolOps::sanitizeMol(*mol); field=UFF::constructForceField(*mol); TEST_ASSERT(field); field->initialize(); needMore = field->minimize(); TEST_ASSERT(!needMore); //std::cout << MolToMolBlock(mol); delete mol; delete field; mol = MolFileToMol(pathName+"/complex1.mol",false); TEST_ASSERT(mol); MolOps::sanitizeMol(*mol); field=UFF::constructForceField(*mol); TEST_ASSERT(field); field->initialize(); needMore = field->minimize(); TEST_ASSERT(!needMore); //std::cout << MolToMolBlock(mol); delete mol; delete field; BOOST_LOG(rdErrorLog) << " done" << std::endl; }
void testUFFBuilder1(){ BOOST_LOG(rdErrorLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdErrorLog) << " Testing UFF builder tools." << std::endl; ROMol *mol,*mol2; std::string key; UFF::AtomicParamVect types; bool foundAll; ForceFields::ForceField *field; boost::shared_array<boost::uint8_t> nbrMat; mol = SmilesToMol("CC(O)C"); Conformer *conf = new Conformer(mol->getNumAtoms()); int cid = static_cast<int>(mol->addConformer(conf, true)); TEST_ASSERT(mol); boost::tie(types,foundAll)=UFF::getAtomTypes(*mol); TEST_ASSERT(foundAll); TEST_ASSERT(types.size()==mol->getNumAtoms()); field=new ForceFields::ForceField(); UFF::Tools::addBonds(*mol,types,field); TEST_ASSERT(field->contribs().size()==3); nbrMat = UFF::Tools::buildNeighborMatrix(*mol); TEST_ASSERT(UFF::Tools::getTwoBitCell(nbrMat,0)==UFF::Tools::RELATION_1_X); TEST_ASSERT(UFF::Tools::getTwoBitCell(nbrMat,1)==UFF::Tools::RELATION_1_2); TEST_ASSERT(UFF::Tools::getTwoBitCell(nbrMat,2)==UFF::Tools::RELATION_1_3); TEST_ASSERT(UFF::Tools::getTwoBitCell(nbrMat,3)==UFF::Tools::RELATION_1_3); UFF::Tools::addAngles(*mol,types,field); TEST_ASSERT(field->contribs().size()==6); // there are no non-bonded terms here: UFF::Tools::addNonbonded(*mol,cid,types,field,nbrMat); TEST_ASSERT(field->contribs().size()==6); // and no torsions either, until we add Hs: UFF::Tools::addTorsions(*mol,types,field); TEST_ASSERT(field->contribs().size()==6); delete mol; delete field; mol = SmilesToMol("CCOC"); Conformer *conf2 = new Conformer(mol->getNumAtoms()); cid = static_cast<int>(mol->addConformer(conf2, true)); TEST_ASSERT(mol); boost::tie(types,foundAll)=UFF::getAtomTypes(*mol); TEST_ASSERT(foundAll); TEST_ASSERT(types.size()==mol->getNumAtoms()); field=new ForceFields::ForceField(); UFF::Tools::addBonds(*mol,types,field); TEST_ASSERT(field->contribs().size()==3); nbrMat = UFF::Tools::buildNeighborMatrix(*mol); TEST_ASSERT(UFF::Tools::getTwoBitCell(nbrMat,0)==UFF::Tools::RELATION_1_X); TEST_ASSERT(UFF::Tools::getTwoBitCell(nbrMat,1)==UFF::Tools::RELATION_1_2); TEST_ASSERT(UFF::Tools::getTwoBitCell(nbrMat,2)==UFF::Tools::RELATION_1_3); TEST_ASSERT(UFF::Tools::getTwoBitCell(nbrMat,3)==UFF::Tools::RELATION_1_X); UFF::Tools::addAngles(*mol,types,field); TEST_ASSERT(field->contribs().size()==5); UFF::Tools::addNonbonded(*mol,cid,types,field,nbrMat); TEST_ASSERT(field->contribs().size()==6); UFF::Tools::addTorsions(*mol,types,field); TEST_ASSERT(field->contribs().size()==7); delete mol; delete field; mol = SmilesToMol("CO"); Conformer *conf3 = new Conformer(mol->getNumAtoms()); cid = static_cast<int>(mol->addConformer(conf3, true)); TEST_ASSERT(mol); boost::tie(types,foundAll)=UFF::getAtomTypes(*mol); TEST_ASSERT(foundAll); TEST_ASSERT(types.size()==mol->getNumAtoms()); field=new ForceFields::ForceField(); UFF::Tools::addBonds(*mol,types,field); TEST_ASSERT(field->contribs().size()==1); nbrMat = UFF::Tools::buildNeighborMatrix(*mol); TEST_ASSERT(UFF::Tools::getTwoBitCell(nbrMat,0)==UFF::Tools::RELATION_1_X); TEST_ASSERT(UFF::Tools::getTwoBitCell(nbrMat,1)==UFF::Tools::RELATION_1_2); UFF::Tools::addAngles(*mol,types,field); TEST_ASSERT(field->contribs().size()==1); UFF::Tools::addNonbonded(*mol,cid,types,field,nbrMat); TEST_ASSERT(field->contribs().size()==1); UFF::Tools::addTorsions(*mol,types,field); TEST_ASSERT(field->contribs().size()==1); mol2 = MolOps::addHs(*mol); TEST_ASSERT(mol2->getNumAtoms()==6); delete field; boost::tie(types,foundAll)=UFF::getAtomTypes(*mol2); TEST_ASSERT(foundAll); TEST_ASSERT(types.size()==mol2->getNumAtoms()); field=new ForceFields::ForceField(); UFF::Tools::addBonds(*mol2,types,field); TEST_ASSERT(field->contribs().size()==5); nbrMat = UFF::Tools::buildNeighborMatrix(*mol2); UFF::Tools::addAngles(*mol2,types,field); TEST_ASSERT(field->contribs().size()==12); UFF::Tools::addNonbonded(*mol2,cid,types,field,nbrMat); TEST_ASSERT(field->contribs().size()==15); UFF::Tools::addTorsions(*mol2,types,field); TEST_ASSERT(field->contribs().size()==18); delete mol2; delete mol; delete field; BOOST_LOG(rdErrorLog) << " done" << std::endl; }
void testMMFFBuilder1() { BOOST_LOG(rdErrorLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdErrorLog) << " Testing MMFF builder tools." << std::endl; ROMol *mol, *mol2; ForceFields::ForceField *field; boost::shared_array<boost::uint8_t> nbrMat; mol = SmilesToMol("CC(O)C"); Conformer *conf = new Conformer(mol->getNumAtoms()); int cid = static_cast<int>(mol->addConformer(conf, true)); TEST_ASSERT(mol); MMFF::MMFFMolProperties *mmffMolProperties = new MMFF::MMFFMolProperties(*mol); TEST_ASSERT(mmffMolProperties); TEST_ASSERT(mmffMolProperties->isValid()); field = new ForceFields::ForceField(); MMFF::Tools::addBonds(*mol, mmffMolProperties, field); TEST_ASSERT(field->contribs().size() == 3); nbrMat = MMFF::Tools::buildNeighborMatrix(*mol); // the neighbor matrix is an upper triangular matrix // position indices are as follows: // 0 1 2 3 // 4 5 6 // 7 8 // 9 TEST_ASSERT(MMFF::Tools::twoBitCellPos(mol->getNumAtoms(), 1, 1) == 4); TEST_ASSERT(MMFF::Tools::twoBitCellPos(mol->getNumAtoms(), 2, 1) == 5); TEST_ASSERT(MMFF::Tools::twoBitCellPos(mol->getNumAtoms(), 1, 2) == 5); TEST_ASSERT(MMFF::Tools::getTwoBitCell(nbrMat, 0) == MMFF::Tools::RELATION_1_X); TEST_ASSERT(MMFF::Tools::getTwoBitCell(nbrMat, 1) == MMFF::Tools::RELATION_1_2); TEST_ASSERT(MMFF::Tools::getTwoBitCell(nbrMat, 2) == MMFF::Tools::RELATION_1_3); TEST_ASSERT(MMFF::Tools::getTwoBitCell(nbrMat, 3) == MMFF::Tools::RELATION_1_3); MMFF::Tools::addAngles(*mol, mmffMolProperties, field); TEST_ASSERT(field->contribs().size() == 6); // there are no non-bonded terms here: MMFF::Tools::addVdW(*mol, cid, mmffMolProperties, field, nbrMat); TEST_ASSERT(field->contribs().size() == 6); // and no torsions either, until we add Hs: MMFF::Tools::addTorsions(*mol, mmffMolProperties, field); TEST_ASSERT(field->contribs().size() == 6); delete mol; delete field; delete mmffMolProperties; mol = SmilesToMol("CCOC"); Conformer *conf2 = new Conformer(mol->getNumAtoms()); cid = static_cast<int>(mol->addConformer(conf2, true)); TEST_ASSERT(mol); mmffMolProperties = new MMFF::MMFFMolProperties(*mol); TEST_ASSERT(mmffMolProperties); TEST_ASSERT(mmffMolProperties->isValid()); field = new ForceFields::ForceField(); MMFF::Tools::addBonds(*mol, mmffMolProperties, field); TEST_ASSERT(field->contribs().size() == 3); nbrMat = MMFF::Tools::buildNeighborMatrix(*mol); TEST_ASSERT(MMFF::Tools::getTwoBitCell(nbrMat, 0) == MMFF::Tools::RELATION_1_X); TEST_ASSERT(MMFF::Tools::getTwoBitCell(nbrMat, 1) == MMFF::Tools::RELATION_1_2); TEST_ASSERT(MMFF::Tools::getTwoBitCell(nbrMat, 2) == MMFF::Tools::RELATION_1_3); TEST_ASSERT(MMFF::Tools::getTwoBitCell(nbrMat, 3) == MMFF::Tools::RELATION_1_4); MMFF::Tools::addAngles(*mol, mmffMolProperties, field); TEST_ASSERT(field->contribs().size() == 5); MMFF::Tools::addVdW(*mol, cid, mmffMolProperties, field, nbrMat); TEST_ASSERT(field->contribs().size() == 6); MMFF::Tools::addTorsions(*mol, mmffMolProperties, field); TEST_ASSERT(field->contribs().size() == 7); delete mol; delete field; delete mmffMolProperties; mol = SmilesToMol("CO"); Conformer *conf3 = new Conformer(mol->getNumAtoms()); cid = static_cast<int>(mol->addConformer(conf3, true)); TEST_ASSERT(mol); mmffMolProperties = new MMFF::MMFFMolProperties(*mol); TEST_ASSERT(mmffMolProperties); TEST_ASSERT(mmffMolProperties->isValid()); field = new ForceFields::ForceField(); MMFF::Tools::addBonds(*mol, mmffMolProperties, field); TEST_ASSERT(field->contribs().size() == 1); nbrMat = MMFF::Tools::buildNeighborMatrix(*mol); TEST_ASSERT(MMFF::Tools::getTwoBitCell(nbrMat, 0) == MMFF::Tools::RELATION_1_X); TEST_ASSERT(MMFF::Tools::getTwoBitCell(nbrMat, 1) == MMFF::Tools::RELATION_1_2); MMFF::Tools::addAngles(*mol, mmffMolProperties, field); TEST_ASSERT(field->contribs().size() == 1); MMFF::Tools::addVdW(*mol, cid, mmffMolProperties, field, nbrMat); TEST_ASSERT(field->contribs().size() == 1); MMFF::Tools::addTorsions(*mol, mmffMolProperties, field); TEST_ASSERT(field->contribs().size() == 1); mol2 = MolOps::addHs(*mol); TEST_ASSERT(mol2->getNumAtoms() == 6); delete field; delete mmffMolProperties; mmffMolProperties = new MMFF::MMFFMolProperties(*mol2); TEST_ASSERT(mmffMolProperties); TEST_ASSERT(mmffMolProperties->isValid()); field = new ForceFields::ForceField(); MMFF::Tools::addBonds(*mol2, mmffMolProperties, field); TEST_ASSERT(field->contribs().size() == 5); nbrMat = MMFF::Tools::buildNeighborMatrix(*mol2); MMFF::Tools::addAngles(*mol2, mmffMolProperties, field); TEST_ASSERT(field->contribs().size() == 12); MMFF::Tools::addVdW(*mol2, cid, mmffMolProperties, field, nbrMat); TEST_ASSERT(field->contribs().size() == 15); MMFF::Tools::addTorsions(*mol2, mmffMolProperties, field); TEST_ASSERT(field->contribs().size() == 18); delete mol2; delete mol; delete field; delete mmffMolProperties; BOOST_LOG(rdErrorLog) << " done" << std::endl; }
ForceFields::ForceField *construct3DForceField( const BoundsMatrix &mmat, RDGeom::Point3DPtrVect &positions, const std::vector<std::pair<int, int> > &bonds, const std::vector<std::vector<int> > &angles, const std::vector<std::vector<int> > &expTorsionAtoms, const std::vector<std::pair<std::vector<int>, std::vector<double> > > & expTorsionAngles, const std::vector<std::vector<int> > &improperAtoms, const std::vector<int> &atomNums) { (void)atomNums; unsigned int N = mmat.numRows(); CHECK_INVARIANT(N == positions.size(), ""); CHECK_INVARIANT(expTorsionAtoms.size() == expTorsionAngles.size(), ""); ForceFields::ForceField *field = new ForceFields::ForceField(positions[0]->dimension()); for (unsigned int i = 0; i < N; ++i) { field->positions().push_back(positions[i]); } // keep track which atoms are 1,2- or 1,3-restrained boost::dynamic_bitset<> atomPairs(N * N); // torsion constraints for (unsigned int t = 0; t < expTorsionAtoms.size(); ++t) { int i = expTorsionAtoms[t][0]; int j = expTorsionAtoms[t][1]; int k = expTorsionAtoms[t][2]; int l = expTorsionAtoms[t][3]; if (i < j) atomPairs[i * N + j] = 1; else atomPairs[j * N + i] = 1; // expTorsionAngles[t][0] = (signs, V's) ForceFields::CrystalFF::TorsionAngleContribM6 *contrib = new ForceFields::CrystalFF::TorsionAngleContribM6( field, i, j, k, l, expTorsionAngles[t].second, expTorsionAngles[t].first); field->contribs().push_back(ForceFields::ContribPtr(contrib)); } // torsion constraints // improper torsions / out-of-plane bend / inversion double oobForceScalingFactor = 10.0; for (unsigned int t = 0; t < improperAtoms.size(); ++t) { std::vector<int> n(4); for (unsigned int i = 0; i < 3; ++i) { n[1] = 1; switch (i) { case 0: n[0] = 0; n[2] = 2; n[3] = 3; break; case 1: n[0] = 0; n[2] = 3; n[3] = 2; break; case 2: n[0] = 2; n[2] = 3; n[3] = 0; break; } ForceFields::UFF::InversionContrib *contrib = new ForceFields::UFF::InversionContrib( field, improperAtoms[t][n[0]], improperAtoms[t][n[1]], improperAtoms[t][n[2]], improperAtoms[t][n[3]], improperAtoms[t][4], improperAtoms[t][5], oobForceScalingFactor); field->contribs().push_back(ForceFields::ContribPtr(contrib)); } } double fdist = 100.0; // force constant // 1,2 distance constraints std::vector<std::pair<int, int> >::const_iterator bi; for (bi = bonds.begin(); bi != bonds.end(); ++bi) { unsigned int i = bi->first; unsigned int j = bi->second; if (i < j) atomPairs[i * N + j] = 1; else atomPairs[j * N + i] = 1; double d = ((*positions[i]) - (*positions[j])).length(); double l = d - 0.01; double u = d + 0.01; ForceFields::UFF::DistanceConstraintContrib *contrib = new ForceFields::UFF::DistanceConstraintContrib(field, i, j, l, u, fdist); field->contribs().push_back(ForceFields::ContribPtr(contrib)); } // 1,3 distance constraints for (unsigned int a = 0; a < angles.size(); ++a) { unsigned int i = angles[a][0]; unsigned int j = angles[a][1]; unsigned int k = angles[a][2]; if (i < j) atomPairs[i * N + j] = 1; else atomPairs[j * N + i] = 1; // check for triple bonds if (angles[a][3]) { ForceFields::UFF::AngleConstraintContrib *contrib = new ForceFields::UFF::AngleConstraintContrib(field, i, j, k, 179.0, 180.0, fdist); field->contribs().push_back(ForceFields::ContribPtr(contrib)); } else { double d = ((*positions[i]) - (*positions[k])).length(); double l = d - 0.01; double u = d + 0.01; ForceFields::UFF::DistanceConstraintContrib *contrib = new ForceFields::UFF::DistanceConstraintContrib(field, i, k, l, u, fdist); field->contribs().push_back(ForceFields::ContribPtr(contrib)); } } // minimum distance for all other atom pairs fdist = 10.0; for (unsigned int i = 1; i < N; ++i) { for (unsigned int j = 0; j < i; ++j) { if (!atomPairs[j * N + i]) { double l = mmat.getLowerBound(i, j); double u = mmat.getUpperBound(i, j); ForceFields::UFF::DistanceConstraintContrib *contrib = new ForceFields::UFF::DistanceConstraintContrib(field, i, j, l, u, fdist); field->contribs().push_back(ForceFields::ContribPtr(contrib)); } } } return field; } // construct3DForceField
PyObject *embedBoundsMatrix(python::object boundsMatArg,int maxIters=10, bool randomizeOnFailure=false,int numZeroFail=2, python::list weights=python::list(), int randomSeed=-1){ PyObject *boundsMatObj = boundsMatArg.ptr(); if(!PyArray_Check(boundsMatObj)) throw_value_error("Argument isn't an array"); PyArrayObject *boundsMat=reinterpret_cast<PyArrayObject *>(boundsMatObj); // get the dimensions of the array unsigned int nrows = boundsMat->dimensions[0]; unsigned int ncols = boundsMat->dimensions[1]; if(nrows!=ncols) throw_value_error("The array has to be square"); if(nrows<=0) throw_value_error("The array has to have a nonzero size"); if (boundsMat->descr->type_num != PyArray_DOUBLE) throw_value_error("Only double arrays are currently supported"); unsigned int dSize = nrows*nrows; double *cData = new double[dSize]; double *inData = reinterpret_cast<double *>(boundsMat->data); memcpy(static_cast<void *>(cData), static_cast<const void *>(inData), dSize*sizeof(double)); DistGeom::BoundsMatrix::DATA_SPTR sdata(cData); DistGeom::BoundsMatrix bm(nrows,sdata); RDGeom::Point3D *positions=new RDGeom::Point3D[nrows]; std::vector<RDGeom::Point *> posPtrs; for (unsigned int i = 0; i < nrows; i++) { posPtrs.push_back(&positions[i]); } RDNumeric::DoubleSymmMatrix distMat(nrows, 0.0); // ---- ---- ---- ---- ---- ---- ---- ---- ---- // start the embedding: bool gotCoords=false; for(int iter=0;iter<maxIters && !gotCoords;iter++){ // pick a random distance matrix DistGeom::pickRandomDistMat(bm,distMat,randomSeed); // and embed it: gotCoords=DistGeom::computeInitialCoords(distMat,posPtrs,randomizeOnFailure, numZeroFail,randomSeed); // update the seed: if(randomSeed>=0) randomSeed+=iter*999; } if(gotCoords){ std::map<std::pair<int,int>,double> weightMap; unsigned int nElems=PySequence_Size(weights.ptr()); for(unsigned int entryIdx=0;entryIdx<nElems;entryIdx++){ PyObject *entry=PySequence_GetItem(weights.ptr(),entryIdx); if(!PySequence_Check(entry) || PySequence_Size(entry)!=3){ throw_value_error("weights argument must be a sequence of 3-sequences"); } int idx1=PyInt_AsLong(PySequence_GetItem(entry,0)); int idx2=PyInt_AsLong(PySequence_GetItem(entry,1)); double w=PyFloat_AsDouble(PySequence_GetItem(entry,2)); weightMap[std::make_pair(idx1,idx2)]=w; } DistGeom::VECT_CHIRALSET csets; ForceFields::ForceField *field = DistGeom::constructForceField(bm,posPtrs,csets,0.0, 0.0, &weightMap); CHECK_INVARIANT(field,"could not build dgeom force field"); field->initialize(); if(field->calcEnergy()>1e-5){ int needMore=1; while(needMore){ needMore=field->minimize(); } } delete field; } else { throw_value_error("could not embed matrix"); } // ---- ---- ---- ---- ---- ---- ---- ---- ---- // construct the results matrix: npy_intp dims[2]; dims[0] = nrows; dims[1] = 3; PyArrayObject *res = (PyArrayObject *)PyArray_SimpleNew(2,dims,NPY_DOUBLE); double *resData=reinterpret_cast<double *>(res->data); for(unsigned int i=0;i<nrows;i++){ unsigned int iTab=i*3; for (unsigned int j = 0; j < 3; ++j) { resData[iTab + j]=positions[i][j]; //.x; } } delete [] positions; return PyArray_Return(res); }
void testSFIssue2378119() { BOOST_LOG(rdErrorLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdErrorLog) << " Testing SFIssue2378119." << std::endl; std::string pathName = getenv("RDBASE"); pathName += "/Code/GraphMol/ForceFieldHelpers/MMFF/test_data"; { RWMol *mol = MolFileToMol(pathName + "/Issue2378119.mol"); TEST_ASSERT(mol); ForceFields::ForceField *field = MMFF::constructForceField(*mol); TEST_ASSERT(field); field->initialize(); double e1 = field->calcEnergy(); TEST_ASSERT(e1 > 0.0 && e1 < 1.0e12); int needMore = field->minimize(200, 1.0e-6, 1.0e-3); TEST_ASSERT(!needMore); double e2 = field->calcEnergy(); TEST_ASSERT(e2 < e1); delete mol; delete field; } { RWMol *mol = MolFileToMol(pathName + "/Issue2378119.2.mol"); TEST_ASSERT(mol); ForceFields::ForceField *field = MMFF::constructForceField(*mol); TEST_ASSERT(field); field->initialize(); double e1 = field->calcEnergy(); TEST_ASSERT(e1 == 0.0); int needMore = field->minimize(200, 1.0e-6, 1.0e-3); TEST_ASSERT(!needMore); double e2 = field->calcEnergy(); TEST_ASSERT(e2 == e1); delete mol; delete field; } { RWMol *mol = MolFileToMol(pathName + "/Issue2378119.2.mol"); TEST_ASSERT(mol); ForceFields::ForceField *field = MMFF::constructForceField(*mol, 100.0, -1, false); TEST_ASSERT(field); field->initialize(); double e1 = field->calcEnergy(); TEST_ASSERT(e1 > 0.0 && e1 < 1.0e12); int needMore = field->minimize(200, 1.0e-6, 1.0e-3); TEST_ASSERT(!needMore); double e2 = field->calcEnergy(); TEST_ASSERT(e2 < e1); delete mol; delete field; } BOOST_LOG(rdErrorLog) << " done" << std::endl; }
ForceFields::ForceField *constructPlain3DForceField( const BoundsMatrix &mmat, RDGeom::Point3DPtrVect &positions, const std::vector<std::pair<int, int> > &bonds, const std::vector<std::vector<int> > &angles, const std::vector<std::vector<int> > &expTorsionAtoms, const std::vector<std::pair<std::vector<int>, std::vector<double> > > & expTorsionAngles, const std::vector<int> &atomNums) { (void)atomNums; unsigned int N = mmat.numRows(); CHECK_INVARIANT(N == positions.size(), ""); CHECK_INVARIANT(expTorsionAtoms.size() == expTorsionAngles.size(), ""); ForceFields::ForceField *field = new ForceFields::ForceField(positions[0]->dimension()); for (unsigned int i = 0; i < N; ++i) { field->positions().push_back(positions[i]); } // keep track which atoms are 1,2- or 1,3-restrained boost::dynamic_bitset<> atomPairs(N * N); // torsion constraints for (unsigned int t = 0; t < expTorsionAtoms.size(); ++t) { int i = expTorsionAtoms[t][0]; int j = expTorsionAtoms[t][1]; int k = expTorsionAtoms[t][2]; int l = expTorsionAtoms[t][3]; if (i < j) atomPairs[i * N + j] = 1; else atomPairs[j * N + i] = 1; // expTorsionAngles[t][0] = (signs, V's) ForceFields::CrystalFF::TorsionAngleContribM6 *contrib = new ForceFields::CrystalFF::TorsionAngleContribM6( field, i, j, k, l, expTorsionAngles[t].second, expTorsionAngles[t].first); field->contribs().push_back(ForceFields::ContribPtr(contrib)); } // torsion constraints double fdist = 100.0; // force constant // 1,2 distance constraints std::vector<std::pair<int, int> >::const_iterator bi; for (bi = bonds.begin(); bi != bonds.end(); ++bi) { unsigned int i = bi->first; unsigned int j = bi->second; if (i < j) atomPairs[i * N + j] = 1; else atomPairs[j * N + i] = 1; double d = ((*positions[i]) - (*positions[j])).length(); double l = d - 0.01; double u = d + 0.01; ForceFields::UFF::DistanceConstraintContrib *contrib = new ForceFields::UFF::DistanceConstraintContrib(field, i, j, l, u, fdist); field->contribs().push_back(ForceFields::ContribPtr(contrib)); } // 1,3 distance constraints for (unsigned int a = 1; a < angles.size(); ++a) { unsigned int i = angles[a][0]; unsigned int j = angles[a][2]; if (i < j) atomPairs[i * N + j] = 1; else atomPairs[j * N + i] = 1; double d = ((*positions[i]) - (*positions[j])).length(); double l = d - 0.01; double u = d + 0.01; ForceFields::UFF::DistanceConstraintContrib *contrib = new ForceFields::UFF::DistanceConstraintContrib(field, i, j, l, u, fdist); field->contribs().push_back(ForceFields::ContribPtr(contrib)); } // minimum distance for all other atom pairs fdist = 10.0; for (unsigned int i = 1; i < N; ++i) { for (unsigned int j = 0; j < i; ++j) { if (!atomPairs[j * N + i]) { double l = mmat.getLowerBound(i, j); double u = mmat.getUpperBound(i, j); ForceFields::UFF::DistanceConstraintContrib *contrib = new ForceFields::UFF::DistanceConstraintContrib(field, i, j, l, u, fdist); field->contribs().push_back(ForceFields::ContribPtr(contrib)); } } } return field; } // constructPlain3DForceField
void testTorsionAngleM6() { std::cerr << "-------------------------------------" << std::endl; std::cerr << " Test CrystalFF torsional term." << std::endl; ForceFields::ForceField ff; Point3D p1, p2, p3, p4; RDGeom::PointPtrVect &ps = ff.positions(); ps.push_back(&p1); ps.push_back(&p2); ps.push_back(&p3); ps.push_back(&p4); ForceFields::CrystalFF::TorsionAngleContribM6 *contrib; // ------- ------- ------- ------- ------- ------- ------- // Basic SP3 - SP3 // ------- ------- ------- ------- ------- ------- ------- // [!#1:1][CX4H2:2]!@[CX4H2:3][!#1:4] 1 0.0 1 0.0 1 4.0 1 0.0 1 0.0 1 0.0 std::vector<int> signs(6, 1); std::vector<double> v(6, 0.0); v[2] = 4.0; contrib = new ForceFields::CrystalFF::TorsionAngleContribM6(&ff, 0, 1, 2, 3, v, signs); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); p1.x = 0; p1.y = 1.5; p1.z = 0; p2.x = 0.0; p2.y = 0.0; p2.z = 0.0; p3.x = 1.5; p3.y = 0.0; p3.z = 0.0; p4.x = 1.5; p4.y = 0.0; p4.z = 1.5; ff.initialize(); ff.minimize(10, 1e-8, 1e-8); double cosPhi = ForceFields::MMFF::Utils::calcTorsionCosPhi( *(RDGeom::Point3D *)ff.positions()[0], *(RDGeom::Point3D *)ff.positions()[1], *(RDGeom::Point3D *)ff.positions()[2], *(RDGeom::Point3D *)ff.positions()[3]); TEST_ASSERT(RDKit::feq(cosPhi, 0.5, 1e-4)); // ------- ------- ------- ------- ------- ------- ------- // Basic SP2 - SP2 // ------- ------- ------- ------- ------- ------- ------- signs[1] = -1; v[2] = 0.0; v[1] = 7.0; ff.contribs().pop_back(); contrib = new ForceFields::CrystalFF::TorsionAngleContribM6(&ff, 0, 1, 2, 3, v, signs); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); p1.x = 0; p1.y = 1.5; p1.z = 0.1; p2.x = 0.0; p2.y = 0.0; p2.z = 0.0; p3.x = 1.5; p3.y = 0.0; p3.z = 0.0; p4.x = 1.5; p4.y = 0.2; p4.z = 1.5; ff.initialize(); ff.minimize(10, 1e-8, 1e-8); cosPhi = ForceFields::MMFF::Utils::calcTorsionCosPhi( *(RDGeom::Point3D *)ff.positions()[0], *(RDGeom::Point3D *)ff.positions()[1], *(RDGeom::Point3D *)ff.positions()[2], *(RDGeom::Point3D *)ff.positions()[3]); TEST_ASSERT(RDKit::feq(cosPhi, 1.0, 1e-4)); }