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