void testParallelComputation(NonbondedForce::NonbondedMethod method) { System system; const int numParticles = 200; for (int i = 0; i < numParticles; i++) system.addParticle(1.0); NonbondedForce* force = new NonbondedForce(); for (int i = 0; i < numParticles; i++) force->addParticle(i%2-0.5, 0.5, 1.0); force->setNonbondedMethod(method); system.addForce(force); system.setDefaultPeriodicBoxVectors(Vec3(5,0,0), Vec3(0,5,0), Vec3(0,0,5)); OpenMM_SFMT::SFMT sfmt; init_gen_rand(0, sfmt); vector<Vec3> positions(numParticles); for (int i = 0; i < numParticles; i++) positions[i] = Vec3(5*genrand_real2(sfmt), 5*genrand_real2(sfmt), 5*genrand_real2(sfmt)); for (int i = 0; i < numParticles; ++i) for (int j = 0; j < i; ++j) { Vec3 delta = positions[i]-positions[j]; if (delta.dot(delta) < 0.1) force->addException(i, j, 0, 1, 0); } // Create two contexts, one with a single device and one with two devices. VerletIntegrator integrator1(0.01); Context context1(system, integrator1, platform); context1.setPositions(positions); State state1 = context1.getState(State::Forces | State::Energy); VerletIntegrator integrator2(0.01); string deviceIndex = platform.getPropertyValue(context1, CudaPlatform::CudaDeviceIndex()); map<string, string> props; props[CudaPlatform::CudaDeviceIndex()] = deviceIndex+","+deviceIndex; Context context2(system, integrator2, platform, props); context2.setPositions(positions); State state2 = context2.getState(State::Forces | State::Energy); // See if they agree. ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-5); for (int i = 0; i < numParticles; i++) ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); // Modify some particle parameters and see if they still agree. for (int i = 0; i < numParticles; i += 5) { double charge, sigma, epsilon; force->getParticleParameters(i, charge, sigma, epsilon); force->setParticleParameters(i, 0.9*charge, sigma, epsilon); } force->updateParametersInContext(context1); force->updateParametersInContext(context2); state1 = context1.getState(State::Forces | State::Energy); state2 = context2.getState(State::Forces | State::Energy); ASSERT_EQUAL_TOL(state1.getPotentialEnergy(), state2.getPotentialEnergy(), 1e-5); for (int i = 0; i < numParticles; i++) ASSERT_EQUAL_VEC(state1.getForces()[i], state2.getForces()[i], 1e-5); }
void testEnergyEthane(int applyBornRadiiScaling) { ReferencePlatform platform; const int numParticles = 8; System system; LangevinIntegrator integrator(0, 0.1, 0.01); // harmonic bond double C_HBondDistance = 0.1097; double C_CBondDistance = 0.1504; HarmonicBondForce* bonds = new HarmonicBondForce(); bonds->addBond(0, 1, C_HBondDistance, 0.0); bonds->addBond(2, 1, C_HBondDistance, 0.0); bonds->addBond(3, 1, C_HBondDistance, 0.0); bonds->addBond(1, 4, C_CBondDistance, 0.0); bonds->addBond(5, 4, C_HBondDistance, 0.0); bonds->addBond(6, 4, C_HBondDistance, 0.0); bonds->addBond(7, 4, C_HBondDistance, 0.0); system.addForce(bonds); double C_radius, C_gamma, C_charge, H_radius, H_gamma, H_charge; int AM1_BCC = 1; H_charge = -0.053; C_charge = -3.0*H_charge; if (AM1_BCC) { C_radius = 0.180; C_gamma = -0.2863; H_radius = 0.125; H_gamma = 0.2437; } else { C_radius = 0.215; C_gamma = -1.1087; H_radius = 0.150; H_gamma = 0.1237; } NonbondedForce* nonbonded = new NonbondedForce(); nonbonded->setNonbondedMethod(NonbondedForce::NoCutoff); GBVIForce* forceField = new GBVIForce(); if (applyBornRadiiScaling) { forceField->setBornRadiusScalingMethod(GBVIForce::QuinticSpline); } else { forceField->setBornRadiusScalingMethod(GBVIForce::NoScaling); } for (int i = 0; i < numParticles; i++) { system.addParticle(1.0); forceField->addParticle(H_charge, H_radius, H_gamma); nonbonded->addParticle( H_charge, H_radius, 0.0); } forceField->setParticleParameters(1, C_charge, C_radius, C_gamma); forceField->setParticleParameters(4, C_charge, C_radius, C_gamma); nonbonded->setParticleParameters( 1, C_charge, C_radius, 0.0); nonbonded->setParticleParameters( 4, C_charge, C_radius, 0.0); forceField->addBond(0, 1, C_HBondDistance); forceField->addBond(2, 1, C_HBondDistance); forceField->addBond(3, 1, C_HBondDistance); forceField->addBond(1, 4, C_CBondDistance); forceField->addBond(5, 4, C_HBondDistance); forceField->addBond(6, 4, C_HBondDistance); forceField->addBond(7, 4, C_HBondDistance); std::vector<pair<int, int> > bondExceptions; std::vector<double> bondDistances; bondExceptions.push_back(pair<int, int>(0, 1)); bondDistances.push_back(C_HBondDistance); bondExceptions.push_back(pair<int, int>(2, 1)); bondDistances.push_back(C_HBondDistance); bondExceptions.push_back(pair<int, int>(3, 1)); bondDistances.push_back(C_HBondDistance); bondExceptions.push_back(pair<int, int>(1, 4)); bondDistances.push_back(C_CBondDistance); bondExceptions.push_back(pair<int, int>(5, 4)); bondDistances.push_back(C_HBondDistance); bondExceptions.push_back(pair<int, int>(6, 4)); bondDistances.push_back(C_HBondDistance); bondExceptions.push_back(pair<int, int>(7, 4)); bondDistances.push_back(C_HBondDistance); nonbonded->createExceptionsFromBonds(bondExceptions, 0.0, 0.0); system.addForce(forceField); system.addForce(nonbonded); Context context(system, integrator, platform); vector<Vec3> positions(numParticles); positions[0] = Vec3(0.5480, 1.7661, 0.0000); positions[1] = Vec3(0.7286, 0.8978, 0.6468); positions[2] = Vec3(0.4974, 0.0000, 0.0588); positions[3] = Vec3(0.0000, 0.9459, 1.4666); positions[4] = Vec3(2.1421, 0.8746, 1.1615); positions[5] = Vec3(2.3239, 0.0050, 1.8065); positions[6] = Vec3(2.8705, 0.8295, 0.3416); positions[7] = Vec3(2.3722, 1.7711, 1.7518); context.setPositions(positions); State state = context.getState(State::Forces | State::Energy); // Take a small step in the direction of the energy gradient. double norm = 0.0; double forceSum[3] = { 0.0, 0.0, 0.0 }; for (int i = 0; i < numParticles; ++i) { Vec3 f = state.getForces()[i]; norm += f[0]*f[0] + f[1]*f[1] + f[2]*f[2]; forceSum[0] += f[0]; forceSum[1] += f[1]; forceSum[2] += f[2]; } norm = std::sqrt(norm); const double delta = 1e-4; double step = delta/norm; for (int i = 0; i < numParticles; ++i) { Vec3 p = positions[i]; Vec3 f = state.getForces()[i]; positions[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); } context.setPositions(positions); State state2 = context.getState(State::Energy); // See whether the potential energy changed by the expected amount. ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state.getPotentialEnergy())/delta, 0.01) }
void testChangingParameters() { const int numMolecules = 600; const int numParticles = numMolecules*2; const double cutoff = 2.0; const double boxSize = 20.0; const double tol = 2e-3; ReferencePlatform reference; System system; for (int i = 0; i < numParticles; i++) system.addParticle(1.0); NonbondedForce* nonbonded = new NonbondedForce(); vector<Vec3> positions(numParticles); OpenMM_SFMT::SFMT sfmt; init_gen_rand(0, sfmt); for (int i = 0; i < numMolecules; i++) { if (i < numMolecules/2) { nonbonded->addParticle(-1.0, 0.2, 0.1); nonbonded->addParticle(1.0, 0.1, 0.1); } else { nonbonded->addParticle(-1.0, 0.2, 0.2); nonbonded->addParticle(1.0, 0.1, 0.2); } positions[2*i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt)); positions[2*i+1] = Vec3(positions[2*i][0]+1.0, positions[2*i][1], positions[2*i][2]); system.addConstraint(2*i, 2*i+1, 1.0); nonbonded->addException(2*i, 2*i+1, 0.0, 0.15, 0.0); } nonbonded->setNonbondedMethod(NonbondedForce::PME); nonbonded->setCutoffDistance(cutoff); system.addForce(nonbonded); system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); // See if Reference and Cuda give the same forces and energies. VerletIntegrator integrator1(0.01); VerletIntegrator integrator2(0.01); Context cuContext(system, integrator1, platform); Context referenceContext(system, integrator2, reference); cuContext.setPositions(positions); referenceContext.setPositions(positions); State cuState = cuContext.getState(State::Forces | State::Energy); State referenceState = referenceContext.getState(State::Forces | State::Energy); for (int i = 0; i < numParticles; i++) ASSERT_EQUAL_VEC(cuState.getForces()[i], referenceState.getForces()[i], tol); ASSERT_EQUAL_TOL(cuState.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol); // Now modify parameters and see if they still agree. for (int i = 0; i < numParticles; i += 5) { double charge, sigma, epsilon; nonbonded->getParticleParameters(i, charge, sigma, epsilon); nonbonded->setParticleParameters(i, 1.5*charge, 1.1*sigma, 1.7*epsilon); } nonbonded->updateParametersInContext(cuContext); nonbonded->updateParametersInContext(referenceContext); cuState = cuContext.getState(State::Forces | State::Energy); referenceState = referenceContext.getState(State::Forces | State::Energy); for (int i = 0; i < numParticles; i++) ASSERT_EQUAL_VEC(cuState.getForces()[i], referenceState.getForces()[i], tol); ASSERT_EQUAL_TOL(cuState.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol); }
void testDispersionCorrection() { // Create a box full of identical particles. int gridSize = 5; int numParticles = gridSize*gridSize*gridSize; double boxSize = gridSize*0.7; double cutoff = boxSize/3; System system; VerletIntegrator integrator(0.01); NonbondedForce* nonbonded = new NonbondedForce(); vector<Vec3> positions(numParticles); int index = 0; for (int i = 0; i < gridSize; i++) for (int j = 0; j < gridSize; j++) for (int k = 0; k < gridSize; k++) { system.addParticle(1.0); nonbonded->addParticle(0, 1.1, 0.5); positions[index] = Vec3(i*boxSize/gridSize, j*boxSize/gridSize, k*boxSize/gridSize); index++; } nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); nonbonded->setCutoffDistance(cutoff); system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); system.addForce(nonbonded); // See if the correction has the correct value. Context context(system, integrator, platform); context.setPositions(positions); double energy1 = context.getState(State::Energy).getPotentialEnergy(); nonbonded->setUseDispersionCorrection(false); context.reinitialize(); context.setPositions(positions); double energy2 = context.getState(State::Energy).getPotentialEnergy(); double term1 = (0.5*pow(1.1, 12)/pow(cutoff, 9))/9; double term2 = (0.5*pow(1.1, 6)/pow(cutoff, 3))/3; double expected = 8*M_PI*numParticles*numParticles*(term1-term2)/(boxSize*boxSize*boxSize); ASSERT_EQUAL_TOL(expected, energy1-energy2, 1e-4); // Now modify half the particles to be different, and see if it is still correct. int numType2 = 0; for (int i = 0; i < numParticles; i += 2) { nonbonded->setParticleParameters(i, 0, 1, 1); numType2++; } int numType1 = numParticles-numType2; nonbonded->updateParametersInContext(context); energy2 = context.getState(State::Energy).getPotentialEnergy(); nonbonded->setUseDispersionCorrection(true); context.reinitialize(); context.setPositions(positions); energy1 = context.getState(State::Energy).getPotentialEnergy(); term1 = ((numType1*(numType1+1))/2)*(0.5*pow(1.1, 12)/pow(cutoff, 9))/9; term2 = ((numType1*(numType1+1))/2)*(0.5*pow(1.1, 6)/pow(cutoff, 3))/3; term1 += ((numType2*(numType2+1))/2)*(1*pow(1.0, 12)/pow(cutoff, 9))/9; term2 += ((numType2*(numType2+1))/2)*(1*pow(1.0, 6)/pow(cutoff, 3))/3; double combinedSigma = 0.5*(1+1.1); double combinedEpsilon = sqrt(1*0.5); term1 += (numType1*numType2)*(combinedEpsilon*pow(combinedSigma, 12)/pow(cutoff, 9))/9; term2 += (numType1*numType2)*(combinedEpsilon*pow(combinedSigma, 6)/pow(cutoff, 3))/3; term1 /= (numParticles*(numParticles+1))/2; term2 /= (numParticles*(numParticles+1))/2; expected = 8*M_PI*numParticles*numParticles*(term1-term2)/(boxSize*boxSize*boxSize); ASSERT_EQUAL_TOL(expected, energy1-energy2, 1e-4); }
void testCutoff14() { System system; VerletIntegrator integrator(0.01); NonbondedForce* nonbonded = new NonbondedForce(); nonbonded->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic); for (int i = 0; i < 5; ++i) { system.addParticle(1.0); nonbonded->addParticle(0, 1.5, 0); } const double cutoff = 3.5; nonbonded->setCutoffDistance(cutoff); const double eps = 30.0; nonbonded->setReactionFieldDielectric(eps); vector<pair<int, int> > bonds; bonds.push_back(pair<int, int>(0, 1)); bonds.push_back(pair<int, int>(1, 2)); bonds.push_back(pair<int, int>(2, 3)); bonds.push_back(pair<int, int>(3, 4)); nonbonded->createExceptionsFromBonds(bonds, 0.0, 0.0); int first14, second14; for (int i = 0; i < nonbonded->getNumExceptions(); i++) { int particle1, particle2; double chargeProd, sigma, epsilon; nonbonded->getExceptionParameters(i, particle1, particle2, chargeProd, sigma, epsilon); if ((particle1 == 0 && particle2 == 3) || (particle1 == 3 && particle2 == 0)) first14 = i; if ((particle1 == 1 && particle2 == 4) || (particle1 == 4 && particle2 == 1)) second14 = i; } system.addForce(nonbonded); Context context(system, integrator, platform); vector<Vec3> positions(5); positions[0] = Vec3(0, 0, 0); positions[1] = Vec3(1, 0, 0); positions[2] = Vec3(2, 0, 0); positions[3] = Vec3(3, 0, 0); positions[4] = Vec3(4, 0, 0); for (int i = 1; i < 5; ++i) { // Test LJ forces nonbonded->setParticleParameters(0, 0, 1.5, 1); for (int j = 1; j < 5; ++j) nonbonded->setParticleParameters(j, 0, 1.5, 0); nonbonded->setParticleParameters(i, 0, 1.5, 1); nonbonded->setExceptionParameters(first14, 0, 3, 0, 1.5, i == 3 ? 0.5 : 0.0); nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0.0); context.reinitialize(); context.setPositions(positions); State state = context.getState(State::Forces | State::Energy); const vector<Vec3>& forces = state.getForces(); double r = positions[i][0]; double x = 1.5/r; double e = 1.0; double force = 4.0*e*(12*std::pow(x, 12.0)-6*std::pow(x, 6.0))/r; double energy = 4.0*e*(std::pow(x, 12.0)-std::pow(x, 6.0)); if (i == 3) { force *= 0.5; energy *= 0.5; } if (i < 3 || r > cutoff) { force = 0; energy = 0; } ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL); ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[i], TOL); ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); // Test Coulomb forces const double q = 0.7; nonbonded->setParticleParameters(0, q, 1.5, 0); nonbonded->setParticleParameters(i, q, 1.5, 0); nonbonded->setExceptionParameters(first14, 0, 3, i == 3 ? q*q/1.2 : 0, 1.5, 0); nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0); context.reinitialize(); context.setPositions(positions); state = context.getState(State::Forces | State::Energy); const vector<Vec3>& forces2 = state.getForces(); force = ONE_4PI_EPS0*q*q/(r*r); energy = ONE_4PI_EPS0*q*q/r; if (i == 3) { force /= 1.2; energy /= 1.2; } if (i < 3 || r > cutoff) { force = 0; energy = 0; } ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces2[0], TOL); ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces2[i], TOL); ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); } }
void testExclusionsAnd14() { System system; NonbondedForce* nonbonded = new NonbondedForce(); for (int i = 0; i < 5; ++i) { system.addParticle(1.0); nonbonded->addParticle(0, 1.5, 0); } vector<pair<int, int> > bonds; bonds.push_back(pair<int, int>(0, 1)); bonds.push_back(pair<int, int>(1, 2)); bonds.push_back(pair<int, int>(2, 3)); bonds.push_back(pair<int, int>(3, 4)); nonbonded->createExceptionsFromBonds(bonds, 0.0, 0.0); int first14, second14; for (int i = 0; i < nonbonded->getNumExceptions(); i++) { int particle1, particle2; double chargeProd, sigma, epsilon; nonbonded->getExceptionParameters(i, particle1, particle2, chargeProd, sigma, epsilon); if ((particle1 == 0 && particle2 == 3) || (particle1 == 3 && particle2 == 0)) first14 = i; if ((particle1 == 1 && particle2 == 4) || (particle1 == 4 && particle2 == 1)) second14 = i; } system.addForce(nonbonded); VerletIntegrator integrator(0.01); Context context(system, integrator, platform); for (int i = 1; i < 5; ++i) { // Test LJ forces vector<Vec3> positions(5); const double r = 1.0; for (int j = 0; j < 5; ++j) { nonbonded->setParticleParameters(j, 0, 1.5, 0); positions[j] = Vec3(0, j, 0); } nonbonded->setParticleParameters(0, 0, 1.5, 1); nonbonded->setParticleParameters(i, 0, 1.5, 1); nonbonded->setExceptionParameters(first14, 0, 3, 0, 1.5, i == 3 ? 0.5 : 0.0); nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0.0); positions[i] = Vec3(r, 0, 0); context.reinitialize(); context.setPositions(positions); State state = context.getState(State::Forces | State::Energy); const vector<Vec3>& forces = state.getForces(); double x = 1.5/r; double eps = 1.0; double force = 4.0*eps*(12*std::pow(x, 12.0)-6*std::pow(x, 6.0))/r; double energy = 4.0*eps*(std::pow(x, 12.0)-std::pow(x, 6.0)); if (i == 3) { force *= 0.5; energy *= 0.5; } if (i < 3) { force = 0; energy = 0; } ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL); ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[i], TOL); ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); // Test Coulomb forces nonbonded->setParticleParameters(0, 2, 1.5, 0); nonbonded->setParticleParameters(i, 2, 1.5, 0); nonbonded->setExceptionParameters(first14, 0, 3, i == 3 ? 4/1.2 : 0, 1.5, 0); nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0); context.reinitialize(); context.setPositions(positions); state = context.getState(State::Forces | State::Energy); const vector<Vec3>& forces2 = state.getForces(); force = ONE_4PI_EPS0*4/(r*r); energy = ONE_4PI_EPS0*4/r; if (i == 3) { force /= 1.2; energy /= 1.2; } if (i < 3) { force = 0; energy = 0; } ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces2[0], TOL); ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces2[i], TOL); ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL); } }