void CudaIntegrateRPMDStepKernel::computeForces(ContextImpl& context) { // Compute forces from all groups that didn't have a specified contraction. for (int i = 0; i < numCopies; i++) { void* copyToContextArgs[] = {&velocities->getDevicePointer(), &cu.getVelm().getDevicePointer(), &positions->getDevicePointer(), &cu.getPosq().getDevicePointer(), &cu.getAtomIndexArray().getDevicePointer(), &i}; cu.executeKernel(copyToContextKernel, copyToContextArgs, cu.getNumAtoms()); context.computeVirtualSites(); Vec3 initialBox[3]; context.getPeriodicBoxVectors(initialBox[0], initialBox[1], initialBox[2]); context.updateContextState(); Vec3 finalBox[3]; context.getPeriodicBoxVectors(finalBox[0], finalBox[1], finalBox[2]); if (initialBox[0] != finalBox[0] || initialBox[1] != finalBox[1] || initialBox[2] != finalBox[2]) throw OpenMMException("Standard barostats cannot be used with RPMDIntegrator. Use RPMDMonteCarloBarostat instead."); context.calcForcesAndEnergy(true, false, groupsNotContracted); void* copyFromContextArgs[] = {&cu.getForce().getDevicePointer(), &forces->getDevicePointer(), &cu.getVelm().getDevicePointer(), &velocities->getDevicePointer(), &cu.getPosq().getDevicePointer(), &positions->getDevicePointer(), &cu.getAtomIndexArray().getDevicePointer(), &i}; cu.executeKernel(copyFromContextKernel, copyFromContextArgs, cu.getNumAtoms()); } // Now loop over contractions and compute forces from them. for (map<int, int>::const_iterator iter = groupsByCopies.begin(); iter != groupsByCopies.end(); ++iter) { int copies = iter->first; int groupFlags = iter->second; // Find the contracted positions. void* contractPosArgs[] = {&positions->getDevicePointer(), &contractedPositions->getDevicePointer()}; cu.executeKernel(positionContractionKernels[copies], contractPosArgs, numParticles*numCopies, workgroupSize); // Compute forces. for (int i = 0; i < copies; i++) { void* copyToContextArgs[] = {&velocities->getDevicePointer(), &cu.getVelm().getDevicePointer(), &contractedPositions->getDevicePointer(), &cu.getPosq().getDevicePointer(), &cu.getAtomIndexArray().getDevicePointer(), &i}; cu.executeKernel(copyToContextKernel, copyToContextArgs, cu.getNumAtoms()); context.computeVirtualSites(); context.calcForcesAndEnergy(true, false, groupFlags); void* copyFromContextArgs[] = {&cu.getForce().getDevicePointer(), &contractedForces->getDevicePointer(), &cu.getVelm().getDevicePointer(), &velocities->getDevicePointer(), &cu.getPosq().getDevicePointer(), &contractedPositions->getDevicePointer(), &cu.getAtomIndexArray().getDevicePointer(), &i}; cu.executeKernel(copyFromContextKernel, copyFromContextArgs, cu.getNumAtoms()); } // Apply the forces to the original copies. void* contractForceArgs[] = {&forces->getDevicePointer(), &contractedForces->getDevicePointer()}; cu.executeKernel(forceContractionKernels[copies], contractForceArgs, numParticles*numCopies, workgroupSize); } if (groupsByCopies.size() > 0) { // Ensure the Context contains the positions from the last copy, since we'll assume that later. int i = numCopies-1; void* copyToContextArgs[] = {&velocities->getDevicePointer(), &cu.getVelm().getDevicePointer(), &positions->getDevicePointer(), &cu.getPosq().getDevicePointer(), &cu.getAtomIndexArray().getDevicePointer(), &i}; cu.executeKernel(copyToContextKernel, copyToContextArgs, cu.getNumAtoms()); } }
void ReferenceIntegrateRPMDStepKernel::computeForces(ContextImpl& context, const RPMDIntegrator& integrator) { const int totalCopies = positions.size(); const int numParticles = positions[0].size(); vector<RealVec>& pos = extractPositions(context); vector<RealVec>& vel = extractVelocities(context); vector<RealVec>& f = extractForces(context); // Compute forces from all groups that didn't have a specified contraction. for (int i = 0; i < totalCopies; i++) { pos = positions[i]; vel = velocities[i]; context.computeVirtualSites(); Vec3 initialBox[3]; context.getPeriodicBoxVectors(initialBox[0], initialBox[1], initialBox[2]); context.updateContextState(); Vec3 finalBox[3]; context.getPeriodicBoxVectors(finalBox[0], finalBox[1], finalBox[2]); if (initialBox[0] != finalBox[0] || initialBox[1] != finalBox[1] || initialBox[2] != finalBox[2]) { // A barostat was applied during updateContextState(). Adjust the particle positions in all the // other copies to match this one. for (int j = 0; j < numParticles; j++) { Vec3 delta = pos[j]-positions[i][j]; for (int k = 0; k < totalCopies; k++) if (k != i) positions[k][j] += delta; } } positions[i] = pos; velocities[i] = vel; context.calcForcesAndEnergy(true, false, groupsNotContracted); forces[i] = f; } // Now loop over contractions and compute forces from them. for (map<int, int>::const_iterator iter = groupsByCopies.begin(); iter != groupsByCopies.end(); ++iter) { int copies = iter->first; int groupFlags = iter->second; fftpack* shortFFT = contractionFFT[copies]; // Find the contracted positions. vector<t_complex> q(totalCopies); const RealOpenMM scale1 = 1.0/totalCopies; for (int particle = 0; particle < numParticles; particle++) { for (int component = 0; component < 3; component++) { // Transform to the frequency domain, set high frequency components to zero, and transform back. for (int k = 0; k < totalCopies; k++) q[k] = t_complex(positions[k][particle][component], 0.0); fftpack_exec_1d(fft, FFTPACK_FORWARD, &q[0], &q[0]); if (copies > 1) { int start = (copies+1)/2; int end = totalCopies-copies+start; for (int k = end; k < totalCopies; k++) q[k-(totalCopies-copies)] = q[k]; fftpack_exec_1d(shortFFT, FFTPACK_BACKWARD, &q[0], &q[0]); } for (int k = 0; k < copies; k++) contractedPositions[k][particle][component] = scale1*q[k].re; } } // Compute forces. for (int i = 0; i < copies; i++) { pos = contractedPositions[i]; context.computeVirtualSites(); context.calcForcesAndEnergy(true, false, groupFlags); contractedForces[i] = f; } // Apply the forces to the original copies. const RealOpenMM scale2 = 1.0/copies; for (int particle = 0; particle < numParticles; particle++) { for (int component = 0; component < 3; component++) { // Transform to the frequency domain, pad with zeros, and transform back. for (int k = 0; k < copies; k++) q[k] = t_complex(contractedForces[k][particle][component], 0.0); if (copies > 1) fftpack_exec_1d(shortFFT, FFTPACK_FORWARD, &q[0], &q[0]); int start = (copies+1)/2; int end = totalCopies-copies+start; for (int k = end; k < totalCopies; k++) q[k] = q[k-(totalCopies-copies)]; for (int k = start; k < end; k++) q[k] = t_complex(0, 0); fftpack_exec_1d(fft, FFTPACK_BACKWARD, &q[0], &q[0]); for (int k = 0; k < totalCopies; k++) forces[k][particle][component] += scale2*q[k].re; } } } }