void testCMAPTorsions() { const int mapSize = 36; // Create two systems: one with a pair of periodic torsions, and one with a CMAP torsion // that approximates the same force. System system1; for (int i = 0; i < 5; i++) system1.addParticle(1.0); PeriodicTorsionForce* periodic = new PeriodicTorsionForce(); periodic->addTorsion(0, 1, 2, 3, 2, M_PI/4, 1.5); periodic->addTorsion(1, 2, 3, 4, 3, M_PI/3, 2.0); system1.addForce(periodic); System system2; for (int i = 0; i < 5; i++) system2.addParticle(1.0); CMAPTorsionForce* cmap = new CMAPTorsionForce(); vector<double> mapEnergy(mapSize*mapSize); for (int i = 0; i < mapSize; i++) { double angle1 = i*2*M_PI/mapSize; double energy1 = 1.5*(1+cos(2*angle1-M_PI/4)); for (int j = 0; j < mapSize; j++) { double angle2 = j*2*M_PI/mapSize; double energy2 = 2.0*(1+cos(3*angle2-M_PI/3)); mapEnergy[i+j*mapSize] = energy1+energy2; } } cmap->addMap(mapSize, mapEnergy); cmap->addTorsion(0, 0, 1, 2, 3, 1, 2, 3, 4); system2.addForce(cmap); // Set the atoms in various positions, and verify that both systems give equal forces and energy. OpenMM_SFMT::SFMT sfmt; init_gen_rand(0, sfmt); vector<Vec3> positions(5); VerletIntegrator integrator1(0.01); VerletIntegrator integrator2(0.01); Context c1(system1, integrator1, platform); Context c2(system2, integrator2, platform); for (int i = 0; i < 50; i++) { for (int j = 0; j < (int) positions.size(); j++) positions[j] = Vec3(5.0*genrand_real2(sfmt), 5.0*genrand_real2(sfmt), 5.0*genrand_real2(sfmt)); c1.setPositions(positions); c2.setPositions(positions); State s1 = c1.getState(State::Forces | State::Energy); State s2 = c2.getState(State::Forces | State::Energy); for (int i = 0; i < system1.getNumParticles(); i++) ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], 0.05); ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), 1e-3); } }
void testPeriodicTorsions() { ReferencePlatform platform; System system; system.addParticle(1.0); system.addParticle(1.0); system.addParticle(1.0); system.addParticle(1.0); VerletIntegrator integrator(0.01); PeriodicTorsionForce* forceField = new PeriodicTorsionForce(); forceField->addTorsion(0, 1, 2, 3, 2, PI_M/3, 1.1); system.addForce(forceField); ASSERT(!forceField->usesPeriodicBoundaryConditions()); ASSERT(!system.usesPeriodicBoundaryConditions()); Context context(system, integrator, platform); vector<Vec3> positions(4); positions[0] = Vec3(0, 1, 0); positions[1] = Vec3(0, 0, 0); positions[2] = Vec3(1, 0, 0); positions[3] = Vec3(1, 0, 2); context.setPositions(positions); State state = context.getState(State::Forces | State::Energy); { const vector<Vec3>& forces = state.getForces(); double torque = -2*1.1*std::sin(2*PI_M/3); ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL); ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, 0), forces[3], TOL); ASSERT_EQUAL_VEC(Vec3(forces[0][0]+forces[1][0]+forces[2][0]+forces[3][0], forces[0][1]+forces[1][1]+forces[2][1]+forces[3][1], forces[0][2]+forces[1][2]+forces[2][2]+forces[3][2]), Vec3(0, 0, 0), TOL); ASSERT_EQUAL_TOL(1.1*(1+std::cos(2*PI_M/3)), state.getPotentialEnergy(), TOL); } // Try changing the torsion parameters and make sure it's still correct. forceField->setTorsionParameters(0, 0, 1, 2, 3, 3, PI_M/3.2, 1.3); forceField->updateParametersInContext(context); state = context.getState(State::Forces | State::Energy); { const vector<Vec3>& forces = state.getForces(); double dtheta = (3*PI_M/2)-(PI_M/3.2); double torque = -3*1.3*std::sin(dtheta); ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL); ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, 0), forces[3], TOL); ASSERT_EQUAL_VEC(Vec3(forces[0][0]+forces[1][0]+forces[2][0]+forces[3][0], forces[0][1]+forces[1][1]+forces[2][1]+forces[3][1], forces[0][2]+forces[1][2]+forces[2][2]+forces[3][2]), Vec3(0, 0, 0), TOL); ASSERT_EQUAL_TOL(1.3*(1+std::cos(dtheta)), state.getPotentialEnergy(), TOL); } }
void testBond() { // Create a system using a CustomCompoundBondForce. System customSystem; customSystem.addParticle(1.0); customSystem.addParticle(1.0); customSystem.addParticle(1.0); customSystem.addParticle(1.0); CustomCompoundBondForce* custom = new CustomCompoundBondForce(4, "0.5*kb*((distance(p1,p2)-b0)^2+(distance(p2,p3)-b0)^2)+0.5*ka*(angle(p2,p3,p4)-a0)^2+kt*(1+cos(dihedral(p1,p2,p3,p4)-t0))"); custom->addPerBondParameter("kb"); custom->addPerBondParameter("ka"); custom->addPerBondParameter("kt"); custom->addPerBondParameter("b0"); custom->addPerBondParameter("a0"); custom->addPerBondParameter("t0"); vector<int> particles(4); particles[0] = 0; particles[1] = 1; particles[2] = 3; particles[3] = 2; vector<double> parameters(6); parameters[0] = 1.5; parameters[1] = 0.8; parameters[2] = 0.6; parameters[3] = 1.1; parameters[4] = 2.9; parameters[5] = 1.3; custom->addBond(particles, parameters); customSystem.addForce(custom); // Create an identical system using standard forces. System standardSystem; standardSystem.addParticle(1.0); standardSystem.addParticle(1.0); standardSystem.addParticle(1.0); standardSystem.addParticle(1.0); HarmonicBondForce* bonds = new HarmonicBondForce(); bonds->addBond(0, 1, 1.1, 1.5); bonds->addBond(1, 3, 1.1, 1.5); standardSystem.addForce(bonds); HarmonicAngleForce* angles = new HarmonicAngleForce(); angles->addAngle(1, 3, 2, 2.9, 0.8); standardSystem.addForce(angles); PeriodicTorsionForce* torsions = new PeriodicTorsionForce(); torsions->addTorsion(0, 1, 3, 2, 1, 1.3, 0.6); standardSystem.addForce(torsions); // Set the atoms in various positions, and verify that both systems give identical forces and energy. OpenMM_SFMT::SFMT sfmt; init_gen_rand(0, sfmt); VerletIntegrator integrator1(0.01); VerletIntegrator integrator2(0.01); Context c1(customSystem, integrator1, platform); Context c2(standardSystem, integrator2, platform); vector<Vec3> positions(4); for (int i = 0; i < 10; i++) { for (int j = 0; j < (int) positions.size(); j++) positions[j] = Vec3(5.0*genrand_real2(sfmt), 5.0*genrand_real2(sfmt), 5.0*genrand_real2(sfmt)); c1.setPositions(positions); c2.setPositions(positions); State s1 = c1.getState(State::Forces | State::Energy); State s2 = c2.getState(State::Forces | State::Energy); for (int i = 0; i < customSystem.getNumParticles(); i++) ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); } // Try changing the bond parameters and make sure it's still correct. parameters[0] = 1.6; parameters[3] = 1.3; custom->setBondParameters(0, particles, parameters); custom->updateParametersInContext(c1); bonds->setBondParameters(0, 0, 1, 1.3, 1.6); bonds->setBondParameters(1, 1, 3, 1.3, 1.6); bonds->updateParametersInContext(c2); { State s1 = c1.getState(State::Forces | State::Energy); State s2 = c2.getState(State::Forces | State::Energy); const vector<Vec3>& forces = s1.getForces(); for (int i = 0; i < customSystem.getNumParticles(); i++) ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], TOL); ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), s2.getPotentialEnergy(), TOL); } }
void testHbond() { // Create a system using a CustomHbondForce. System customSystem; customSystem.addParticle(1.0); customSystem.addParticle(1.0); customSystem.addParticle(1.0); customSystem.addParticle(1.0); customSystem.addParticle(1.0); CustomHbondForce* custom = new CustomHbondForce("0.5*kr*(distance(d1,a1)-r0)^2 + 0.5*ktheta*(angle(a1,d1,d2)-theta0)^2 + 0.5*kpsi*(angle(d1,a1,a2)-psi0)^2 + kchi*(1+cos(n*dihedral(a3,a2,a1,d1)-chi0))"); custom->addPerDonorParameter("r0"); custom->addPerDonorParameter("theta0"); custom->addPerDonorParameter("psi0"); custom->addPerAcceptorParameter("chi0"); custom->addPerAcceptorParameter("n"); custom->addGlobalParameter("kr", 0.4); custom->addGlobalParameter("ktheta", 0.5); custom->addGlobalParameter("kpsi", 0.6); custom->addGlobalParameter("kchi", 0.7); vector<double> parameters(3); parameters[0] = 1.5; parameters[1] = 1.7; parameters[2] = 1.9; custom->addDonor(1, 0, -1, parameters); parameters.resize(2); parameters[0] = 2.1; parameters[1] = 2; custom->addAcceptor(2, 3, 4, parameters); custom->setCutoffDistance(10.0); customSystem.addForce(custom); // Create an identical system using HarmonicBondForce, HarmonicAngleForce, and PeriodicTorsionForce. System standardSystem; standardSystem.addParticle(1.0); standardSystem.addParticle(1.0); standardSystem.addParticle(1.0); standardSystem.addParticle(1.0); standardSystem.addParticle(1.0); HarmonicBondForce* bond = new HarmonicBondForce(); bond->addBond(1, 2, 1.5, 0.4); standardSystem.addForce(bond); HarmonicAngleForce* angle = new HarmonicAngleForce(); angle->addAngle(0, 1, 2, 1.7, 0.5); angle->addAngle(1, 2, 3, 1.9, 0.6); standardSystem.addForce(angle); PeriodicTorsionForce* torsion = new PeriodicTorsionForce(); torsion->addTorsion(1, 2, 3, 4, 2, 2.1, 0.7); standardSystem.addForce(torsion); // Set the atoms in various positions, and verify that both systems give identical forces and energy. OpenMM_SFMT::SFMT sfmt; init_gen_rand(0, sfmt); vector<Vec3> positions(5); VerletIntegrator integrator1(0.01); VerletIntegrator integrator2(0.01); Context c1(customSystem, integrator1, platform); Context c2(standardSystem, integrator2, platform); for (int i = 0; i < 10; i++) { for (int j = 0; j < (int) positions.size(); j++) positions[j] = Vec3(2.0*genrand_real2(sfmt), 2.0*genrand_real2(sfmt), 2.0*genrand_real2(sfmt)); c1.setPositions(positions); c2.setPositions(positions); State s1 = c1.getState(State::Forces | State::Energy); State s2 = c2.getState(State::Forces | State::Energy); for (int i = 0; i < customSystem.getNumParticles(); i++) ASSERT_EQUAL_VEC(s2.getForces()[i], s1.getForces()[i], TOL); ASSERT_EQUAL_TOL(s2.getPotentialEnergy(), s1.getPotentialEnergy(), TOL); } // Try changing the parameters and make sure it's still correct. parameters.resize(3); parameters[0] = 1.4; parameters[1] = 1.7; parameters[2] = 1.9; custom->setDonorParameters(0, 1, 0, -1, parameters); parameters.resize(2); parameters[0] = 2.2; parameters[1] = 2; custom->setAcceptorParameters(0, 2, 3, 4, parameters); bond->setBondParameters(0, 1, 2, 1.4, 0.4); torsion->setTorsionParameters(0, 1, 2, 3, 4, 2, 2.2, 0.7); custom->updateParametersInContext(c1); bond->updateParametersInContext(c2); torsion->updateParametersInContext(c2); State s1 = c1.getState(State::Forces | State::Energy); State s2 = c2.getState(State::Forces | State::Energy); for (int i = 0; i < customSystem.getNumParticles(); i++) ASSERT_EQUAL_VEC(s2.getForces()[i], s1.getForces()[i], TOL); ASSERT_EQUAL_TOL(s2.getPotentialEnergy(), s1.getPotentialEnergy(), TOL); }