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 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; }
double ReferenceIntegrateDrudeLangevinStepKernel::computeKineticEnergy(ContextImpl& context, const DrudeLangevinIntegrator& integrator) { return computeShiftedKineticEnergy(context, particleInvMass, 0.5*integrator.getStepSize(), constraints); }
void ReferenceIntegrateDrudeLangevinStepKernel::execute(ContextImpl& context, const DrudeLangevinIntegrator& integrator) { vector<RealVec>& pos = extractPositions(context); vector<RealVec>& vel = extractVelocities(context); vector<RealVec>& force = extractForces(context); // Update velocities of ordinary particles. const RealOpenMM vscale = exp(-integrator.getStepSize()*integrator.getFriction()); const RealOpenMM fscale = (1-vscale)/integrator.getFriction(); const RealOpenMM kT = BOLTZ*integrator.getTemperature(); const RealOpenMM noisescale = sqrt(2*kT*integrator.getFriction())*sqrt(0.5*(1-vscale*vscale)/integrator.getFriction()); for (int i = 0; i < (int) normalParticles.size(); i++) { int index = normalParticles[i]; RealOpenMM invMass = particleInvMass[index]; if (invMass != 0.0) { RealOpenMM sqrtInvMass = sqrt(invMass); for (int j = 0; j < 3; j++) vel[index][j] = vscale*vel[index][j] + fscale*invMass*force[index][j] + noisescale*sqrtInvMass*SimTKOpenMMUtilities::getNormallyDistributedRandomNumber(); } } // Update velocities of Drude particle pairs. const RealOpenMM vscaleDrude = exp(-integrator.getStepSize()*integrator.getDrudeFriction()); const RealOpenMM fscaleDrude = (1-vscaleDrude)/integrator.getDrudeFriction(); const RealOpenMM kTDrude = BOLTZ*integrator.getDrudeTemperature(); const RealOpenMM noisescaleDrude = sqrt(2*kTDrude*integrator.getDrudeFriction())*sqrt(0.5*(1-vscaleDrude*vscaleDrude)/integrator.getDrudeFriction()); for (int i = 0; i < (int) pairParticles.size(); i++) { int p1 = pairParticles[i].first; int p2 = pairParticles[i].second; RealOpenMM mass1fract = pairInvTotalMass[i]/particleInvMass[p1]; RealOpenMM mass2fract = pairInvTotalMass[i]/particleInvMass[p2]; RealOpenMM sqrtInvTotalMass = sqrt(pairInvTotalMass[i]); RealOpenMM sqrtInvReducedMass = sqrt(pairInvReducedMass[i]); RealVec cmVel = vel[p1]*mass1fract+vel[p2]*mass2fract; RealVec relVel = vel[p2]-vel[p1]; RealVec cmForce = force[p1]+force[p2]; RealVec relForce = force[p2]*mass1fract - force[p1]*mass2fract; for (int j = 0; j < 3; j++) { cmVel[j] = vscale*cmVel[j] + fscale*pairInvTotalMass[i]*cmForce[j] + noisescale*sqrtInvTotalMass*SimTKOpenMMUtilities::getNormallyDistributedRandomNumber(); relVel[j] = vscaleDrude*relVel[j] + fscaleDrude*pairInvReducedMass[i]*relForce[j] + noisescaleDrude*sqrtInvReducedMass*SimTKOpenMMUtilities::getNormallyDistributedRandomNumber(); } vel[p1] = cmVel-relVel*mass2fract; vel[p2] = cmVel+relVel*mass1fract; } // Update the particle positions. int numParticles = particleInvMass.size(); vector<RealVec> xPrime(numParticles); RealOpenMM dt = integrator.getStepSize(); for (int i = 0; i < numParticles; i++) if (particleInvMass[i] != 0.0) xPrime[i] = pos[i]+vel[i]*dt; // Apply constraints. if (constraints != NULL) constraints->apply(numParticles, pos, xPrime, particleInvMass); // Record the constrained positions and velocities. RealOpenMM dtInv = 1.0/dt; for (int i = 0; i < numParticles; i++) { if (particleInvMass[i] != 0.0) { vel[i] = (xPrime[i]-pos[i])*dtInv; pos[i] = xPrime[i]; } } ReferenceVirtualSites::computePositions(context.getSystem(), pos); data.time += integrator.getStepSize(); data.stepCount++; }
void ReferenceIntegrateDrudeLangevinStepKernel::execute(ContextImpl& context, const DrudeLangevinIntegrator& integrator) { vector<RealVec>& pos = extractPositions(context); vector<RealVec>& vel = extractVelocities(context); vector<RealVec>& force = extractForces(context); // Update velocities of ordinary particles. const RealOpenMM vscale = exp(-integrator.getStepSize()*integrator.getFriction()); const RealOpenMM fscale = (1-vscale)/integrator.getFriction(); const RealOpenMM kT = BOLTZ*integrator.getTemperature(); const RealOpenMM noisescale = sqrt(2*kT*integrator.getFriction())*sqrt(0.5*(1-vscale*vscale)/integrator.getFriction()); for (int i = 0; i < (int) normalParticles.size(); i++) { int index = normalParticles[i]; RealOpenMM invMass = particleInvMass[index]; if (invMass != 0.0) { RealOpenMM sqrtInvMass = sqrt(invMass); for (int j = 0; j < 3; j++) vel[index][j] = vscale*vel[index][j] + fscale*invMass*force[index][j] + noisescale*sqrtInvMass*SimTKOpenMMUtilities::getNormallyDistributedRandomNumber(); } } // Update velocities of Drude particle pairs. const RealOpenMM vscaleDrude = exp(-integrator.getStepSize()*integrator.getDrudeFriction()); const RealOpenMM fscaleDrude = (1-vscaleDrude)/integrator.getDrudeFriction(); const RealOpenMM kTDrude = BOLTZ*integrator.getDrudeTemperature(); const RealOpenMM noisescaleDrude = sqrt(2*kTDrude*integrator.getDrudeFriction())*sqrt(0.5*(1-vscaleDrude*vscaleDrude)/integrator.getDrudeFriction()); for (int i = 0; i < (int) pairParticles.size(); i++) { int p1 = pairParticles[i].first; int p2 = pairParticles[i].second; RealOpenMM mass1fract = pairInvTotalMass[i]/particleInvMass[p1]; RealOpenMM mass2fract = pairInvTotalMass[i]/particleInvMass[p2]; RealOpenMM sqrtInvTotalMass = sqrt(pairInvTotalMass[i]); RealOpenMM sqrtInvReducedMass = sqrt(pairInvReducedMass[i]); RealVec cmVel = vel[p1]*mass1fract+vel[p2]*mass2fract; RealVec relVel = vel[p2]-vel[p1]; RealVec cmForce = force[p1]+force[p2]; RealVec relForce = force[p2]*mass1fract - force[p1]*mass2fract; for (int j = 0; j < 3; j++) { cmVel[j] = vscale*cmVel[j] + fscale*pairInvTotalMass[i]*cmForce[j] + noisescale*sqrtInvTotalMass*SimTKOpenMMUtilities::getNormallyDistributedRandomNumber(); relVel[j] = vscaleDrude*relVel[j] + fscaleDrude*pairInvReducedMass[i]*relForce[j] + noisescaleDrude*sqrtInvReducedMass*SimTKOpenMMUtilities::getNormallyDistributedRandomNumber(); } vel[p1] = cmVel-relVel*mass2fract; vel[p2] = cmVel+relVel*mass1fract; } // Update the particle positions. int numParticles = particleInvMass.size(); vector<RealVec> xPrime(numParticles); RealOpenMM dt = integrator.getStepSize(); for (int i = 0; i < numParticles; i++) if (particleInvMass[i] != 0.0) xPrime[i] = pos[i]+vel[i]*dt; // Apply constraints. extractConstraints(context).apply(pos, xPrime, particleInvMass, integrator.getConstraintTolerance()); // Record the constrained positions and velocities. RealOpenMM dtInv = 1.0/dt; for (int i = 0; i < numParticles; i++) { if (particleInvMass[i] != 0.0) { vel[i] = (xPrime[i]-pos[i])*dtInv; pos[i] = xPrime[i]; } } // Apply hard wall constraints. const RealOpenMM maxDrudeDistance = integrator.getMaxDrudeDistance(); if (maxDrudeDistance > 0) { const RealOpenMM hardwallscaleDrude = sqrt(kTDrude); for (int i = 0; i < (int) pairParticles.size(); i++) { int p1 = pairParticles[i].first; int p2 = pairParticles[i].second; RealVec delta = pos[p1]-pos[p2]; RealOpenMM r = sqrt(delta.dot(delta)); RealOpenMM rInv = 1/r; if (rInv*maxDrudeDistance < 1.0) { // The constraint has been violated, so make the inter-particle distance "bounce" // off the hard wall. if (rInv*maxDrudeDistance < 0.5) throw OpenMMException("Drude particle moved too far beyond hard wall constraint"); RealVec bondDir = delta*rInv; RealVec vel1 = vel[p1]; RealVec vel2 = vel[p2]; RealOpenMM mass1 = particleMass[p1]; RealOpenMM mass2 = particleMass[p2]; RealOpenMM deltaR = r-maxDrudeDistance; RealOpenMM deltaT = dt; RealOpenMM dotvr1 = vel1.dot(bondDir); RealVec vb1 = bondDir*dotvr1; RealVec vp1 = vel1-vb1; if (mass2 == 0) { // The parent particle is massless, so move only the Drude particle. if (dotvr1 != 0.0) deltaT = deltaR/abs(dotvr1); if (deltaT > dt) deltaT = dt; dotvr1 = -dotvr1*hardwallscaleDrude/(abs(dotvr1)*sqrt(mass1)); RealOpenMM dr = -deltaR + deltaT*dotvr1; pos[p1] += bondDir*dr; vel[p1] = vp1 + bondDir*dotvr1; } else { // Move both particles. RealOpenMM invTotalMass = pairInvTotalMass[i]; RealOpenMM dotvr2 = vel2.dot(bondDir); RealVec vb2 = bondDir*dotvr2; RealVec vp2 = vel2-vb2; RealOpenMM vbCMass = (mass1*dotvr1 + mass2*dotvr2)*invTotalMass; dotvr1 -= vbCMass; dotvr2 -= vbCMass; if (dotvr1 != dotvr2) deltaT = deltaR/abs(dotvr1-dotvr2); if (deltaT > dt) deltaT = dt; RealOpenMM vBond = hardwallscaleDrude/sqrt(mass1); dotvr1 = -dotvr1*vBond*mass2*invTotalMass/abs(dotvr1); dotvr2 = -dotvr2*vBond*mass1*invTotalMass/abs(dotvr2); RealOpenMM dr1 = -deltaR*mass2*invTotalMass + deltaT*dotvr1; RealOpenMM dr2 = deltaR*mass1*invTotalMass + deltaT*dotvr2; dotvr1 += vbCMass; dotvr2 += vbCMass; pos[p1] += bondDir*dr1; pos[p2] += bondDir*dr2; vel[p1] = vp1 + bondDir*dotvr1; vel[p2] = vp2 + bondDir*dotvr2; } } } } ReferenceVirtualSites::computePositions(context.getSystem(), pos); data.time += integrator.getStepSize(); data.stepCount++; }
double CudaIntegrateDrudeLangevinStepKernel::computeKineticEnergy(ContextImpl& context, const DrudeLangevinIntegrator& integrator) { return cu.getIntegrationUtilities().computeKineticEnergy(0.5*integrator.getStepSize()); }
void CudaIntegrateDrudeLangevinStepKernel::execute(ContextImpl& context, const DrudeLangevinIntegrator& integrator) { cu.setAsCurrent(); CudaIntegrationUtilities& integration = cu.getIntegrationUtilities(); int numAtoms = cu.getNumAtoms(); // Compute integrator coefficients. double stepSize = integrator.getStepSize(); double vscale = exp(-stepSize*integrator.getFriction()); double fscale = (1-vscale)/integrator.getFriction()/(double) 0x100000000; double noisescale = sqrt(2*BOLTZ*integrator.getTemperature()*integrator.getFriction())*sqrt(0.5*(1-vscale*vscale)/integrator.getFriction()); double vscaleDrude = exp(-stepSize*integrator.getDrudeFriction()); double fscaleDrude = (1-vscaleDrude)/integrator.getDrudeFriction()/(double) 0x100000000; double noisescaleDrude = sqrt(2*BOLTZ*integrator.getDrudeTemperature()*integrator.getDrudeFriction())*sqrt(0.5*(1-vscaleDrude*vscaleDrude)/integrator.getDrudeFriction()); double maxDrudeDistance = integrator.getMaxDrudeDistance(); double hardwallscaleDrude = sqrt(BOLTZ*integrator.getDrudeTemperature()); if (stepSize != prevStepSize) { if (cu.getUseDoublePrecision() || cu.getUseMixedPrecision()) { double2 ss = make_double2(0, stepSize); integration.getStepSize().upload(&ss); } else { float2 ss = make_float2(0, (float) stepSize); integration.getStepSize().upload(&ss); } prevStepSize = stepSize; } // Create appropriate pointer for the precision mode. float vscaleFloat = (float) vscale; float fscaleFloat = (float) fscale; float noisescaleFloat = (float) noisescale; float vscaleDrudeFloat = (float) vscaleDrude; float fscaleDrudeFloat = (float) fscaleDrude; float noisescaleDrudeFloat = (float) noisescaleDrude; float maxDrudeDistanceFloat =(float) maxDrudeDistance; float hardwallscaleDrudeFloat = (float) hardwallscaleDrude; void *vscalePtr, *fscalePtr, *noisescalePtr, *vscaleDrudePtr, *fscaleDrudePtr, *noisescaleDrudePtr, *maxDrudeDistancePtr, *hardwallscaleDrudePtr; if (cu.getUseDoublePrecision() || cu.getUseMixedPrecision()) { vscalePtr = &vscale; fscalePtr = &fscale; noisescalePtr = &noisescale; vscaleDrudePtr = &vscaleDrude; fscaleDrudePtr = &fscaleDrude; noisescaleDrudePtr = &noisescaleDrude; maxDrudeDistancePtr = &maxDrudeDistance; hardwallscaleDrudePtr = &hardwallscaleDrude; } else { vscalePtr = &vscaleFloat; fscalePtr = &fscaleFloat; noisescalePtr = &noisescaleFloat; vscaleDrudePtr = &vscaleDrudeFloat; fscaleDrudePtr = &fscaleDrudeFloat; noisescaleDrudePtr = &noisescaleDrudeFloat; maxDrudeDistancePtr = &maxDrudeDistanceFloat; hardwallscaleDrudePtr = &hardwallscaleDrudeFloat; } // Call the first integration kernel. int randomIndex = integration.prepareRandomNumbers(normalParticles->getSize()+2*pairParticles->getSize()); void* args1[] = {&cu.getVelm().getDevicePointer(), &cu.getForce().getDevicePointer(), &integration.getPosDelta().getDevicePointer(), &normalParticles->getDevicePointer(), &pairParticles->getDevicePointer(), &integration.getStepSize().getDevicePointer(), vscalePtr, fscalePtr, noisescalePtr, vscaleDrudePtr, fscaleDrudePtr, noisescaleDrudePtr, &integration.getRandom().getDevicePointer(), &randomIndex}; cu.executeKernel(kernel1, args1, numAtoms); // Apply constraints. integration.applyConstraints(integrator.getConstraintTolerance()); // Call the second integration kernel. CUdeviceptr posCorrection = (cu.getUseMixedPrecision() ? cu.getPosqCorrection().getDevicePointer() : 0); void* args2[] = {&cu.getPosq().getDevicePointer(), &posCorrection, &integration.getPosDelta().getDevicePointer(), &cu.getVelm().getDevicePointer(), &integration.getStepSize().getDevicePointer()}; cu.executeKernel(kernel2, args2, numAtoms); // Apply hard wall constraints. void* hardwallArgs[] = {&cu.getPosq().getDevicePointer(), &posCorrection, &cu.getVelm().getDevicePointer(), &pairParticles->getDevicePointer(), &integration.getStepSize().getDevicePointer(), maxDrudeDistancePtr, hardwallscaleDrudePtr}; cu.executeKernel(hardwallKernel, hardwallArgs, pairParticles->getSize()); integration.computeVirtualSites(); // Update the time and step count. cu.setTime(cu.getTime()+stepSize); cu.setStepCount(cu.getStepCount()+1); cu.reorderAtoms(); }