void ReferenceCalcDrudeForceKernel::initialize(const System& system, const DrudeForce& force) { // Initialize particle parameters. int numParticles = force.getNumParticles(); particle.resize(numParticles); particle1.resize(numParticles); particle2.resize(numParticles); particle3.resize(numParticles); particle4.resize(numParticles); charge.resize(numParticles); polarizability.resize(numParticles); aniso12.resize(numParticles); aniso34.resize(numParticles); for (int i = 0; i < numParticles; i++) force.getParticleParameters(i, particle[i], particle1[i], particle2[i], particle3[i], particle4[i], charge[i], polarizability[i], aniso12[i], aniso34[i]); // Initialize screened pair parameters. int numPairs = force.getNumScreenedPairs(); pair1.resize(numPairs); pair2.resize(numPairs); pairThole.resize(numPairs); for (int i = 0; i < numPairs; i++) force.getScreenedPairParameters(i, pair1[i], pair2[i], pairThole[i]); }
void testAnisotropicParticle() { const double k = ONE_4PI_EPS0*1.5; const double charge = 0.1; const double alpha = ONE_4PI_EPS0*charge*charge/k; const double a1 = 0.8; const double a2 = 1.1; const double k1 = k/a1; const double k2 = k/a2; const double k3 = k/(3-a1-a2); System system; system.addParticle(1.0); system.addParticle(1.0); system.addParticle(1.0); system.addParticle(1.0); system.addParticle(1.0); DrudeForce* drude = new DrudeForce(); drude->addParticle(1, 0, 2, 3, 4, charge, alpha, a1, a2); system.addForce(drude); vector<Vec3> positions(5); positions[0] = Vec3(0, 0, 0); positions[1] = Vec3(0.1, -0.5, 0.8); positions[2] = Vec3(0, 2, 0); positions[3] = Vec3(1, 2, 0); positions[4] = Vec3(1, 2, 3); validateForce(system, positions, 0.5*k1*0.5*0.5 + 0.5*k2*0.8*0.8 + 0.5*k3*0.1*0.1); }
void ReferenceIntegrateDrudeSCFStepKernel::initialize(const System& system, const DrudeSCFIntegrator& integrator, const DrudeForce& force) { // Identify Drude particles. for (int i = 0; i < force.getNumParticles(); i++) { int p, p1, p2, p3, p4; double charge, polarizability, aniso12, aniso34; force.getParticleParameters(i, p, p1, p2, p3, p4, charge, polarizability, aniso12, aniso34); drudeParticles.push_back(p); } // Record particle masses. vector<RealOpenMM> particleMass; for (int i = 0; i < system.getNumParticles(); i++) { double mass = system.getParticleMass(i); particleMass.push_back(mass); particleInvMass.push_back(mass == 0.0 ? 0.0 : 1.0/mass); } // Initialize the energy minimizer. minimizerPos = lbfgs_malloc(drudeParticles.size()*3); if (minimizerPos == NULL) throw OpenMMException("DrudeSCFIntegrator: Failed to allocate memory"); lbfgs_parameter_init(&minimizerParams); minimizerParams.linesearch = LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE; if (sizeof(RealOpenMM) < 8) minimizerParams.xtol = 1e-7; }
void testThole() { const double k = ONE_4PI_EPS0*1.5; const double charge = 0.1; const double alpha = ONE_4PI_EPS0*charge*charge/k; const double thole = 2.5; System system; system.addParticle(1.0); system.addParticle(1.0); system.addParticle(1.0); system.addParticle(1.0); DrudeForce* drude = new DrudeForce(); drude->addParticle(1, 0, -1, -1, -1, charge, alpha, 1, 1); drude->addParticle(3, 2, -1, -1, -1, charge, alpha, 1, 1); drude->addScreenedPair(0, 1, thole); system.addForce(drude); vector<Vec3> positions(4); positions[0] = Vec3(0, 0, 0); positions[1] = Vec3(0, -0.5, 0); positions[2] = Vec3(1, 0, 0); positions[3] = Vec3(1, 0, 0.3); double energySpring1 = 0.5*k*0.5*0.5; double energySpring2 = 0.5*k*0.3*0.3; double energyDipole = 0.0; double q[] = {-charge, charge, -charge, charge}; for (int i = 0; i < 2; i++) for (int j = 2; j < 4; j++) { Vec3 delta = positions[i]-positions[j]; double r = sqrt(delta.dot(delta)); energyDipole += ONE_4PI_EPS0*q[i]*q[j]*computeScreening(r, thole, alpha, alpha)/r; } validateForce(system, positions, energySpring1+energySpring2+energyDipole); }
void ReferenceIntegrateDrudeLangevinStepKernel::initialize(const System& system, const DrudeLangevinIntegrator& integrator, const DrudeForce& force) { SimTKOpenMMUtilities::setRandomNumberSeed((unsigned int) integrator.getRandomNumberSeed()); // Identify particle pairs and ordinary particles. set<int> particles; for (int i = 0; i < system.getNumParticles(); i++) { particles.insert(i); double mass = system.getParticleMass(i); particleMass.push_back(mass); particleInvMass.push_back(mass == 0.0 ? 0.0 : 1.0/mass); } for (int i = 0; i < force.getNumParticles(); i++) { int p, p1, p2, p3, p4; double charge, polarizability, aniso12, aniso34; force.getParticleParameters(i, p, p1, p2, p3, p4, charge, polarizability, aniso12, aniso34); particles.erase(p); particles.erase(p1); pairParticles.push_back(make_pair(p, p1)); double m1 = system.getParticleMass(p); double m2 = system.getParticleMass(p1); pairInvTotalMass.push_back(1.0/(m1+m2)); pairInvReducedMass.push_back((m1+m2)/(m1*m2)); } normalParticles.insert(normalParticles.begin(), particles.begin(), particles.end()); }
void CudaIntegrateDrudeSCFStepKernel::initialize(const System& system, const DrudeSCFIntegrator& integrator, const DrudeForce& force) { cu.getPlatformData().initializeContexts(system); cu.setAsCurrent(); // Identify Drude particles. for (int i = 0; i < force.getNumParticles(); i++) { int p, p1, p2, p3, p4; double charge, polarizability, aniso12, aniso34; force.getParticleParameters(i, p, p1, p2, p3, p4, charge, polarizability, aniso12, aniso34); drudeParticles.push_back(p); } // Initialize the energy minimizer. minimizerPos = lbfgs_malloc(drudeParticles.size()*3); if (minimizerPos == NULL) throw OpenMMException("DrudeSCFIntegrator: Failed to allocate memory"); lbfgs_parameter_init(&minimizerParams); minimizerParams.linesearch = LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE; // Create the kernels. map<string, string> defines; defines["NUM_ATOMS"] = cu.intToString(cu.getNumAtoms()); defines["PADDED_NUM_ATOMS"] = cu.intToString(cu.getPaddedNumAtoms()); CUmodule module = cu.createModule(CudaKernelSources::verlet, defines, ""); kernel1 = cu.getKernel(module, "integrateVerletPart1"); kernel2 = cu.getKernel(module, "integrateVerletPart2"); prevStepSize = -1.0; }
void testForceEnergyConsistency() { // Create a box of polarizable particles. const int gridSize = 3; const int numAtoms = gridSize*gridSize*gridSize; const double spacing = 0.6; const double boxSize = spacing*(gridSize+1); const double temperature = 300.0; const double temperatureDrude = 10.0; System system; vector<Vec3> positions; NonbondedForce* nonbonded = new NonbondedForce(); DrudeForce* drude = new DrudeForce(); system.addForce(nonbonded); system.addForce(drude); system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); nonbonded->setNonbondedMethod(NonbondedForce::PME); nonbonded->setCutoffDistance(1.0); nonbonded->setUseSwitchingFunction(true); nonbonded->setSwitchingDistance(0.9); nonbonded->setEwaldErrorTolerance(5e-5); for (int i = 0; i < numAtoms; i++) { int startIndex = system.getNumParticles(); system.addParticle(1.0); system.addParticle(1.0); nonbonded->addParticle(1.0, 0.3, 1.0); nonbonded->addParticle(-1.0, 0.3, 1.0); nonbonded->addException(startIndex, startIndex+1, 0, 1, 0); drude->addParticle(startIndex+1, startIndex, -1, -1, -1, -1.0, 0.001, 1, 1); } for (int i = 0; i < gridSize; i++) for (int j = 0; j < gridSize; j++) for (int k = 0; k < gridSize; k++) { Vec3 pos(i*spacing, j*spacing, k*spacing); positions.push_back(pos); positions.push_back(pos); } // Simulate it and check that force and energy remain consistent. DrudeLangevinIntegrator integ(temperature, 50.0, temperatureDrude, 50.0, 0.001); Platform& platform = Platform::getPlatformByName("Reference"); Context context(system, integ, platform); context.setPositions(positions); State prevState; for (int i = 0; i < 100; i++) { State state = context.getState(State::Energy | State::Forces | State::Positions); if (i > 0) { double expectedEnergyChange = 0; for (int j = 0; j < system.getNumParticles(); j++) { Vec3 delta = state.getPositions()[j]-prevState.getPositions()[j]; expectedEnergyChange -= 0.5*(state.getForces()[j]+prevState.getForces()[j]).dot(delta); } ASSERT_EQUAL_TOL(expectedEnergyChange, state.getPotentialEnergy()-prevState.getPotentialEnergy(), 0.05); } prevState = state; integ.step(1); } }
void testSinglePair() { const double temperature = 300.0; const double temperatureDrude = 10.0; const double k = ONE_4PI_EPS0*1.5; const double charge = 0.1; const double alpha = ONE_4PI_EPS0*charge*charge/k; const double mass1 = 1.0; const double mass2 = 0.1; const double totalMass = mass1+mass2; const double reducedMass = (mass1*mass2)/(mass1+mass2); const double maxDistance = 0.05; System system; system.addParticle(mass1); system.addParticle(mass2); DrudeForce* drude = new DrudeForce(); drude->addParticle(1, 0, -1, -1, -1, charge, alpha, 1, 1); system.addForce(drude); vector<Vec3> positions(2); positions[0] = Vec3(0, 0, 0); positions[1] = Vec3(0, 0, 0); DrudeLangevinIntegrator integ(temperature, 20.0, temperatureDrude, 20.0, 0.003); integ.setMaxDrudeDistance(maxDistance); Platform& platform = Platform::getPlatformByName("Reference"); Context context(system, integ, platform); context.setPositions(positions); // Equilibrate. integ.step(1000); // Compute the internal and center of mass temperatures. double keCM = 0, keInternal = 0; int numSteps = 10000; for (int i = 0; i < numSteps; i++) { integ.step(10); State state = context.getState(State::Velocities | State::Positions); const vector<Vec3>& vel = state.getVelocities(); Vec3 velCM = vel[0]*(mass1/totalMass) + vel[1]*(mass2/totalMass); keCM += 0.5*totalMass*velCM.dot(velCM); Vec3 velInternal = vel[0]-vel[1]; keInternal += 0.5*reducedMass*velInternal.dot(velInternal); Vec3 delta = state.getPositions()[0]-state.getPositions()[1]; double distance = sqrt(delta.dot(delta)); ASSERT(distance <= maxDistance*(1+1e-6)); } ASSERT_USUALLY_EQUAL_TOL(3*0.5*BOLTZ*temperature, keCM/numSteps, 0.1); ASSERT_USUALLY_EQUAL_TOL(3*0.5*BOLTZ*temperatureDrude, keInternal/numSteps, 0.01); }
void testSingleParticle() { const double k = ONE_4PI_EPS0*1.5; const double charge = 0.1; const double alpha = ONE_4PI_EPS0*charge*charge/k; System system; system.addParticle(1.0); system.addParticle(1.0); DrudeForce* drude = new DrudeForce(); drude->addParticle(1, 0, -1, -1, -1, charge, alpha, 1, 1); system.addForce(drude); vector<Vec3> positions(2); positions[0] = Vec3(-1, 0, 0); positions[1] = Vec3(2, 0, 0); validateForce(system, positions, 0.5*k*3*3); }
void ReferenceIntegrateDrudeSCFStepKernel::initialize(const System& system, const DrudeSCFIntegrator& integrator, const DrudeForce& force) { // Identify Drude particles. for (int i = 0; i < force.getNumParticles(); i++) { int p, p1, p2, p3, p4; double charge, polarizability, aniso12, aniso34; force.getParticleParameters(i, p, p1, p2, p3, p4, charge, polarizability, aniso12, aniso34); drudeParticles.push_back(p); } // Record particle masses. vector<RealOpenMM> particleMass; for (int i = 0; i < system.getNumParticles(); i++) { double mass = system.getParticleMass(i); particleMass.push_back(mass); particleInvMass.push_back(mass == 0.0 ? 0.0 : 1.0/mass); } // Prepare constraints. int numConstraints = system.getNumConstraints(); if (numConstraints > 0) { vector<pair<int, int> > constraintIndices(numConstraints); vector<RealOpenMM> constraintDistances(numConstraints); for (int i = 0; i < numConstraints; ++i) { int particle1, particle2; double distance; system.getConstraintParameters(i, particle1, particle2, distance); constraintIndices[i].first = particle1; constraintIndices[i].second = particle2; constraintDistances[i] = static_cast<RealOpenMM>(distance); } vector<ReferenceCCMAAlgorithm::AngleInfo> angles; findAnglesForCCMA(system, angles); constraints = new ReferenceCCMAAlgorithm(system.getNumParticles(), numConstraints, constraintIndices, constraintDistances, particleMass, angles, (RealOpenMM)integrator.getConstraintTolerance()); } // Initialize the energy minimizer. minimizerPos = lbfgs_malloc(drudeParticles.size()*3); if (minimizerPos == NULL) throw OpenMMException("DrudeSCFIntegrator: Failed to allocate memory"); lbfgs_parameter_init(&minimizerParams); minimizerParams.linesearch = LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE; if (sizeof(RealOpenMM) < 8) minimizerParams.xtol = 1e-7; }
void ReferenceIntegrateDrudeLangevinStepKernel::initialize(const System& system, const DrudeLangevinIntegrator& integrator, const DrudeForce& force) { SimTKOpenMMUtilities::setRandomNumberSeed((unsigned int) integrator.getRandomNumberSeed()); // Identify particle pairs and ordinary particles. set<int> particles; vector<RealOpenMM> particleMass; for (int i = 0; i < system.getNumParticles(); i++) { particles.insert(i); double mass = system.getParticleMass(i); particleMass.push_back(mass); particleInvMass.push_back(mass == 0.0 ? 0.0 : 1.0/mass); } for (int i = 0; i < force.getNumParticles(); i++) { int p, p1, p2, p3, p4; double charge, polarizability, aniso12, aniso34; force.getParticleParameters(i, p, p1, p2, p3, p4, charge, polarizability, aniso12, aniso34); particles.erase(p); particles.erase(p1); pairParticles.push_back(make_pair(p, p1)); double m1 = system.getParticleMass(p); double m2 = system.getParticleMass(p1); pairInvTotalMass.push_back(1.0/(m1+m2)); pairInvReducedMass.push_back((m1+m2)/(m1*m2)); } normalParticles.insert(normalParticles.begin(), particles.begin(), particles.end()); // Prepare constraints. int numConstraints = system.getNumConstraints(); if (numConstraints > 0) { vector<pair<int, int> > constraintIndices(numConstraints); vector<RealOpenMM> constraintDistances(numConstraints); for (int i = 0; i < numConstraints; ++i) { int particle1, particle2; double distance; system.getConstraintParameters(i, particle1, particle2, distance); constraintIndices[i].first = particle1; constraintIndices[i].second = particle2; constraintDistances[i] = static_cast<RealOpenMM>(distance); } vector<ReferenceCCMAAlgorithm::AngleInfo> angles; findAnglesForCCMA(system, angles); constraints = new ReferenceCCMAAlgorithm(system.getNumParticles(), numConstraints, constraintIndices, constraintDistances, particleMass, angles, (RealOpenMM)integrator.getConstraintTolerance()); } }
void CudaIntegrateDrudeLangevinStepKernel::initialize(const System& system, const DrudeLangevinIntegrator& integrator, const DrudeForce& force) { cu.getPlatformData().initializeContexts(system); cu.getIntegrationUtilities().initRandomNumberGenerator((unsigned int) integrator.getRandomNumberSeed()); // Identify particle pairs and ordinary particles. set<int> particles; vector<int> normalParticleVec; vector<int2> pairParticleVec; for (int i = 0; i < system.getNumParticles(); i++) particles.insert(i); for (int i = 0; i < force.getNumParticles(); i++) { int p, p1, p2, p3, p4; double charge, polarizability, aniso12, aniso34; force.getParticleParameters(i, p, p1, p2, p3, p4, charge, polarizability, aniso12, aniso34); particles.erase(p); particles.erase(p1); pairParticleVec.push_back(make_int2(p, p1)); } normalParticleVec.insert(normalParticleVec.begin(), particles.begin(), particles.end()); normalParticles = CudaArray::create<int>(cu, max((int) normalParticleVec.size(), 1), "drudeNormalParticles"); pairParticles = CudaArray::create<int2>(cu, max((int) pairParticleVec.size(), 1), "drudePairParticles"); if (normalParticleVec.size() > 0) normalParticles->upload(normalParticleVec); if (pairParticleVec.size() > 0) pairParticles->upload(pairParticleVec); // Create kernels. map<string, string> defines; defines["NUM_ATOMS"] = cu.intToString(cu.getNumAtoms()); defines["PADDED_NUM_ATOMS"] = cu.intToString(cu.getPaddedNumAtoms()); defines["NUM_NORMAL_PARTICLES"] = cu.intToString(normalParticleVec.size()); defines["NUM_PAIRS"] = cu.intToString(pairParticleVec.size()); map<string, string> replacements; CUmodule module = cu.createModule(CudaKernelSources::vectorOps+CudaDrudeKernelSources::drudeLangevin, defines, ""); kernel1 = cu.getKernel(module, "integrateDrudeLangevinPart1"); kernel2 = cu.getKernel(module, "integrateDrudeLangevinPart2"); hardwallKernel = cu.getKernel(module, "applyHardWallConstraints"); prevStepSize = -1.0; }
void CudaCalcDrudeForceKernel::copyParametersToContext(ContextImpl& context, const DrudeForce& force) { int numContexts = cu.getPlatformData().contexts.size(); // Set the particle parameters. int startParticleIndex = cu.getContextIndex()*force.getNumParticles()/numContexts; int endParticleIndex = (cu.getContextIndex()+1)*force.getNumParticles()/numContexts; int numParticles = endParticleIndex-startParticleIndex; if (numParticles > 0) { if (particleParams == NULL || numParticles != particleParams->getSize()) throw OpenMMException("updateParametersInContext: The number of Drude particles has changed"); vector<float4> paramVector(numParticles); for (int i = 0; i < numParticles; i++) { int p, p1, p2, p3, p4; double charge, polarizability, aniso12, aniso34; force.getParticleParameters(startParticleIndex+i, p, p1, p2, p3, p4, charge, polarizability, aniso12, aniso34); double a1 = (p2 == -1 ? 1 : aniso12); double a2 = (p3 == -1 || p4 == -1 ? 1 : aniso34); double a3 = 3-a1-a2; double k3 = ONE_4PI_EPS0*charge*charge/(polarizability*a3); double k1 = ONE_4PI_EPS0*charge*charge/(polarizability*a1) - k3; double k2 = ONE_4PI_EPS0*charge*charge/(polarizability*a2) - k3; if (p2 == -1) k1 = 0; if (p3 == -1 || p4 == -1) k2 = 0; paramVector[i] = make_float4((float) k1, (float) k2, (float) k3, 0.0f); } particleParams->upload(paramVector); } // Set the pair parameters. int startPairIndex = cu.getContextIndex()*force.getNumScreenedPairs()/numContexts; int endPairIndex = (cu.getContextIndex()+1)*force.getNumScreenedPairs()/numContexts; int numPairs = endPairIndex-startPairIndex; if (numPairs > 0) { if (pairParams == NULL || numPairs != pairParams->getSize()) throw OpenMMException("updateParametersInContext: The number of screened pairs has changed"); vector<float2> paramVector(numPairs); for (int i = 0; i < numPairs; i++) { int drude1, drude2; double thole; force.getScreenedPairParameters(startPairIndex+i, drude1, drude2, thole); int p, p1, p2, p3, p4; double charge1, charge2, polarizability1, polarizability2, aniso12, aniso34; force.getParticleParameters(drude1, p, p1, p2, p3, p4, charge1, polarizability1, aniso12, aniso34); force.getParticleParameters(drude2, p, p1, p2, p3, p4, charge2, polarizability2, aniso12, aniso34); double screeningScale = thole/pow(polarizability1*polarizability2, 1.0/6.0); double energyScale = ONE_4PI_EPS0*charge1*charge2; paramVector[i] = make_float2((float) screeningScale, (float) energyScale); } pairParams->upload(paramVector); } }
void testChangingParameters() { const double k = ONE_4PI_EPS0*1.5; const double charge = 0.1; const double alpha = ONE_4PI_EPS0*charge*charge/k; Platform& platform = Platform::getPlatformByName("OpenCL"); // Create the system. System system; system.addParticle(1.0); system.addParticle(1.0); DrudeForce* drude = new DrudeForce(); drude->addParticle(1, 0, -1, -1, -1, charge, alpha, 1, 1); system.addForce(drude); vector<Vec3> positions(2); positions[0] = Vec3(-1, 0, 0); positions[1] = Vec3(2, 0, 0); // Check the energy. VerletIntegrator integ(1.0); Context context(system, integ, platform); context.setPositions(positions); State state = context.getState(State::Energy); ASSERT_EQUAL_TOL(0.5*k*3*3, state.getPotentialEnergy(), 1e-5); // Modify the parameters. const double k2 = ONE_4PI_EPS0*2.2; const double charge2 = 0.3; const double alpha2 = ONE_4PI_EPS0*charge2*charge2/k2; drude->setParticleParameters(0, 1, 0, -1, -1, -1, charge2, alpha2, 1, 1); drude->updateParametersInContext(context); state = context.getState(State::Energy); ASSERT_EQUAL_TOL(0.5*k2*3*3, state.getPotentialEnergy(), 1e-5); }
void ReferenceCalcDrudeForceKernel::copyParametersToContext(ContextImpl& context, const DrudeForce& force) { if (force.getNumParticles() != particle.size()) throw OpenMMException("updateParametersInContext: The number of Drude particles has changed"); if (force.getNumScreenedPairs() != pair1.size()) throw OpenMMException("updateParametersInContext: The number of screened pairs has changed"); for (int i = 0; i < force.getNumParticles(); i++) { int p, p1, p2, p3, p4; force.getParticleParameters(i, p, p1, p2, p3, p4, charge[i], polarizability[i], aniso12[i], aniso34[i]); if (p != particle[i] || p1 != particle1[i] || p2 != particle2[i] || p3 != particle3[i] || p4 != particle4[i]) throw OpenMMException("updateParametersInContext: A particle index has changed"); } for (int i = 0; i < force.getNumScreenedPairs(); i++) { int p1, p2; force.getScreenedPairParameters(i, p1, p2, pairThole[i]); if (p1 != pair1[i] || p2 != pair2[i]) throw OpenMMException("updateParametersInContext: A particle index for a screened pair has changed"); } }
void CudaCalcDrudeForceKernel::initialize(const System& system, const DrudeForce& force) { cu.setAsCurrent(); int numContexts = cu.getPlatformData().contexts.size(); int startParticleIndex = cu.getContextIndex()*force.getNumParticles()/numContexts; int endParticleIndex = (cu.getContextIndex()+1)*force.getNumParticles()/numContexts; int numParticles = endParticleIndex-startParticleIndex; if (numParticles > 0) { // Create the harmonic interaction . vector<vector<int> > atoms(numParticles, vector<int>(5)); particleParams = CudaArray::create<float4>(cu, numParticles, "drudeParticleParams"); vector<float4> paramVector(numParticles); for (int i = 0; i < numParticles; i++) { double charge, polarizability, aniso12, aniso34; force.getParticleParameters(startParticleIndex+i, atoms[i][0], atoms[i][1], atoms[i][2], atoms[i][3], atoms[i][4], charge, polarizability, aniso12, aniso34); double a1 = (atoms[i][2] == -1 ? 1 : aniso12); double a2 = (atoms[i][3] == -1 || atoms[i][4] == -1 ? 1 : aniso34); double a3 = 3-a1-a2; double k3 = ONE_4PI_EPS0*charge*charge/(polarizability*a3); double k1 = ONE_4PI_EPS0*charge*charge/(polarizability*a1) - k3; double k2 = ONE_4PI_EPS0*charge*charge/(polarizability*a2) - k3; if (atoms[i][2] == -1) { atoms[i][2] = 0; k1 = 0; } if (atoms[i][3] == -1 || atoms[i][4] == -1) { atoms[i][3] = 0; atoms[i][4] = 0; k2 = 0; } paramVector[i] = make_float4((float) k1, (float) k2, (float) k3, 0.0f); } particleParams->upload(paramVector); map<string, string> replacements; replacements["PARAMS"] = cu.getBondedUtilities().addArgument(particleParams->getDevicePointer(), "float4"); cu.getBondedUtilities().addInteraction(atoms, cu.replaceStrings(CudaDrudeKernelSources::drudeParticleForce, replacements), force.getForceGroup()); } int startPairIndex = cu.getContextIndex()*force.getNumScreenedPairs()/numContexts; int endPairIndex = (cu.getContextIndex()+1)*force.getNumScreenedPairs()/numContexts; int numPairs = endPairIndex-startPairIndex; if (numPairs > 0) { // Create the screened interaction between dipole pairs. vector<vector<int> > atoms(numPairs, vector<int>(4)); pairParams = CudaArray::create<float2>(cu, numPairs, "drudePairParams"); vector<float2> paramVector(numPairs); for (int i = 0; i < numPairs; i++) { int drude1, drude2; double thole; force.getScreenedPairParameters(startPairIndex+i, drude1, drude2, thole); int p2, p3, p4; double charge1, charge2, polarizability1, polarizability2, aniso12, aniso34; force.getParticleParameters(drude1, atoms[i][0], atoms[i][1], p2, p3, p4, charge1, polarizability1, aniso12, aniso34); force.getParticleParameters(drude2, atoms[i][2], atoms[i][3], p2, p3, p4, charge2, polarizability2, aniso12, aniso34); double screeningScale = thole/pow(polarizability1*polarizability2, 1.0/6.0); double energyScale = ONE_4PI_EPS0*charge1*charge2; paramVector[i] = make_float2((float) screeningScale, (float) energyScale); } pairParams->upload(paramVector); map<string, string> replacements; replacements["PARAMS"] = cu.getBondedUtilities().addArgument(pairParams->getDevicePointer(), "float2"); cu.getBondedUtilities().addInteraction(atoms, cu.replaceStrings(CudaDrudeKernelSources::drudePairForce, replacements), force.getForceGroup()); } cu.addForce(new CudaDrudeForceInfo(force)); }
void testWater() { // Create a box of SWM4-NDP water molecules. This involves constraints, virtual sites, // and Drude particles. const int gridSize = 3; const int numMolecules = gridSize*gridSize*gridSize; const double spacing = 0.6; const double boxSize = spacing*(gridSize+1); System system; NonbondedForce* nonbonded = new NonbondedForce(); DrudeForce* drude = new DrudeForce(); system.addForce(nonbonded); system.addForce(drude); system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); nonbonded->setCutoffDistance(1.0); for (int i = 0; i < numMolecules; i++) { int startIndex = system.getNumParticles(); system.addParticle(15.6); // O system.addParticle(0.4); // D system.addParticle(1.0); // H1 system.addParticle(1.0); // H2 system.addParticle(0.0); // M nonbonded->addParticle(1.71636, 0.318395, 0.21094*4.184); nonbonded->addParticle(-1.71636, 1, 0); nonbonded->addParticle(0.55733, 1, 0); nonbonded->addParticle(0.55733, 1, 0); nonbonded->addParticle(-1.11466, 1, 0); for (int j = 0; j < 5; j++) for (int k = 0; k < j; k++) nonbonded->addException(startIndex+j, startIndex+k, 0, 1, 0); system.addConstraint(startIndex, startIndex+2, 0.09572); system.addConstraint(startIndex, startIndex+3, 0.09572); system.addConstraint(startIndex+2, startIndex+3, 0.15139); system.setVirtualSite(startIndex+4, new ThreeParticleAverageSite(startIndex, startIndex+2, startIndex+3, 0.786646558, 0.106676721, 0.106676721)); drude->addParticle(startIndex+1, startIndex, -1, -1, -1, -1.71636, ONE_4PI_EPS0*1.71636*1.71636/(100000*4.184), 1, 1); } vector<Vec3> positions; for (int i = 0; i < gridSize; i++) for (int j = 0; j < gridSize; j++) for (int k = 0; k < gridSize; k++) { Vec3 pos(i*spacing, j*spacing, k*spacing); positions.push_back(pos); positions.push_back(pos); positions.push_back(pos+Vec3(0.09572, 0, 0)); positions.push_back(pos+Vec3(-0.023999, 0.092663, 0)); positions.push_back(pos); } // Simulate it and check energy conservation and the total force on the Drude particles. DrudeSCFIntegrator integ(0.0005); Platform& platform = Platform::getPlatformByName("Reference"); Context context(system, integ, platform); context.setPositions(positions); context.applyConstraints(1e-5); context.setVelocitiesToTemperature(300.0); State state = context.getState(State::Energy); double initialEnergy; int numSteps = 1000; for (int i = 0; i < numSteps; i++) { integ.step(1); state = context.getState(State::Energy | State::Forces); if (i == 0) initialEnergy = state.getPotentialEnergy()+state.getKineticEnergy(); else ASSERT_EQUAL_TOL(initialEnergy, state.getPotentialEnergy()+state.getKineticEnergy(), 0.01); const vector<Vec3>& force = state.getForces(); double norm = 0.0; for (int j = 1; j < (int) force.size(); j += 5) norm += sqrt(force[j].dot(force[j])); norm = (norm/numMolecules); ASSERT(norm < 1.0); } }
void testWater() { // Create a box of SWM4-NDP water molecules. This involves constraints, virtual sites, // and Drude particles. const int gridSize = 3; const int numMolecules = gridSize*gridSize*gridSize; const double spacing = 0.6; const double boxSize = spacing*(gridSize+1); const double temperature = 300.0; const double temperatureDrude = 10.0; System system; NonbondedForce* nonbonded = new NonbondedForce(); DrudeForce* drude = new DrudeForce(); system.addForce(nonbonded); system.addForce(drude); system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic); nonbonded->setCutoffDistance(1.0); for (int i = 0; i < numMolecules; i++) { int startIndex = system.getNumParticles(); system.addParticle(15.6); // O system.addParticle(0.4); // D system.addParticle(1.0); // H1 system.addParticle(1.0); // H2 system.addParticle(0.0); // M nonbonded->addParticle(1.71636, 0.318395, 0.21094*4.184); nonbonded->addParticle(-1.71636, 1, 0); nonbonded->addParticle(0.55733, 1, 0); nonbonded->addParticle(0.55733, 1, 0); nonbonded->addParticle(-1.11466, 1, 0); for (int j = 0; j < 5; j++) for (int k = 0; k < j; k++) nonbonded->addException(startIndex+j, startIndex+k, 0, 1, 0); system.addConstraint(startIndex, startIndex+2, 0.09572); system.addConstraint(startIndex, startIndex+3, 0.09572); system.addConstraint(startIndex+2, startIndex+3, 0.15139); system.setVirtualSite(startIndex+4, new ThreeParticleAverageSite(startIndex, startIndex+2, startIndex+3, 0.786646558, 0.106676721, 0.106676721)); drude->addParticle(startIndex+1, startIndex, -1, -1, -1, -1.71636, ONE_4PI_EPS0*1.71636*1.71636/(100000*4.184), 1, 1); } vector<Vec3> positions; for (int i = 0; i < gridSize; i++) for (int j = 0; j < gridSize; j++) for (int k = 0; k < gridSize; k++) { Vec3 pos(i*spacing, j*spacing, k*spacing); positions.push_back(pos); positions.push_back(pos); positions.push_back(pos+Vec3(0.09572, 0, 0)); positions.push_back(pos+Vec3(-0.023999, 0.092663, 0)); positions.push_back(pos); } // Simulate it and check the temperature. DrudeLangevinIntegrator integ(temperature, 50.0, temperatureDrude, 50.0, 0.0005); Platform& platform = Platform::getPlatformByName("Reference"); Context context(system, integ, platform); context.setPositions(positions); context.applyConstraints(1e-5); // Equilibrate. integ.step(500); // Compute the internal and center of mass temperatures. double ke = 0; int numSteps = 4000; for (int i = 0; i < numSteps; i++) { integ.step(1); ke += context.getState(State::Energy).getKineticEnergy(); } ke /= numSteps; int numStandardDof = 3*3*numMolecules-system.getNumConstraints(); int numDrudeDof = 3*numMolecules; int numDof = numStandardDof+numDrudeDof; double expectedTemp = (numStandardDof*temperature+numDrudeDof*temperatureDrude)/numDof; ASSERT_USUALLY_EQUAL_TOL(expectedTemp, ke/(0.5*numDof*BOLTZ), 0.03); }