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 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); }