// $Id$ // // Copyright (C) 2004-2008 Greg Landrum and Rational Discovery LLC // // @@ All Rights Reserved @@ // This file is part of the RDKit. // The contents are covered by the terms of the BSD license // which is included in the file license.txt, found at the root // of the RDKit source tree. // #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace RDGeom; void test1(){ std::cerr << "-------------------------------------" << std::endl; std::cerr << "Unit tests for force field basics." << std::endl; ForceFields::ForceField ff; TEST_ASSERT(ff.dimension() ==3 ); Point3D p1(0,0,0),p2(1,0,0),p3(2,0,0),p4(0,1,0); RDGeom::PointPtrVect &ps=ff.positions(); ps.push_back(&p1); ps.push_back(&p2); ps.push_back(&p3); ps.push_back(&p4); #if 0 Point3D f1,f2,f3,f4; RDGeom::PointPtrVect &fs=ff.forces(); fs.push_back(&f1); fs.push_back(&f2); fs.push_back(&f3); fs.push_back(&f4); #endif TEST_ASSERT(ff.positions().size()==4); //TEST_ASSERT(ff.forces().size()==4); ff.initialize(); TEST_ASSERT(RDKit::feq(ff.distance(0,1),1.0)); TEST_ASSERT(RDKit::feq(ff.distance(1,0),1.0)); TEST_ASSERT(RDKit::feq(ff.distance(0,0),0.0)); TEST_ASSERT(RDKit::feq(ff.distance(0,2),2.0)); TEST_ASSERT(RDKit::feq(ff.distance(2,0),2.0)); TEST_ASSERT(RDKit::feq(ff.distance(0,3),1.0)); TEST_ASSERT(RDKit::feq(ff.distance(3,0),1.0)); TEST_ASSERT(RDKit::feq(ff.distance(3,3),0.0)); TEST_ASSERT(RDKit::feq(ff.distance(1,2),1.0)); TEST_ASSERT(RDKit::feq(ff.distance(2,1),1.0)); std::cerr << " done" << std::endl; } void testUFF1(){ std::cerr << "-------------------------------------" << std::endl; std::cerr << "Unit tests for basics of UFF bond-stretch terms." << std::endl; ForceFields::UFF::AtomicParams p1,p2; double restLen,forceConstant; // sp3 carbon: p1.r1 = .757; p1.Z1 = 1.912; p1.GMP_Xi = 5.343; // sp3 - sp3: checks basics restLen=ForceFields::UFF::Utils::calcBondRestLength(1.0,&p1,&p1); TEST_ASSERT(RDKit::feq(restLen,1.514)); forceConstant=ForceFields::UFF::Utils::calcBondForceConstant(restLen,&p1,&p1); TEST_ASSERT(RDKit::feq(forceConstant,699.5918)); // sp2 carbon: p2.r1 = .732; p2.Z1 = 1.912; p2.GMP_Xi = 5.343; // sp2 - sp2: checks rBO restLen=ForceFields::UFF::Utils::calcBondRestLength(2.0,&p2,&p2); TEST_ASSERT(RDKit::feq(restLen,1.32883,1e-5)); forceConstant=ForceFields::UFF::Utils::calcBondForceConstant(restLen,&p2,&p2); TEST_ASSERT(RDKit::feq(forceConstant,1034.69,1e-2)); // sp3 nitrogen: p2.r1 = .700; p2.Z1 = 2.544; p2.GMP_Xi = 6.899; // Csp3 - Nsp3: checks rEN restLen=ForceFields::UFF::Utils::calcBondRestLength(1.0,&p1,&p2); TEST_ASSERT(RDKit::feq(restLen,1.462929,1e-5)); forceConstant=ForceFields::UFF::Utils::calcBondForceConstant(restLen,&p1,&p2); TEST_ASSERT(RDKit::feq(forceConstant,1031.77,1e-2)); // amide bond: check we can reproduce values from the UFF paper: // C_R: p1.r1 = .729; p1.Z1 = 1.912; p1.GMP_Xi = 5.343; // N_R: p2.r1 = .699; p2.Z1 = 2.544; p2.GMP_Xi = 6.899; restLen=ForceFields::UFF::Utils::calcBondRestLength(ForceFields::UFF::Params::amideBondOrder,&p1,&p2); TEST_ASSERT(RDKit::feq(restLen,1.368,1e-3)); // NOTE: the paper has 1.366 forceConstant=ForceFields::UFF::Utils::calcBondForceConstant(restLen,&p1,&p2); TEST_ASSERT(RDKit::feq(forceConstant,1260.,1)); // NOTE: the paper has 1293 std::cerr << " done" << std::endl; } void testUFF2(){ std::cerr << "-------------------------------------" << std::endl; std::cerr << "Unit tests for UFF bond-stretch terms." << std::endl; ForceFields::ForceField ff; Point3D p1(0,0,0),p2(1.514,0,0); RDGeom::PointPtrVect &ps=ff.positions(); ps.push_back(&p1); ps.push_back(&p2); ForceFields::UFF::AtomicParams param1; // sp3 carbon: param1.r1 = .757; param1.Z1 = 1.912; param1.GMP_Xi = 5.343; // C_3 - C_3, r0=1.514, k01=699.5918 ForceFields::ForceFieldContrib *bs; bs = new ForceFields::UFF::BondStretchContrib(&ff,0,1,1,¶m1,¶m1); ff.contribs().push_back(ForceFields::ContribPtr(bs)); ff.initialize(); double *p,*g; p = new double[6]; g = new double[6]; for(int i=0;i<6;i++){ p[i] = 0.0; g[i] = 0.0; } double E; // edge case: zero bond length: E=bs->getEnergy(p); TEST_ASSERT(E>0.0); bs->getGrad(p,g); for(int i=0;i<6;i++){ TEST_ASSERT(fabs(g[i])>0.0); } p[0] = 0; p[3] = 1.514; for(int i=0;i<6;i++){ g[i] = 0.0; } ff.initialize(); E=bs->getEnergy(p); TEST_ASSERT(RDKit::feq(E,0.0)); bs->getGrad(p,g); for(int i=0;i<6;i++){ TEST_ASSERT(RDKit::feq(g[i],0.0)); } (*ff.positions()[1])[0] = 1.814; p[3] = 1.814; ff.initialize(); E=bs->getEnergy(p); TEST_ASSERT(RDKit::feq(E,31.4816)); bs->getGrad(p,g); TEST_ASSERT(RDKit::feq(g[0],-209.8775)); TEST_ASSERT(RDKit::feq(g[3],209.8775)); TEST_ASSERT(RDKit::feq(g[1],0.0)); TEST_ASSERT(RDKit::feq(g[2],0.0)); TEST_ASSERT(RDKit::feq(g[4],0.0)); TEST_ASSERT(RDKit::feq(g[5],0.0)); // try a different axis: for(int i=0;i<6;i++){ g[i] = 0.0; p[i] = 0.0; } ff.initialize(); (*ff.positions()[1])[0] = 0.0; (*ff.positions()[1])[2] = 1.814; p[5] = 1.814; E=bs->getEnergy(p); TEST_ASSERT(RDKit::feq(E,31.4816)); bs->getGrad(p,g); TEST_ASSERT(RDKit::feq(g[2],-209.8775)); TEST_ASSERT(RDKit::feq(g[5],209.8775)); TEST_ASSERT(RDKit::feq(g[0],0.0)); TEST_ASSERT(RDKit::feq(g[1],0.0)); TEST_ASSERT(RDKit::feq(g[3],0.0)); TEST_ASSERT(RDKit::feq(g[4],0.0)); // try a bit of minimization RDGeom::Point3D d; ff.initialize(); (*ff.positions()[1])[2] = 0.0; (*ff.positions()[1])[0] = 1.814; ff.minimize(10,1e-8); d=*(RDGeom::Point3D*)ff.positions()[0] - *(RDGeom::Point3D*)ff.positions()[1]; TEST_ASSERT(RDKit::feq(d.length(),1.514,1e-3)); // minimize in "3D" ff.initialize(); (*ff.positions()[1])[2] = 1.1; (*ff.positions()[1])[1] = 0.9; (*ff.positions()[1])[0] = 1.00; ff.minimize(10,1e-8); d=*(RDGeom::Point3D*)ff.positions()[0] - *(RDGeom::Point3D*)ff.positions()[1]; TEST_ASSERT(RDKit::feq(d.length(),1.514,1e-3)); delete [] p; delete [] g; std::cerr << " done" << std::endl; } void testUFF3(){ std::cerr << "-------------------------------------" << std::endl; std::cerr << "Unit tests for basics of UFF angle terms." << std::endl; ForceFields::UFF::AtomicParams p1,p2,p3; double restLen,forceConstant; // sp3 carbon: p3.r1 = .757; p3.Z1 = 1.912; p3.GMP_Xi = 5.343; p3.theta0 = 109.47*M_PI/180.0; // sp3 - sp3: checks basics restLen=ForceFields::UFF::Utils::calcBondRestLength(1.0,&p3,&p3); TEST_ASSERT(RDKit::feq(restLen,1.514)); // C_3 - C_3 - C_3 forceConstant=ForceFields::UFF::Utils::calcAngleForceConstant(p3.theta0,1,1,&p3,&p3,&p3); //TEST_ASSERT(RDKit::feq(forceConstant,699.5918)); // amide bond bend: // C_R - N_R - C_3 // C_R: p1.r1 = .729; p1.Z1 = 1.912; p1.GMP_Xi = 5.343; // N_R: p2.r1 = .699; p2.Z1 = 2.544; p2.GMP_Xi = 6.899; p2.theta0 = 120.0*M_PI/180.; restLen=ForceFields::UFF::Utils::calcBondRestLength(ForceFields::UFF::Params::amideBondOrder,&p1,&p2); TEST_ASSERT(RDKit::feq(restLen,1.368,1e-3)); restLen=ForceFields::UFF::Utils::calcBondRestLength(1.0,&p2,&p3); TEST_ASSERT(RDKit::feq(restLen,1.462,1e-3)); forceConstant=ForceFields::UFF::Utils::calcAngleForceConstant(p2.theta0,ForceFields::UFF::Params::amideBondOrder,1, &p1,&p2,&p3); TEST_ASSERT(RDKit::feq(forceConstant,123.5,1e-1)); // paper has 105.5 std::cerr << " done" << std::endl; } void testUFF4(){ std::cerr << "-------------------------------------" << std::endl; std::cerr << "Unit tests for UFF angle-bend terms." << std::endl; ForceFields::ForceField ff; Point3D p1(1.514,0,0),p2(0,0,0),p3(0.1,1.5,0); RDGeom::PointPtrVect &ps=ff.positions(); ps.push_back(&p1); ps.push_back(&p2); ps.push_back(&p3); ForceFields::UFF::AtomicParams param1; // sp3 carbon: param1.r1 = .757; param1.Z1 = 1.912; param1.GMP_Xi = 5.343; // cheat to get the angle to 90 so that testing is easier: param1.theta0 = 90.0*M_PI/180.; // C_3 - C_3, r0=1.514, k01=699.5918 ForceFields::ForceFieldContrib *contrib; contrib = new ForceFields::UFF::BondStretchContrib(&ff,0,1,1,¶m1,¶m1); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::BondStretchContrib(&ff,1,2,1,¶m1,¶m1); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::AngleBendContrib(&ff,0,1,2,1,1,¶m1,¶m1,¶m1); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); RDGeom::Point3D d,v1,v2; double theta; #if 1 // ------- ------- ------- ------- ------- ------- ------- // try a bit of minimization ff.initialize(); ff.minimize(10,1e-8,1e-8); v1=*(RDGeom::Point3D*)ff.positions()[0]-*(RDGeom::Point3D*)ff.positions()[1]; v2=*(RDGeom::Point3D*)ff.positions()[1]-*(RDGeom::Point3D*)ff.positions()[2]; theta = v1.angleTo(v2); TEST_ASSERT(RDKit::feq(v1.length(),1.514,1e-3)); TEST_ASSERT(RDKit::feq(v2.length(),1.514,1e-3)); TEST_ASSERT(RDKit::feq(theta,90*M_PI/180.,1e-4)); // ------- ------- ------- ------- ------- ------- ------- // more complicated atomic coords: p1.x=1.3; p1.y=0.1; p1.z=0.1; p2.x=-0.1; p2.y=0.05; p2.z=-0.05; p3.x=0.1; p3.y=1.5; p3.z=0.05; ff.initialize(); ff.minimize(10,1e-8,1e-8); v1=*(RDGeom::Point3D*)ff.positions()[0]-*(RDGeom::Point3D*)ff.positions()[1]; v2=*(RDGeom::Point3D*)ff.positions()[1]-*(RDGeom::Point3D*)ff.positions()[2]; theta = v1.angleTo(v2); TEST_ASSERT(RDKit::feq(v1.length(),1.514,1e-3)); TEST_ASSERT(RDKit::feq(v2.length(),1.514,1e-3)); TEST_ASSERT(RDKit::feq(theta,90*M_PI/180.,1e-4)); // ------- ------- ------- ------- ------- ------- ------- // try for the tetrahedral angle instead of 90: param1.theta0 = 109.47*M_PI/180.; ff.contribs().pop_back(); contrib = new ForceFields::UFF::AngleBendContrib(&ff,0,1,2,1,1,¶m1,¶m1,¶m1); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); p1.x=1.3; p1.y=0.1; p1.z=0.1; p2.x=-0.1; p2.y=0.05; p2.z=-0.05; p3.x=0.1; p3.y=1.5; p3.z=0.05; ff.initialize(); ff.minimize(100,1e-8,1e-8); v1=*(RDGeom::Point3D*)ff.positions()[0]-*(RDGeom::Point3D*)ff.positions()[1]; v2=*(RDGeom::Point3D*)ff.positions()[2]-*(RDGeom::Point3D*)ff.positions()[1]; theta = v1.angleTo(v2); TEST_ASSERT(RDKit::feq(v1.length(),1.514,1e-3)); TEST_ASSERT(RDKit::feq(v2.length(),1.514,1e-3)); TEST_ASSERT(RDKit::feq(theta,param1.theta0,1e-4)); #endif // ------- ------- ------- ------- ------- ------- ------- // // Do a series of "special cases" (i.e. test the functional forms // for linear, trigonal planar, square planar and octahedral) // // ------- ------- ------- ------- ------- ------- ------- // ------- ------- ------- ------- ------- ------- ------- // test a linear molecule: param1.theta0 = M_PI; //ff.contribs().pop_back(); //ff.contribs().pop_back(); ff.contribs().pop_back(); contrib = new ForceFields::UFF::AngleBendContrib(&ff,0,1,2,1,1,¶m1,¶m1,¶m1,2); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); p1.x=1.3; p1.y=0.1; p1.z=0.0; p2.x=0.0; p2.y=0.0; p2.z=0.0; p3.x=-1.3; p3.y=0.1; p3.z=0.00; ff.initialize(); ff.minimize(100,1e-8,1e-8); v1=*(RDGeom::Point3D*)ff.positions()[0]-*(RDGeom::Point3D*)ff.positions()[1]; v2=*(RDGeom::Point3D*)ff.positions()[2]-*(RDGeom::Point3D*)ff.positions()[1]; theta = v1.angleTo(v2); TEST_ASSERT(RDKit::feq(v1.length(),1.514,1e-3)); TEST_ASSERT(RDKit::feq(v2.length(),1.514,1e-3)); TEST_ASSERT(RDKit::feq(theta,param1.theta0,1e-4)); // ------- ------- ------- ------- ------- ------- ------- // test n=3: param1.theta0 = 120.*M_PI/180.0; //ff.contribs().pop_back(); //ff.contribs().pop_back(); ff.contribs().pop_back(); contrib = new ForceFields::UFF::AngleBendContrib(&ff,0,1,2,1,1,¶m1,¶m1,¶m1,3); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); p1.x=1.3; p1.y=0.1; p1.z=0.0; p2.x=0.0; p2.y=0.0; p2.z=0.0; p3.x=-.3; p3.y=-1.3; p3.z=0.00; ff.initialize(); ff.minimize(100,1e-8,1e-8); v1=*(RDGeom::Point3D*)ff.positions()[0]-*(RDGeom::Point3D*)ff.positions()[1]; v2=*(RDGeom::Point3D*)ff.positions()[2]-*(RDGeom::Point3D*)ff.positions()[1]; theta = v1.angleTo(v2); TEST_ASSERT(RDKit::feq(v1.length(),1.514,1e-3)); TEST_ASSERT(RDKit::feq(v2.length(),1.514,1e-3)); TEST_ASSERT(RDKit::feq(theta,param1.theta0,1e-4)); // ------- ------- ------- ------- ------- ------- ------- // test n=4: param1.theta0 = M_PI/2.0; //ff.contribs().pop_back(); //ff.contribs().pop_back(); ff.contribs().pop_back(); contrib = new ForceFields::UFF::AngleBendContrib(&ff,0,1,2,1,1,¶m1,¶m1,¶m1,4); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); p1.x=1.3; p1.y=0.1; p1.z=0.0; p2.x=0.0; p2.y=0.0; p2.z=0.0; p3.x=-.3; p3.y=-1.3; p3.z=0.00; ff.initialize(); ff.minimize(100,1e-8,1e-8); v1=*(RDGeom::Point3D*)ff.positions()[0]-*(RDGeom::Point3D*)ff.positions()[1]; v2=*(RDGeom::Point3D*)ff.positions()[2]-*(RDGeom::Point3D*)ff.positions()[1]; theta = v1.angleTo(v2); TEST_ASSERT(RDKit::feq(v1.length(),1.514,1e-3)); TEST_ASSERT(RDKit::feq(v2.length(),1.514,1e-3)); TEST_ASSERT(RDKit::feq(theta,param1.theta0,1e-4)); #if 0 std::cerr << " " << *ff.positions()[0] << std::endl; std::cerr << " " << *ff.positions()[1] << std::endl; std::cerr << " " << *ff.positions()[2] << std::endl; std::cerr << "v1: " << v1 << std::endl; std::cerr << "v2: " << v2 << std::endl; std::cerr << "FINAL: " << v1.angleTo(v2) << " " << v1.signedAngleTo(v2) << std::endl; #endif std::cerr << " done" << std::endl; } void testUFF5(){ std::cerr << "-------------------------------------" << std::endl; std::cerr << " Test Simple UFF molecule optimizations." << std::endl; ForceFields::ForceField ff; Point3D p1,p2,p3,p4,p5,p6; RDGeom::PointPtrVect &ps=ff.positions(); ps.push_back(&p1); ps.push_back(&p2); ps.push_back(&p3); ps.push_back(&p4); ps.push_back(&p5); ps.push_back(&p6); ForceFields::UFF::AtomicParams param1,param2; // sp2 carbon: param1.r1 = .732; param1.Z1 = 1.912; param1.GMP_Xi = 5.343; param1.theta0 = 120.*M_PI/180.; // H_1: param2.r1 = 0.354; param2.Z1 = 0.712; param2.GMP_Xi = 4.528; ForceFields::ForceFieldContrib *contrib; // build ethylene: contrib = new ForceFields::UFF::BondStretchContrib(&ff,0,1,2,¶m1,¶m1); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::BondStretchContrib(&ff,0,2,1,¶m1,¶m2); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::BondStretchContrib(&ff,0,3,1,¶m1,¶m2); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::BondStretchContrib(&ff,1,4,1,¶m1,¶m2); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::BondStretchContrib(&ff,1,5,1,¶m1,¶m2); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::AngleBendContrib(&ff,1,0,2,2,1,¶m1,¶m1,¶m2,3); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::AngleBendContrib(&ff,1,0,3,2,1,¶m1,¶m1,¶m2,3); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::AngleBendContrib(&ff,2,0,3,1,1,¶m2,¶m1,¶m2,3); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::AngleBendContrib(&ff,0,1,4,2,1,¶m1,¶m1,¶m2,3); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::AngleBendContrib(&ff,0,1,5,2,1,¶m1,¶m1,¶m2,3); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::AngleBendContrib(&ff,4,1,5,1,1,¶m2,¶m1,¶m2,3); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); // dodge the fact that we're not using torsions yet by putting // everything in the z=0 plane: p1.x=-0.58; p1.y=-0.33; p1.z=0.0; p2.x=0.58; p2.y=0.33; p2.z=0.0; p3.x=-0.61; p3.y=-1.43; p3.z=0.0; p4.x=-1.54; p4.y=0.20; p4.z=0.0; p5.x=0.61; p5.y=1.43; p5.z=0.0; p6.x=1.54; p6.y=-0.20; p6.z=0.0; RDGeom::Point3D d,v1,v2; double theta; // ------- ------- ------- ------- ------- ------- ------- // try a bit of minimization ff.initialize(); ff.minimize(10,1e-8,1e-8); double CCDblBondLen=ForceFields::UFF::Utils::calcBondRestLength(2,¶m1,¶m1); double CHBondLen=ForceFields::UFF::Utils::calcBondRestLength(1,¶m1,¶m2); v1=*(RDGeom::Point3D*)ff.positions()[0]-*(RDGeom::Point3D*)ff.positions()[1]; v2=*(RDGeom::Point3D*)ff.positions()[0]-*(RDGeom::Point3D*)ff.positions()[2]; theta = v1.angleTo(v2); TEST_ASSERT(RDKit::feq(v1.length(),CCDblBondLen,1e-3)); TEST_ASSERT(RDKit::feq(v2.length(),CHBondLen,1e-3)); TEST_ASSERT(RDKit::feq(theta,param1.theta0,1e-4)); v2=*(RDGeom::Point3D*)ff.positions()[0]-*(RDGeom::Point3D*)ff.positions()[3]; theta = v1.angleTo(v2); TEST_ASSERT(RDKit::feq(v2.length(),CHBondLen,1e-3)); TEST_ASSERT(RDKit::feq(theta,param1.theta0,1e-4)); v1=*(RDGeom::Point3D*)ff.positions()[0]-*(RDGeom::Point3D*)ff.positions()[2]; theta = v1.angleTo(v2); TEST_ASSERT(RDKit::feq(theta,param1.theta0,1e-4)); std::cerr << " done" << std::endl; } void testUFF6(){ std::cerr << "-------------------------------------" << std::endl; std::cerr << "Unit tests for UFF nonbonded terms." << std::endl; ForceFields::ForceField ff; Point3D p1(0,0,0),p2(0.0,0,0); RDGeom::PointPtrVect &ps=ff.positions(); ps.push_back(&p1); ps.push_back(&p2); ForceFields::UFF::AtomicParams param1; // sp3 carbon: param1.r1 = .757; param1.Z1 = 1.912; param1.GMP_Xi = 5.343; param1.x1 = 3.851; param1.D1 = 0.105; ff.initialize(); ForceFields::ForceFieldContrib *contrib; contrib = new ForceFields::UFF::vdWContrib(&ff,0,1,¶m1,¶m1); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); // try a bit of minimization RDGeom::Point3D d; ff.initialize(); // edge case: our energy at zero length should be zero: double E; E=ff.calcEnergy(); TEST_ASSERT(RDKit::feq(E,0.0)); (*ff.positions()[0])[0] = 0.0; (*ff.positions()[1])[0] = 4.0; ff.minimize(10,1e-8,1e-8); d=*(RDGeom::Point3D*)ff.positions()[0] - *(RDGeom::Point3D*)ff.positions()[1]; TEST_ASSERT(RDKit::feq(d.length(),3.851,1e-3)); // minimize in "3D" ff.initialize(); (*ff.positions()[0])[0] = 0.0; (*ff.positions()[0])[1] = 0.0; (*ff.positions()[0])[2] = 0.0; (*ff.positions()[1])[2] = 3.1; (*ff.positions()[1])[1] = 0.9; (*ff.positions()[1])[0] = 1.00; ff.minimize(10,1e-8,1e-8); d=*(RDGeom::Point3D*)ff.positions()[0]-*(RDGeom::Point3D*)ff.positions()[1]; TEST_ASSERT(RDKit::feq(d.length(),3.851,1e-3)); std::cerr << " done" << std::endl; } void testUFF7(){ std::cerr << "-------------------------------------" << std::endl; std::cerr << " Test UFF torsional terms." << 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::UFF::AtomicParams param1,param2; // sp3 carbon: param1.r1 = .757; param1.Z1 = 1.912; param1.GMP_Xi = 5.343; param1.x1 = 3.851; param1.D1 = 0.105; param1.V1 = 2.119; param1.U1 = 2.0; // H_1: param2.r1 = 0.354; param2.Z1 = 0.712; param2.GMP_Xi = 4.528; RDGeom::Point3D d,v1,v2; double cosPhi; ForceFields::ForceFieldContrib *contrib; // ------- ------- ------- ------- ------- ------- ------- // Basic SP3 - SP3 // ------- ------- ------- ------- ------- ------- ------- contrib = new ForceFields::UFF::TorsionAngleContrib(&ff,0,1,2,3,1, 6,6, RDKit::Atom::SP3,RDKit::Atom::SP3, ¶m1,¶m1); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); #if 1 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); cosPhi = ForceFields::UFF::Utils::calculateCosTorsion(*(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 // ------- ------- ------- ------- ------- ------- ------- ff.contribs().pop_back(); contrib = new ForceFields::UFF::TorsionAngleContrib(&ff,0,1,2,3,1, 6,6, RDKit::Atom::SP2,RDKit::Atom::SP2, ¶m1,¶m1); 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::UFF::Utils::calculateCosTorsion(*(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)); // ------- ------- ------- ------- ------- ------- ------- // Basic SP2 - SP3 // ------- ------- ------- ------- ------- ------- ------- ff.contribs().pop_back(); contrib = new ForceFields::UFF::TorsionAngleContrib(&ff,0,1,2,3,1, 6,6, RDKit::Atom::SP2,RDKit::Atom::SP3, ¶m1,¶m1); 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(100,1e-8,1e-8); cosPhi = ForceFields::UFF::Utils::calculateCosTorsion(*(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)); // ------- ------- ------- ------- ------- ------- ------- // special case for group 6 - group 6 bonds: // ------- ------- ------- ------- ------- ------- ------- ff.contribs().pop_back(); contrib = new ForceFields::UFF::TorsionAngleContrib(&ff,0,1,2,3,1, 8,8, RDKit::Atom::SP3,RDKit::Atom::SP3, ¶m1,¶m1); 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(100,1e-8,1e-8); cosPhi = ForceFields::UFF::Utils::calculateCosTorsion(*(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.0,1e-4)); // ------- ------- ------- ------- ------- ------- ------- // special case for SP3 group 6 - SP2 other group // ------- ------- ------- ------- ------- ------- ------- ff.contribs().pop_back(); contrib = new ForceFields::UFF::TorsionAngleContrib(&ff,0,1,2,3,1, 8,6, RDKit::Atom::SP3,RDKit::Atom::SP2, ¶m1,¶m1); 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(100,1e-8,1e-8); cosPhi = ForceFields::UFF::Utils::calculateCosTorsion(*(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.0,1e-4)); #endif // ------- ------- ------- ------- ------- ------- ------- // special case for (SP2 -) SP2 - SP3 // ------- ------- ------- ------- ------- ------- ------- ff.contribs().pop_back(); contrib = new ForceFields::UFF::TorsionAngleContrib(&ff,0,1,2,3,1, 6,6, RDKit::Atom::SP2,RDKit::Atom::SP3, ¶m1,¶m1,true); 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(100,1e-8,1e-8); cosPhi = ForceFields::UFF::Utils::calculateCosTorsion(*(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)); std::cerr << " done" << std::endl; } void testUFFParams(){ std::cerr << "-------------------------------------" << std::endl; std::cerr << " Test UFF Parameter objects" << std::endl; ForceFields::UFF::ParamCollection *params=ForceFields::UFF::ParamCollection::getParams(); TEST_ASSERT(params); const ForceFields::UFF::AtomicParams *ptr; ptr=(*params)("C_3"); TEST_ASSERT(ptr); TEST_ASSERT(RDKit::feq(ptr->r1,0.757)); TEST_ASSERT(RDKit::feq(ptr->theta0,109.47*M_PI/180.)); TEST_ASSERT(RDKit::feq(ptr->x1,3.851)); TEST_ASSERT(RDKit::feq(ptr->D1,0.105)); TEST_ASSERT(RDKit::feq(ptr->zeta,12.73)); TEST_ASSERT(RDKit::feq(ptr->Z1,1.912)); TEST_ASSERT(RDKit::feq(ptr->V1,2.119)); TEST_ASSERT(RDKit::feq(ptr->GMP_Xi,5.343)); TEST_ASSERT(RDKit::feq(ptr->GMP_Hardness,5.063)); TEST_ASSERT(RDKit::feq(ptr->GMP_Radius,0.759)); ptr=(*params)("N_3"); TEST_ASSERT(ptr); ptr=(*params)("C_5"); TEST_ASSERT(!ptr); } void testUFF8(){ std::cerr << "-------------------------------------" << std::endl; std::cerr << " Test Simple UFF molecule optimization, part 2." << std::endl; ForceFields::ForceField ff; Point3D p1,p2,p3,p4,p5,p6; RDGeom::PointPtrVect &ps=ff.positions(); ps.push_back(&p1); ps.push_back(&p2); ps.push_back(&p3); ps.push_back(&p4); ps.push_back(&p5); ps.push_back(&p6); ForceFields::UFF::ParamCollection *params=ForceFields::UFF::ParamCollection::getParams(); const ForceFields::UFF::AtomicParams *param1,*param2; // C_2 (sp2 carbon): param1 = (*params)("C_2"); TEST_ASSERT(param1); // H_: param2 = (*params)("H_"); TEST_ASSERT(param2); ForceFields::ForceFieldContrib *contrib; // build ethylene: // BONDS: contrib = new ForceFields::UFF::BondStretchContrib(&ff,0,1,2,param1,param1); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::BondStretchContrib(&ff,0,2,1,param1,param2); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::BondStretchContrib(&ff,0,3,1,param1,param2); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::BondStretchContrib(&ff,1,4,1,param1,param2); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::BondStretchContrib(&ff,1,5,1,param1,param2); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); // ANGLES: contrib = new ForceFields::UFF::AngleBendContrib(&ff,1,0,2,2,1,param1,param1,param2,3); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::AngleBendContrib(&ff,1,0,3,2,1,param1,param1,param2,3); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::AngleBendContrib(&ff,2,0,3,1,1,param2,param1,param2,3); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::AngleBendContrib(&ff,0,1,4,2,1,param1,param1,param2,3); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::AngleBendContrib(&ff,0,1,5,2,1,param1,param1,param2,3); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::AngleBendContrib(&ff,4,1,5,1,1,param2,param1,param2,3); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); // DIHEDRALS: contrib = new ForceFields::UFF::TorsionAngleContrib(&ff,2,0,1,4,2, 6,6, RDKit::Atom::SP3,RDKit::Atom::SP3, param1,param1); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::TorsionAngleContrib(&ff,2,0,1,5,2, 6,6, RDKit::Atom::SP3,RDKit::Atom::SP3, param1,param1); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::TorsionAngleContrib(&ff,3,0,1,4,2, 6,6, RDKit::Atom::SP3,RDKit::Atom::SP3, param1,param1); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::TorsionAngleContrib(&ff,3,0,1,5,2, 6,6, RDKit::Atom::SP3,RDKit::Atom::SP3, param1,param1); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); p1.x=-0.58; p1.y=-0.33; p1.z=0.1; p2.x=0.58; p2.y=0.33; p2.z=0.1; p3.x=-0.61; p3.y=-1.43; p3.z=0.0; p4.x=-1.54; p4.y=0.20; p4.z=0.0; p5.x=0.61; p5.y=1.43; p5.z=0.0; p6.x=1.54; p6.y=-0.20; p6.z=0.0; RDGeom::Point3D d,v1,v2; double theta; // ------- ------- ------- ------- ------- ------- ------- // try a bit of minimization ff.initialize(); ff.minimize(100,1e-8,1e-8); double CCDblBondLen=ForceFields::UFF::Utils::calcBondRestLength(2,param1,param1); double CHBondLen=ForceFields::UFF::Utils::calcBondRestLength(1,param1,param2); v1=*(RDGeom::Point3D*)ff.positions()[0] - *(RDGeom::Point3D*)ff.positions()[1]; v2=*(RDGeom::Point3D*)ff.positions()[0] - *(RDGeom::Point3D*)ff.positions()[2]; theta = v1.angleTo(v2); TEST_ASSERT(RDKit::feq(v1.length(),CCDblBondLen,1e-3)); TEST_ASSERT(RDKit::feq(v2.length(),CHBondLen,1e-3)); TEST_ASSERT(RDKit::feq(theta,param1->theta0,1e-4)); v2=*(RDGeom::Point3D*)ff.positions()[0] - *(RDGeom::Point3D*)ff.positions()[3]; theta = v1.angleTo(v2); TEST_ASSERT(RDKit::feq(v2.length(),CHBondLen,1e-3)); TEST_ASSERT(RDKit::feq(theta,param1->theta0,1e-4)); v1=*(RDGeom::Point3D*)ff.positions()[0] - *(RDGeom::Point3D*)ff.positions()[2]; theta = v1.angleTo(v2); TEST_ASSERT(RDKit::feq(theta,param1->theta0,1e-4)); std::cerr << " done" << std::endl; } void testUFFTorsionConflict(){ std::cerr << "-------------------------------------" << std::endl; std::cerr << " Test UFF Torsion Conflicts." << std::endl; ForceFields::ForceField ff; Point3D p1,p2,p3,p4,p5,p6,p7; RDGeom::PointPtrVect &ps=ff.positions(); ps.push_back(&p1); ps.push_back(&p2); ps.push_back(&p3); ps.push_back(&p4); ps.push_back(&p5); ps.push_back(&p6); ps.push_back(&p7); ForceFields::UFF::ParamCollection *params=ForceFields::UFF::ParamCollection::getParams(); const ForceFields::UFF::AtomicParams *param1,*param2,*param3; // C_2 (sp2 carbon): param1 = (*params)("C_2"); TEST_ASSERT(param1); // H_: param2 = (*params)("H_"); TEST_ASSERT(param2); // C_3 (sp3 carbon): param3 = (*params)("C_3"); TEST_ASSERT(param3); ForceFields::ForceFieldContrib *contrib; // BONDS: contrib = new ForceFields::UFF::BondStretchContrib(&ff,0,1,2,param1,param1); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::BondStretchContrib(&ff,1,2,1,param1,param3); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::BondStretchContrib(&ff,1,3,1,param1,param2); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::BondStretchContrib(&ff,2,4,1,param1,param2); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::BondStretchContrib(&ff,2,5,1,param1,param2); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::BondStretchContrib(&ff,2,6,1,param1,param2); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); #if 1 // ANGLES: contrib = new ForceFields::UFF::AngleBendContrib(&ff,0,1,2,2.0,1.0,param1,param1,param3); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::AngleBendContrib(&ff,0,1,3,2.0,1.0,param1,param1,param2); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::AngleBendContrib(&ff,1,2,4,1.0,1.0,param1,param3,param2); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::AngleBendContrib(&ff,1,2,5,1.0,1.0,param1,param3,param2); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::AngleBendContrib(&ff,1,2,6,1.0,1.0,param1,param3,param2); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::AngleBendContrib(&ff,2,1,3,1.0,1.0,param3,param1,param2); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); #endif // DIHEDRALS: contrib = new ForceFields::UFF::TorsionAngleContrib(&ff,0,1,2,4,1.0, 6,6, RDKit::Atom::SP2,RDKit::Atom::SP3, param1,param3,true); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::TorsionAngleContrib(&ff,3,1,2,4,1.0, 6,6, RDKit::Atom::SP2,RDKit::Atom::SP3, param1,param3,false); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::TorsionAngleContrib(&ff,0,1,2,5,1.0, 6,6, RDKit::Atom::SP2,RDKit::Atom::SP3, param1,param3,true); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::TorsionAngleContrib(&ff,3,1,2,5,1.0, 6,6, RDKit::Atom::SP2,RDKit::Atom::SP3, param1,param3,false); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::TorsionAngleContrib(&ff,0,1,2,6,1.0, 6,6, RDKit::Atom::SP2,RDKit::Atom::SP3, param1,param3,true); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); contrib = new ForceFields::UFF::TorsionAngleContrib(&ff,3,1,2,6,1.0, 6,6, RDKit::Atom::SP2,RDKit::Atom::SP3, param1,param3,false); ff.contribs().push_back(ForceFields::ContribPtr(contrib)); p1.x=0.5411; p1.y=-0.7741; p1.z=0.0902; p2.x=-0.5622; p2.y=-0.0368; p2.z=0.1202; p3.x=-0.5101; p3.y=1.4485; p3.z=0.0816; p4.x=-1.5285; p4.y=-0.5341; p4.z=0.1892; p5.x=0.5097; p5.y=1.8065; p5.z=0.1988; p6.x=-1.1436; p6.y=1.8781; p6.z=0.8983; p7.x=-0.9145; p7.y=1.8185; p7.z=-0.8983; RDGeom::Point3D d,v1,v2; // ------- ------- ------- ------- ------- ------- ------- // try a bit of minimization ff.initialize(); ff.minimize(100,1e-8,1e-8); #if 1 std::cerr.setf(std::ios_base::fixed,std::ios_base::floatfield); std::cerr.precision(4); std::cerr << "C " << *ff.positions()[0] << std::endl; std::cerr << "C " << *ff.positions()[1] << std::endl; std::cerr << "C " << *ff.positions()[2] << std::endl; std::cerr << "H " << *ff.positions()[3] << std::endl; std::cerr << "H " << *ff.positions()[4] << std::endl; std::cerr << "O " << *ff.positions()[5] << std::endl; std::cerr << "F " << *ff.positions()[6] << std::endl; #endif std::cerr << " done" << std::endl; } void testUFFDistanceConstraints(){ std::cerr << "-------------------------------------" << std::endl; std::cerr << "Unit tests for UFF distance constraint terms." << std::endl; ForceFields::ForceField ff; Point3D p1(0,0,0),p2(1.514,0,0); RDGeom::PointPtrVect &ps=ff.positions(); ps.push_back(&p1); ps.push_back(&p2); double *p,*g; p = new double[6]; g = new double[6]; for(int i=0;i<6;i++){ p[i] = 0.0; g[i] = 0.0; } p[0] = 0; p[3] = 1.40; ff.initialize(); // C_3 - C_3, r0=1.514, k01=699.5918 ForceFields::ForceFieldContrib *bs; bs = new ForceFields::UFF::DistanceConstraintContrib(&ff,0,1,1.35,1.55,1000.0); ff.contribs().push_back(ForceFields::ContribPtr(bs)); double E; E=bs->getEnergy(p); TEST_ASSERT(RDKit::feq(E,0.0)); bs->getGrad(p,g); for(int i=0;i<6;i++){ TEST_ASSERT(RDKit::feq(g[i],0.0)); } ff.initialize(); (*ff.positions()[1])[0] = 1.20; p[3] = 1.20; E=bs->getEnergy(p); TEST_ASSERT(RDKit::feq(E,11.25)); bs->getGrad(p,g); TEST_ASSERT(RDKit::feq(g[0],150.0)); TEST_ASSERT(RDKit::feq(g[3],-150.0)); TEST_ASSERT(RDKit::feq(g[1],0.0)); TEST_ASSERT(RDKit::feq(g[2],0.0)); TEST_ASSERT(RDKit::feq(g[4],0.0)); TEST_ASSERT(RDKit::feq(g[5],0.0)); // try a bit of minimization RDGeom::Point3D d; ff.initialize(); (*ff.positions()[1])[2] = 0.0; (*ff.positions()[1])[0] = 1.20; ff.minimize(10,1e-8); d=*(RDGeom::Point3D*)ff.positions()[0]-*(RDGeom::Point3D*)ff.positions()[1]; TEST_ASSERT(d.length()>=1.35) TEST_ASSERT(d.length()<=1.55) ff.initialize(); (*ff.positions()[1])[2] = 0.0; (*ff.positions()[1])[0] = 1.70; ff.minimize(10,1e-8); d=*(RDGeom::Point3D*)ff.positions()[0]-*(RDGeom::Point3D*)ff.positions()[1]; TEST_ASSERT(d.length()>=1.35) TEST_ASSERT(d.length()<=1.55) delete [] p; delete [] g; std::cerr << " done" << std::endl; } int main(){ #if 1 test1(); testUFF1(); testUFF2(); testUFF3(); testUFF4(); testUFF5(); testUFF6(); testUFF7(); testUFFParams(); testUFF8(); testUFFTorsionConflict(); #endif testUFFDistanceConstraints(); }