void testHarmonicBonds() { const int numParticles = 10; System system; HarmonicBondForce* bonds = new HarmonicBondForce(); system.addForce(bonds); // Create a chain of particles connected by harmonic bonds. vector<Vec3> positions(numParticles); for (int i = 0; i < numParticles; i++) { system.addParticle(1.0); positions[i] = Vec3(i, 0, 0); if (i > 0) bonds->addBond(i-1, i, 1+0.1*i, 1); } // Minimize it and check that all bonds are at their equilibrium distances. VerletIntegrator integrator(0.01); Context context(system, integrator, platform); context.setPositions(positions); LocalEnergyMinimizer::minimize(context, 1e-5); State state = context.getState(State::Positions); for (int i = 1; i < numParticles; i++) { Vec3 delta = state.getPositions()[i]-state.getPositions()[i-1]; ASSERT_EQUAL_TOL(1+0.1*i, sqrt(delta.dot(delta)), 1e-4); } }
void testSingleBond() { System system; system.addParticle(2.0); system.addParticle(2.0); VariableVerletIntegrator integrator(1e-6); HarmonicBondForce* forceField = new HarmonicBondForce(); forceField->addBond(0, 1, 1.5, 1); system.addForce(forceField); Context context(system, integrator, platform); vector<Vec3> positions(2); positions[0] = Vec3(-1, 0, 0); positions[1] = Vec3(1, 0, 0); context.setPositions(positions); // This is simply a harmonic oscillator, so compare it to the analytical solution. const double freq = 1.0;; State state = context.getState(State::Energy); const double initialEnergy = state.getKineticEnergy()+state.getPotentialEnergy(); for (int i = 0; i < 1000; ++i) { state = context.getState(State::Positions | State::Velocities | State::Energy); double time = state.getTime(); double expectedDist = 1.5+0.5*std::cos(freq*time); ASSERT_EQUAL_VEC(Vec3(-0.5*expectedDist, 0, 0), state.getPositions()[0], 0.02); ASSERT_EQUAL_VEC(Vec3(0.5*expectedDist, 0, 0), state.getPositions()[1], 0.02); double expectedSpeed = -0.5*freq*std::sin(freq*time); ASSERT_EQUAL_VEC(Vec3(-0.5*expectedSpeed, 0, 0), state.getVelocities()[0], 0.02); ASSERT_EQUAL_VEC(Vec3(0.5*expectedSpeed, 0, 0), state.getVelocities()[1], 0.02); double energy = state.getKineticEnergy()+state.getPotentialEnergy(); ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05); integrator.step(1); } }
void testTemperature() { const int numParticles = 8; const int numBonds = numParticles-1; const double temp = 10.0; System system; BrownianIntegrator integrator(temp, 2.0, 0.01); HarmonicBondForce* forceField = new HarmonicBondForce(); for (int i = 0; i < numParticles; ++i) system.addParticle(2.0); for (int i = 0; i < numBonds; ++i) forceField->addBond(i, i+1, 1.0, 5.0); system.addForce(forceField); Context context(system, integrator, platform); vector<Vec3> positions(numParticles); for (int i = 0; i < numParticles; ++i) positions[i] = Vec3(i, 0, 0); context.setPositions(positions); // Let it equilibrate. integrator.step(10000); // Now run it for a while and see if the temperature is correct. double pe = 0.0; const int steps = 50000; for (int i = 0; i < steps; ++i) { State state = context.getState(State::Energy); pe += state.getPotentialEnergy(); integrator.step(1); } pe /= steps; double expected = 0.5*numBonds*BOLTZ*temp; ASSERT_USUALLY_EQUAL_TOL(expected, pe, 0.1*expected); }
void testParallelComputation() { System system; const int numParticles = 200; for (int i = 0; i < numParticles; i++) system.addParticle(1.0); HarmonicBondForce* force = new HarmonicBondForce(); for (int i = 1; i < numParticles; i++) force->addBond(i-1, i, 1.1, i); system.addForce(force); vector<Vec3> positions(numParticles); for (int i = 0; i < numParticles; i++) positions[i] = Vec3(i, 0, 0); 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); 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 testSingleBond() { System system; system.addParticle(2.0); system.addParticle(2.0); double dt = 0.01; BrownianIntegrator integrator(0, 0.1, dt); HarmonicBondForce* forceField = new HarmonicBondForce(); forceField->addBond(0, 1, 1.5, 1); system.addForce(forceField); Context context(system, integrator, platform); vector<Vec3> positions(2); positions[0] = Vec3(-1, 0, 0); positions[1] = Vec3(1, 0, 0); context.setPositions(positions); // This is simply an overdamped harmonic oscillator, so compare it to the analytical solution. double rate = 2*1.0/(0.1*2.0); for (int i = 0; i < 1000; ++i) { State state = context.getState(State::Positions | State::Velocities); double time = state.getTime(); double expectedDist = 1.5+0.5*std::exp(-rate*time); ASSERT_EQUAL_VEC(Vec3(-0.5*expectedDist, 0, 0), state.getPositions()[0], 0.02); ASSERT_EQUAL_VEC(Vec3(0.5*expectedDist, 0, 0), state.getPositions()[1], 0.02); if (i > 0) { double expectedSpeed = -0.5*rate*std::exp(-rate*(time-0.5*dt)); ASSERT_EQUAL_VEC(Vec3(-0.5*expectedSpeed, 0, 0), state.getVelocities()[0], 0.11); ASSERT_EQUAL_VEC(Vec3(0.5*expectedSpeed, 0, 0), state.getVelocities()[1], 0.11); } integrator.step(1); } }
/** * Test a multiple time step r-RESPA integrator. */ void testRespa() { const int numParticles = 8; System system; system.setDefaultPeriodicBoxVectors(Vec3(4, 0, 0), Vec3(0, 4, 0), Vec3(0, 0, 4)); CustomIntegrator integrator(0.002); integrator.addComputePerDof("v", "v+0.5*dt*f1/m"); for (int i = 0; i < 2; i++) { integrator.addComputePerDof("v", "v+0.5*(dt/2)*f0/m"); integrator.addComputePerDof("x", "x+(dt/2)*v"); integrator.addComputePerDof("v", "v+0.5*(dt/2)*f0/m"); } integrator.addComputePerDof("v", "v+0.5*dt*f1/m"); HarmonicBondForce* bonds = new HarmonicBondForce(); for (int i = 0; i < numParticles-2; i++) bonds->addBond(i, i+1, 1.0, 0.5); system.addForce(bonds); NonbondedForce* nb = new NonbondedForce(); nb->setCutoffDistance(2.0); nb->setNonbondedMethod(NonbondedForce::Ewald); for (int i = 0; i < numParticles; ++i) { system.addParticle(i%2 == 0 ? 5.0 : 10.0); nb->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0); } nb->setForceGroup(1); nb->setReciprocalSpaceForceGroup(0); system.addForce(nb); Context context(system, integrator, platform); vector<Vec3> positions(numParticles); vector<Vec3> velocities(numParticles); OpenMM_SFMT::SFMT sfmt; init_gen_rand(0, sfmt); for (int i = 0; i < numParticles; ++i) { positions[i] = Vec3(i/2, (i+1)/2, 0); velocities[i] = Vec3(genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5); } context.setPositions(positions); context.setVelocities(velocities); // Simulate it and monitor energy conservations. double initialEnergy = 0.0; for (int i = 0; i < 1000; ++i) { State state = context.getState(State::Energy); double energy = state.getKineticEnergy()+state.getPotentialEnergy(); if (i == 1) initialEnergy = energy; else if (i > 1) ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05); integrator.step(2); } }
/** * Test a Monte Carlo integrator that uses global variables and depends on energy. */ void testMonteCarlo() { System system; system.addParticle(1.0); system.addParticle(1.0); CustomIntegrator integrator(0.1); const double kT = BOLTZ*300.0; integrator.addGlobalVariable("kT", kT); integrator.addGlobalVariable("oldE", 0); integrator.addGlobalVariable("accept", 0); integrator.addPerDofVariable("oldx", 0); integrator.addComputeGlobal("oldE", "energy"); integrator.addComputePerDof("oldx", "x"); integrator.addComputePerDof("x", "x+dt*gaussian"); integrator.addComputeGlobal("accept", "step(exp((oldE-energy)/kT)-uniform)"); integrator.addComputePerDof("x", "accept*x + (1-accept)*oldx"); HarmonicBondForce* forceField = new HarmonicBondForce(); forceField->addBond(0, 1, 2.0, 10.0); system.addForce(forceField); Context context(system, integrator, platform); vector<Vec3> positions(2); positions[0] = Vec3(-1, 0, 0); positions[1] = Vec3(1, 0, 0); context.setPositions(positions); // Compute the histogram of distances and see if it satisfies a Boltzmann distribution. const int numBins = 100; const double maxDist = 4.0; const int numIterations = 5000; vector<int> counts(numBins, 0); for (int i = 0; i < numIterations; ++i) { integrator.step(10); State state = context.getState(State::Positions); Vec3 delta = state.getPositions()[0]-state.getPositions()[1]; double dist = sqrt(delta.dot(delta)); if (dist < maxDist) counts[(int) (numBins*dist/maxDist)]++; } vector<double> expected(numBins, 0); double sum = 0; for (int i = 0; i < numBins; i++) { double dist = (i+0.5)*maxDist/numBins; expected[i] = dist*dist*exp(-5.0*(dist-2)*(dist-2)/kT); sum += expected[i]; } for (int i = 0; i < numBins; i++) ASSERT_USUALLY_EQUAL_TOL((double) counts[i]/numIterations, expected[i]/sum, 0.01); }
void testWithoutThermostat() { const int numParticles = 20; const int numCopies = 10; const double temperature = 300.0; const double mass = 2.0; // Create a chain of particles. System system; HarmonicBondForce* bonds = new HarmonicBondForce(); system.addForce(bonds); for (int i = 0; i < numParticles; i++) { system.addParticle(mass); if (i > 0) bonds->addBond(i-1, i, 1.0, 1000.0); } RPMDIntegrator integ(numCopies, temperature, 1.0, 0.001); integ.setApplyThermostat(false); Platform& platform = Platform::getPlatformByName("Reference"); Context context(system, integ, platform); OpenMM_SFMT::SFMT sfmt; init_gen_rand(0, sfmt); vector<vector<Vec3> > positions(numCopies); for (int i = 0; i < numCopies; i++) { positions[i].resize(numParticles); for (int j = 0; j < numParticles; j++) positions[i][j] = Vec3(0.95*j, 0.01*genrand_real2(sfmt), 0.01*genrand_real2(sfmt)); integ.setPositions(i, positions[i]); } // Simulate it and see if the energy remains constant. double initialEnergy; int numSteps = 100; for (int i = 0; i < numSteps; i++) { integ.step(1); double energy = integ.getTotalEnergy(); if (i == 0) initialEnergy = energy; else ASSERT_EQUAL_TOL(initialEnergy, energy, 1e-4); } }
void testMotionRemoval() { const int numParticles = 8; const double temp = 100.0; const double collisionFreq = 10.0; ReferencePlatform platform; System system; VerletIntegrator integrator(0.01); HarmonicBondForce* bonds = new HarmonicBondForce(); bonds->addBond(2, 3, 2.0, 0.5); system.addForce(bonds); NonbondedForce* nonbonded = new NonbondedForce(); for (int i = 0; i < numParticles; ++i) { system.addParticle(i+1); nonbonded->addParticle((i%2 == 0 ? 1.0 : -1.0), 1.0, 5.0); } system.addForce(nonbonded); CMMotionRemover* remover = new CMMotionRemover(); system.addForce(remover); Context context(system, integrator, platform); vector<Vec3> positions(numParticles); vector<Vec3> velocities(numParticles); OpenMM_SFMT::SFMT sfmt; init_gen_rand(0, sfmt); for (int i = 0; i < numParticles; ++i) { positions[i] = Vec3((i%2 == 0 ? 2 : -2), (i%4 < 2 ? 2 : -2), (i < 4 ? 2 : -2)); velocities[i] = Vec3(genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5); } context.setPositions(positions); context.setVelocities(velocities); // Now run it for a while and see if the center of mass remains fixed. Vec3 cmPos = calcCM(context.getState(State::Positions).getPositions(), system); for (int i = 0; i < 1000; ++i) { integrator.step(1); State state = context.getState(State::Positions | State::Velocities); Vec3 pos = calcCM(state.getPositions(), system); ASSERT_EQUAL_VEC(cmPos, pos, 1e-2); Vec3 vel = calcCM(state.getVelocities(), system); ASSERT_EQUAL_VEC(Vec3(0, 0, 0), vel, 1e-2); } }
void testBonds() { ReferencePlatform platform; System system; system.addParticle(1.0); system.addParticle(1.0); system.addParticle(1.0); VerletIntegrator integrator(0.01); HarmonicBondForce* forceField = new HarmonicBondForce(); forceField->addBond(0, 1, 1.5, 0.8); forceField->addBond(1, 2, 1.2, 0.7); system.addForce(forceField); Context context(system, integrator, platform); vector<Vec3> positions(3); positions[0] = Vec3(0, 2, 0); positions[1] = Vec3(0, 0, 0); positions[2] = Vec3(1, 0, 0); context.setPositions(positions); State state = context.getState(State::Forces | State::Energy); { const vector<Vec3>& forces = state.getForces(); ASSERT_EQUAL_VEC(Vec3(0, -0.8*0.5, 0), forces[0], TOL); ASSERT_EQUAL_VEC(Vec3(0.7*0.2, 0, 0), forces[2], TOL); ASSERT_EQUAL_VEC(Vec3(-forces[0][0]-forces[2][0], -forces[0][1]-forces[2][1], -forces[0][2]-forces[2][2]), forces[1], TOL); ASSERT_EQUAL_TOL(0.5*0.8*0.5*0.5 + 0.5*0.7*0.2*0.2, state.getPotentialEnergy(), TOL); } // Try changing the bond parameters and make sure it's still correct. forceField->setBondParameters(0, 0, 1, 1.6, 0.9); forceField->setBondParameters(1, 1, 2, 1.3, 0.8); forceField->updateParametersInContext(context); state = context.getState(State::Forces | State::Energy); { const vector<Vec3>& forces = state.getForces(); ASSERT_EQUAL_VEC(Vec3(0, -0.9*0.4, 0), forces[0], TOL); ASSERT_EQUAL_VEC(Vec3(0.8*0.3, 0, 0), forces[2], TOL); ASSERT_EQUAL_VEC(Vec3(-forces[0][0]-forces[2][0], -forces[0][1]-forces[2][1], -forces[0][2]-forces[2][2]), forces[1], TOL); ASSERT_EQUAL_TOL(0.5*0.9*0.4*0.4 + 0.5*0.8*0.3*0.3, state.getPotentialEnergy(), TOL); } }
/** * Test a simple leapfrog integrator on a single bond. */ void testSingleBond() { System system; system.addParticle(2.0); system.addParticle(2.0); const double dt = 0.01; CustomIntegrator integrator(dt); integrator.addComputePerDof("v", "v+dt*f/m"); integrator.addComputePerDof("x", "x+dt*v"); integrator.setKineticEnergyExpression("m*v1*v1/2; v1=v+0.5*dt*f/m"); HarmonicBondForce* forceField = new HarmonicBondForce(); forceField->addBond(0, 1, 1.5, 1); system.addForce(forceField); Context context(system, integrator, platform); vector<Vec3> positions(2); positions[0] = Vec3(-1, 0, 0); positions[1] = Vec3(1, 0, 0); context.setPositions(positions); vector<Vec3> velocities(2); velocities[0] = Vec3(-0.5*dt*0.5*0.5, 0, 0); velocities[1] = Vec3(0.5*dt*0.5*0.5, 0, 0); context.setVelocities(velocities); // This is simply a harmonic oscillator, so compare it to the analytical solution. const double freq = 1.0;; for (int i = 0; i < 1000; ++i) { State state = context.getState(State::Positions | State::Velocities | State::Energy); double time = state.getTime(); double expectedDist = 1.5+0.5*std::cos(freq*time); ASSERT_EQUAL_VEC(Vec3(-0.5*expectedDist, 0, 0), state.getPositions()[0], 1e-4); ASSERT_EQUAL_VEC(Vec3(0.5*expectedDist, 0, 0), state.getPositions()[1], 1e-4); double expectedSpeed = -0.5*freq*std::sin(freq*(time-dt/2)); ASSERT_EQUAL_VEC(Vec3(-0.5*expectedSpeed, 0, 0), state.getVelocities()[0], 1e-4); ASSERT_EQUAL_VEC(Vec3(0.5*expectedSpeed, 0, 0), state.getVelocities()[1], 1e-4); double energy = state.getKineticEnergy()+state.getPotentialEnergy(); ASSERT_EQUAL_TOL(0.5*0.5*0.5, energy, 1e-4); integrator.step(1); } }
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); }
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 testWithoutThermostat() { const int numParticles = 20; const int numCopies = 10; const double temperature = 300.0; const double mass = 2.0; // Create a chain of particles. System system; HarmonicBondForce* bonds = new HarmonicBondForce(); system.addForce(bonds); for (int i = 0; i < numParticles; i++) { system.addParticle(mass); if (i > 0) bonds->addBond(i-1, i, 1.0, 1000.0); } RPMDIntegrator integ(numCopies, temperature, 1.0, 0.001); integ.setApplyThermostat(false); Platform& platform = Platform::getPlatformByName("CUDA"); Context context(system, integ, platform); OpenMM_SFMT::SFMT sfmt; init_gen_rand(0, sfmt); vector<vector<Vec3> > positions(numCopies); for (int i = 0; i < numCopies; i++) { positions[i].resize(numParticles); for (int j = 0; j < numParticles; j++) positions[i][j] = Vec3(0.95*j, 0.01*genrand_real2(sfmt), 0.01*genrand_real2(sfmt)); integ.setPositions(i, positions[i]); } // Simulate it and see if the energy remains constant. double initialEnergy; int numSteps = 100; const double hbar = 1.054571628e-34*AVOGADRO/(1000*1e-12); const double wn = numCopies*BOLTZ*temperature/hbar; const double springConstant = mass*wn*wn; for (int i = 0; i < numSteps; i++) { integ.step(1); // Sum the energies of all the copies. double energy = 0.0; for (int j = 0; j < numCopies; j++) { State state = integ.getState(j, State::Positions | State::Energy); positions[j] = state.getPositions(); energy += state.getPotentialEnergy()+state.getKineticEnergy(); } // Add the energy from the springs connecting copies. for (int j = 0; j < numCopies; j++) { int previous = (j == 0 ? numCopies-1 : j-1); for (int k = 0; k < numParticles; k++) { Vec3 delta = positions[j][k]-positions[previous][k]; energy += 0.5*springConstant*delta.dot(delta); } } if (i == 0) initialEnergy = energy; else ASSERT_EQUAL_TOL(initialEnergy, energy, 1e-4); } }
void testLargeSystem() { 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(); HarmonicBondForce* bonds = new HarmonicBondForce(); vector<Vec3> positions(numParticles); vector<Vec3> velocities(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]); velocities[2*i] = Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt)); velocities[2*i+1] = Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt)); bonds->addBond(2*i, 2*i+1, 1.0, 0.1); nonbonded->addException(2*i, 2*i+1, 0.0, 0.15, 0.0); } // Try with cutoffs but not periodic boundary conditions, and make sure the cl and Reference // platforms agree. nonbonded->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic); nonbonded->setCutoffDistance(cutoff); system.addForce(nonbonded); system.addForce(bonds); VerletIntegrator integrator1(0.01); VerletIntegrator integrator2(0.01); Context cuContext(system, integrator1, platform); Context referenceContext(system, integrator2, reference); cuContext.setPositions(positions); cuContext.setVelocities(velocities); referenceContext.setPositions(positions); referenceContext.setVelocities(velocities); State cuState = cuContext.getState(State::Positions | State::Velocities | State::Forces | State::Energy); State referenceState = referenceContext.getState(State::Positions | State::Velocities | State::Forces | State::Energy); for (int i = 0; i < numParticles; i++) { ASSERT_EQUAL_VEC(cuState.getPositions()[i], referenceState.getPositions()[i], tol); ASSERT_EQUAL_VEC(cuState.getVelocities()[i], referenceState.getVelocities()[i], tol); ASSERT_EQUAL_VEC(cuState.getForces()[i], referenceState.getForces()[i], tol); } ASSERT_EQUAL_TOL(cuState.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol); // Now do the same thing with periodic boundary conditions. nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); cuContext.reinitialize(); referenceContext.reinitialize(); cuContext.setPositions(positions); cuContext.setVelocities(velocities); referenceContext.setPositions(positions); referenceContext.setVelocities(velocities); cuState = cuContext.getState(State::Positions | State::Velocities | State::Forces | State::Energy); referenceState = referenceContext.getState(State::Positions | State::Velocities | State::Forces | State::Energy); for (int i = 0; i < numParticles; i++) { double dx = cuState.getPositions()[i][0]-referenceState.getPositions()[i][0]; double dy = cuState.getPositions()[i][1]-referenceState.getPositions()[i][1]; double dz = cuState.getPositions()[i][2]-referenceState.getPositions()[i][2]; ASSERT_EQUAL_TOL(fmod(cuState.getPositions()[i][0]-referenceState.getPositions()[i][0], boxSize), 0, tol); ASSERT_EQUAL_TOL(fmod(cuState.getPositions()[i][1]-referenceState.getPositions()[i][1], boxSize), 0, tol); ASSERT_EQUAL_TOL(fmod(cuState.getPositions()[i][2]-referenceState.getPositions()[i][2], boxSize), 0, tol); ASSERT_EQUAL_VEC(cuState.getVelocities()[i], referenceState.getVelocities()[i], tol); ASSERT_EQUAL_VEC(cuState.getForces()[i], referenceState.getForces()[i], tol); } ASSERT_EQUAL_TOL(cuState.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol); }
void testWithBarostat() { const int gridSize = 3; const int numMolecules = gridSize*gridSize*gridSize; const int numParticles = numMolecules*2; const int numCopies = 5; const double spacing = 2.0; const double cutoff = 3.0; const double boxSize = spacing*(gridSize+1); const double temperature = 300.0; System system; system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); HarmonicBondForce* bonds = new HarmonicBondForce(); system.addForce(bonds); NonbondedForce* nonbonded = new NonbondedForce(); nonbonded->setCutoffDistance(cutoff); nonbonded->setNonbondedMethod(NonbondedForce::PME); nonbonded->setForceGroup(1); nonbonded->setReciprocalSpaceForceGroup(2); system.addForce(nonbonded); system.addForce(new MonteCarloBarostat(0.5, temperature)); // Create a cloud of molecules. OpenMM_SFMT::SFMT sfmt; init_gen_rand(0, sfmt); vector<Vec3> positions(numParticles); for (int i = 0; i < numMolecules; i++) { system.addParticle(1.0); system.addParticle(1.0); nonbonded->addParticle(-0.2, 0.2, 0.2); nonbonded->addParticle(0.2, 0.2, 0.2); nonbonded->addException(2*i, 2*i+1, 0, 1, 0); bonds->addBond(2*i, 2*i+1, 1.0, 10000.0); } RPMDIntegrator integ(numCopies, temperature, 50.0, 0.001); Platform& platform = Platform::getPlatformByName("Reference"); Context context(system, integ, platform); for (int copy = 0; copy < numCopies; copy++) { for (int i = 0; i < gridSize; i++) for (int j = 0; j < gridSize; j++) for (int k = 0; k < gridSize; k++) { Vec3 pos = Vec3(spacing*(i+0.02*genrand_real2(sfmt)), spacing*(j+0.02*genrand_real2(sfmt)), spacing*(k+0.02*genrand_real2(sfmt))); int index = k+gridSize*(j+gridSize*i); positions[2*index] = pos; positions[2*index+1] = Vec3(pos[0]+1.0, pos[1], pos[2]); } integ.setPositions(copy, positions); } // Check the temperature. const int numSteps = 500; integ.step(100); vector<double> ke(numCopies, 0.0); for (int i = 0; i < numSteps; i++) { integ.step(1); vector<State> state(numCopies); for (int j = 0; j < numCopies; j++) state[j] = integ.getState(j, State::Velocities, true); for (int j = 0; j < numParticles; j++) { for (int k = 0; k < numCopies; k++) { Vec3 v = state[k].getVelocities()[j]; ke[k] += 0.5*system.getParticleMass(j)*v.dot(v); } } } double meanKE = 0.0; for (int i = 0; i < numCopies; i++) meanKE += ke[i]; meanKE /= numSteps*numCopies; double expectedKE = 0.5*numCopies*numParticles*3*BOLTZ*temperature; ASSERT_USUALLY_EQUAL_TOL(expectedKE, meanKE, 1e-2); }
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); } }
/** * Test evaluating force groups separately. */ void testForceGroups() { System system; system.addParticle(2.0); system.addParticle(2.0); CustomIntegrator integrator(0.01); integrator.addPerDofVariable("outf", 0); integrator.addPerDofVariable("outf1", 0); integrator.addPerDofVariable("outf2", 0); integrator.addGlobalVariable("oute", 0); integrator.addGlobalVariable("oute1", 0); integrator.addGlobalVariable("oute2", 0); integrator.addComputePerDof("outf", "f"); integrator.addComputePerDof("outf1", "f1"); integrator.addComputePerDof("outf2", "f2"); integrator.addComputeGlobal("oute", "energy"); integrator.addComputeGlobal("oute1", "energy1"); integrator.addComputeGlobal("oute2", "energy2"); HarmonicBondForce* bonds = new HarmonicBondForce(); bonds->addBond(0, 1, 1.5, 1.1); bonds->setForceGroup(1); system.addForce(bonds); NonbondedForce* nb = new NonbondedForce(); nb->addParticle(0.2, 1, 0); nb->addParticle(0.2, 1, 0); nb->setForceGroup(2); system.addForce(nb); Context context(system, integrator, platform); vector<Vec3> positions(2); positions[0] = Vec3(-1, 0, 0); positions[1] = Vec3(1, 0, 0); context.setPositions(positions); // See if the various forces are computed correctly. integrator.step(1); vector<Vec3> f, f1, f2; double e1 = 0.5*1.1*0.5*0.5; double e2 = 138.935456*0.2*0.2/2.0; integrator.getPerDofVariable(0, f); integrator.getPerDofVariable(1, f1); integrator.getPerDofVariable(2, f2); ASSERT_EQUAL_VEC(Vec3(1.1*0.5, 0, 0), f1[0], 1e-5); ASSERT_EQUAL_VEC(Vec3(-1.1*0.5, 0, 0), f1[1], 1e-5); ASSERT_EQUAL_VEC(Vec3(-138.935456*0.2*0.2/4.0, 0, 0), f2[0], 1e-5); ASSERT_EQUAL_VEC(Vec3(138.935456*0.2*0.2/4.0, 0, 0), f2[1], 1e-5); ASSERT_EQUAL_VEC(f1[0]+f2[0], f[0], 1e-5); ASSERT_EQUAL_VEC(f1[1]+f2[1], f[1], 1e-5); ASSERT_EQUAL_TOL(e1, integrator.getGlobalVariable(1), 1e-5); ASSERT_EQUAL_TOL(e2, integrator.getGlobalVariable(2), 1e-5); ASSERT_EQUAL_TOL(e1+e2, integrator.getGlobalVariable(0), 1e-5); // Make sure they also match the values returned by the Context. State s = context.getState(State::Forces | State::Energy, false); State s1 = context.getState(State::Forces | State::Energy, false, 2); State s2 = context.getState(State::Forces | State::Energy, false, 4); vector<Vec3> c, c1, c2; c = context.getState(State::Forces, false).getForces(); c1 = context.getState(State::Forces, false, 2).getForces(); c2 = context.getState(State::Forces, false, 4).getForces(); ASSERT_EQUAL_VEC(f[0], c[0], 1e-5); ASSERT_EQUAL_VEC(f[1], c[1], 1e-5); ASSERT_EQUAL_VEC(f1[0], c1[0], 1e-5); ASSERT_EQUAL_VEC(f1[1], c1[1], 1e-5); ASSERT_EQUAL_VEC(f2[0], c2[0], 1e-5); ASSERT_EQUAL_VEC(f2[1], c2[1], 1e-5); ASSERT_EQUAL_TOL(s.getPotentialEnergy(), integrator.getGlobalVariable(0), 1e-5); ASSERT_EQUAL_TOL(s1.getPotentialEnergy(), integrator.getGlobalVariable(1), 1e-5); ASSERT_EQUAL_TOL(s2.getPotentialEnergy(), integrator.getGlobalVariable(2), 1e-5); }