Unverified Commit be19e022 authored by Peter Eastman's avatar Peter Eastman Committed by GitHub
Browse files

Converted RPMD plugin to common platform (#3079)

* Converted RPMD plugin to common platform

* Merged RPMD tests for different platforms

* Try to fix errors on CPU OpenCL
parent 98d81730
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * Medical Research, grant U54 GM072970. See https://simtk.org. *
* * * *
* Portions copyright (c) 2019 Stanford University and the Authors. * * Portions copyright (c) 2019-2021 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -140,6 +140,17 @@ public: ...@@ -140,6 +140,17 @@ public:
* in page-locked memory. * in page-locked memory.
*/ */
virtual void upload(const void* data, bool blocking=true) = 0; virtual void upload(const void* data, bool blocking=true) = 0;
/**
* Copy values from host memory to a subset of the array.
*
* @param data the data to copy
* @param offset the index of the element within the array at which the copy should begin
* @param elements the number of elements to copy
* @param blocking if true, this call will block until the transfer is complete. Subclasses often
* have restrictions on non-blocking copies, such as that the source data must be
* in page-locked memory.
*/
virtual void uploadSubArray(const void* data, int offset, int elements, bool blocking=true) = 0;
/** /**
* Copy the values in the array to host memory. * Copy the values in the array to host memory.
* *
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * Medical Research, grant U54 GM072970. See https://simtk.org. *
* * * *
* Portions copyright (c) 2019 Stanford University and the Authors. * * Portions copyright (c) 2019-2021 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -118,7 +118,20 @@ public: ...@@ -118,7 +118,20 @@ public:
* have restrictions on non-blocking copies, such as that the source data must be * have restrictions on non-blocking copies, such as that the source data must be
* in page-locked memory. * in page-locked memory.
*/ */
void upload(const void* data, bool blocking=true); void upload(const void* data, bool blocking=true) {
uploadSubArray(data, 0, getSize(), blocking);
}
/**
* Copy values from host memory to a subset of the array.
*
* @param data the data to copy
* @param offset the index of the element within the array at which the copy should begin
* @param elements the number of elements to copy
* @param blocking if true, this call will block until the transfer is complete. Subclasses often
* have restrictions on non-blocking copies, such as that the source data must be
* in page-locked memory.
*/
void uploadSubArray(const void* data, int offset, int elements, bool blocking=true);
/** /**
* Copy the values in the array to host memory. * Copy the values in the array to host memory.
* *
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * Medical Research, grant U54 GM072970. See https://simtk.org. *
* * * *
* Portions copyright (c) 2019 Stanford University and the Authors. * * Portions copyright (c) 2019-2021 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -84,10 +84,10 @@ ComputeContext& ComputeArray::getContext() { ...@@ -84,10 +84,10 @@ ComputeContext& ComputeArray::getContext() {
return impl->getContext(); return impl->getContext();
} }
void ComputeArray::upload(const void* data, bool blocking) { void ComputeArray::uploadSubArray(const void* data, int offset, int elements, bool blocking) {
if (impl == NULL) if (impl == NULL)
throw OpenMMException("ComputeArray has not been initialized"); throw OpenMMException("ComputeArray has not been initialized");
impl->upload(data, blocking); impl->uploadSubArray(data, offset, elements, blocking);
} }
void ComputeArray::download(void* data, bool blocking) const { void ComputeArray::download(void* data, bool blocking) const {
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * Medical Research, grant U54 GM072970. See https://simtk.org. *
* * * *
* Portions copyright (c) 2009-2019 Stanford University and the Authors. * * Portions copyright (c) 2009-2021 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -146,13 +146,25 @@ public: ...@@ -146,13 +146,25 @@ public:
ArrayInterface::download(data); ArrayInterface::download(data);
} }
/** /**
* Copy the values in an array to the device memory. * Copy the values from host memory to the array.
* *
* @param data the data to copy * @param data the data to copy
* @param blocking if true, this call will block until the transfer is complete. If false, * @param blocking if true, this call will block until the transfer is complete. If false,
* the source array must be in page-locked memory. * the source array must be in page-locked memory.
*/ */
void upload(const void* data, bool blocking=true); void upload(const void* data, bool blocking=true) {
uploadSubArray(data, 0, getSize(), blocking);
}
/**
* Copy values from host memory to a subset of the array.
*
* @param data the data to copy
* @param offset the index of the element within the array at which the copy should begin
* @param elements the number of elements to copy
* @param blocking if true, this call will block until the transfer is complete. If false,
* the source array must be in page-locked memory.
*/
void uploadSubArray(const void* data, int offset, int elements, bool blocking=true);
/** /**
* Copy the values in the device memory to an array. * Copy the values in the device memory to an array.
* *
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * Medical Research, grant U54 GM072970. See https://simtk.org. *
* * * *
* Portions copyright (c) 2012-2019 Stanford University and the Authors. * * Portions copyright (c) 2012-2021 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -86,14 +86,16 @@ ComputeContext& CudaArray::getContext() { ...@@ -86,14 +86,16 @@ ComputeContext& CudaArray::getContext() {
return *context; return *context;
} }
void CudaArray::upload(const void* data, bool blocking) { void CudaArray::uploadSubArray(const void* data, int offset, int elements, bool blocking) {
if (pointer == 0) if (pointer == 0)
throw OpenMMException("CudaArray has not been initialized"); throw OpenMMException("CudaArray has not been initialized");
if (offset < 0 || offset+elements > getSize())
throw OpenMMException("uploadSubArray: data exceeds range of array");
CUresult result; CUresult result;
if (blocking) if (blocking)
result = cuMemcpyHtoD(pointer, data, size*elementSize); result = cuMemcpyHtoD(pointer+offset*elementSize, data, elements*elementSize);
else else
result = cuMemcpyHtoDAsync(pointer, data, size*elementSize, context->getCurrentStream()); result = cuMemcpyHtoDAsync(pointer+offset*elementSize, data, elements*elementSize, context->getCurrentStream());
if (result != CUDA_SUCCESS) { if (result != CUDA_SUCCESS) {
std::stringstream str; std::stringstream str;
str<<"Error uploading array "<<name<<": "<<CudaContext::getErrorString(result)<<" ("<<result<<")"; str<<"Error uploading array "<<name<<": "<<CudaContext::getErrorString(result)<<" ("<<result<<")";
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * Medical Research, grant U54 GM072970. See https://simtk.org. *
* * * *
* Portions copyright (c) 2009-2019 Stanford University and the Authors. * * Portions copyright (c) 2009-2021 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -208,12 +208,23 @@ public: ...@@ -208,12 +208,23 @@ public:
ArrayInterface::download(data); ArrayInterface::download(data);
} }
/** /**
* Copy the values in an array to the Buffer. * Copy the values from host memory to the array.
* *
* @param data the data to copy * @param data the data to copy
* @param blocking if true, this call will block until the transfer is complete. * @param blocking if true, this call will block until the transfer is complete.
*/ */
void upload(const void* data, bool blocking=true); void upload(const void* data, bool blocking=true) {
uploadSubArray(data, 0, getSize(), blocking);
}
/**
* Copy values from host memory to a subset of the array.
*
* @param data the data to copy
* @param offset the index of the element within the array at which the copy should begin
* @param elements the number of elements to copy
* @param blocking if true, this call will block until the transfer is complete.
*/
void uploadSubArray(const void* data, int offset, int elements, bool blocking=true);
/** /**
* Copy the values in the Buffer to an array. * Copy the values in the Buffer to an array.
* *
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * Medical Research, grant U54 GM072970. See https://simtk.org. *
* * * *
* Portions copyright (c) 2012-2019 Stanford University and the Authors. * * Portions copyright (c) 2012-2021 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -96,11 +96,13 @@ ComputeContext& OpenCLArray::getContext() { ...@@ -96,11 +96,13 @@ ComputeContext& OpenCLArray::getContext() {
return *context; return *context;
} }
void OpenCLArray::upload(const void* data, bool blocking) { void OpenCLArray::uploadSubArray(const void* data, int offset, int elements, bool blocking) {
if (buffer == NULL) if (buffer == NULL)
throw OpenMMException("OpenCLArray has not been initialized"); throw OpenMMException("OpenCLArray has not been initialized");
if (offset < 0 || offset+elements > getSize())
throw OpenMMException("uploadSubArray: data exceeds range of array");
try { try {
context->getQueue().enqueueWriteBuffer(*buffer, blocking ? CL_TRUE : CL_FALSE, 0, size*elementSize, data); context->getQueue().enqueueWriteBuffer(*buffer, blocking ? CL_TRUE : CL_FALSE, offset*elementSize, elements*elementSize, data);
} }
catch (cl::Error err) { catch (cl::Error err) {
std::stringstream str; std::stringstream str;
......
...@@ -108,6 +108,7 @@ ENDIF(OPENMM_BUILD_STATIC_LIB) ...@@ -108,6 +108,7 @@ ENDIF(OPENMM_BUILD_STATIC_LIB)
# Which hardware platforms to build # Which hardware platforms to build
ADD_SUBDIRECTORY(platforms/reference) ADD_SUBDIRECTORY(platforms/reference)
ADD_SUBDIRECTORY(platforms/common)
IF(OPENMM_BUILD_OPENCL_LIB) IF(OPENMM_BUILD_OPENCL_LIB)
SET(OPENMM_BUILD_RPMD_OPENCL_LIB ON CACHE BOOL "Build RPMD implementation for OpenCL") SET(OPENMM_BUILD_RPMD_OPENCL_LIB ON CACHE BOOL "Build RPMD implementation for OpenCL")
......
...@@ -69,11 +69,11 @@ public: ...@@ -69,11 +69,11 @@ public:
*/ */
virtual void execute(ContextImpl& context, const RPMDIntegrator& integrator, bool forcesAreValid) = 0; virtual void execute(ContextImpl& context, const RPMDIntegrator& integrator, bool forcesAreValid) = 0;
/** /**
* Get the positions of all particles in one copy of the system. * Set the positions of all particles in one copy of the system.
*/ */
virtual void setPositions(int copy, const std::vector<Vec3>& positions) = 0; virtual void setPositions(int copy, const std::vector<Vec3>& positions) = 0;
/** /**
* Get the velocities of all particles in one copy of the system. * Set the velocities of all particles in one copy of the system.
*/ */
virtual void setVelocities(int copy, const std::vector<Vec3>& velocities) = 0; virtual void setVelocities(int copy, const std::vector<Vec3>& velocities) = 0;
/** /**
......
# Encode the kernel sources into a C++ class.
SET(KERNEL_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src")
SET(KERNEL_SOURCE_CLASS CommonRpmdKernelSources)
SET(KERNELS_CPP ${CMAKE_CURRENT_BINARY_DIR}/src/${KERNEL_SOURCE_CLASS}.cpp)
SET(KERNELS_H ${CMAKE_CURRENT_BINARY_DIR}/src/${KERNEL_SOURCE_CLASS}.h)
INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/src)
FILE(GLOB COMMON_KERNELS ${KERNEL_SOURCE_DIR}/kernels/*.cc)
ADD_CUSTOM_COMMAND(OUTPUT ${KERNELS_CPP} ${KERNELS_H}
COMMAND ${CMAKE_COMMAND}
ARGS -D KERNEL_SOURCE_DIR=${KERNEL_SOURCE_DIR} -D KERNELS_CPP=${KERNELS_CPP} -D KERNELS_H=${KERNELS_H} -D KERNEL_SOURCE_CLASS=${KERNEL_SOURCE_CLASS} -D KERNEL_FILE_EXTENSION=cc -P ${CMAKE_SOURCE_DIR}/cmake_modules/EncodeKernelFiles.cmake
DEPENDS ${COMMON_KERNELS}
)
SET_SOURCE_FILES_PROPERTIES(${KERNELS_CPP} ${KERNELS_H} PROPERTIES GENERATED TRUE)
ADD_CUSTOM_TARGET(RpmdCommonKernels DEPENDS ${KERNELS_CPP} ${KERNELS_H})
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * * along with this program. If not, see <http://www.gnu.org/licenses/>. *
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
#include "CudaRpmdKernelSources.h" #include "CommonRpmdKernelSources.h"
using namespace OpenMM; using namespace OpenMM;
using namespace std; using namespace std;
......
#ifndef OPENMM_CUDARPMDKERNELSOURCES_H_ #ifndef OPENMM_COMMONRPMDKERNELSOURCES_H_
#define OPENMM_CUDARPMDKERNELSOURCES_H_ #define OPENMM_COMMONRPMDKERNELSOURCES_H_
/* -------------------------------------------------------------------------- * /* -------------------------------------------------------------------------- *
* OpenMM * * OpenMM *
...@@ -32,16 +32,16 @@ ...@@ -32,16 +32,16 @@
namespace OpenMM { namespace OpenMM {
/** /**
* This class is a central holding place for the source code of CUDA kernels. * This class is a central holding place for the source code of device kernels.
* The CMake build script inserts declarations into it based on the .cu files in the * The CMake build script inserts declarations into it based on the .cc files in the
* kernels subfolder. * kernels subfolder.
*/ */
class CudaRpmdKernelSources { class CommonRpmdKernelSources {
public: public:
@KERNEL_FILE_DECLARATIONS@ @KERNEL_FILE_DECLARATIONS@
}; };
} // namespace OpenMM } // namespace OpenMM
#endif /*OPENMM_CUDARPMDKERNELSOURCES_H_*/ #endif /*OPENMM_COMMONRPMDKERNELSOURCES_H_*/
#ifndef OPENCL_RPMD_KERNELS_H_ #ifndef COMMON_RPMD_KERNELS_H_
#define OPENCL_RPMD_KERNELS_H_ #define COMMON_RPMD_KERNELS_H_
/* -------------------------------------------------------------------------- * /* -------------------------------------------------------------------------- *
* OpenMM * * OpenMM *
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * Medical Research, grant U54 GM072970. See https://simtk.org. *
* * * *
* Portions copyright (c) 2011-2018 Stanford University and the Authors. * * Portions copyright (c) 2011-2021 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -33,19 +33,20 @@ ...@@ -33,19 +33,20 @@
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
#include "openmm/RpmdKernels.h" #include "openmm/RpmdKernels.h"
#include "OpenCLContext.h" #include "openmm/common/ComputeContext.h"
#include "OpenCLArray.h" #include "openmm/common/ComputeArray.h"
#include <map> #include <map>
namespace OpenMM { namespace OpenMM {
/** /**
* This kernel is invoked by RPMDIntegrator to take one time step, and to get and * This kernel is invoked by RPMDIntegrator to take one time step, and to get and
* set the state of system copies. * set the state of system copies.
*/ */
class OpenCLIntegrateRPMDStepKernel : public IntegrateRPMDStepKernel { class CommonIntegrateRPMDStepKernel : public IntegrateRPMDStepKernel {
public: public:
OpenCLIntegrateRPMDStepKernel(const std::string& name, const Platform& platform, OpenCLContext& cl) : CommonIntegrateRPMDStepKernel(const std::string& name, const Platform& platform, ComputeContext& cc) :
IntegrateRPMDStepKernel(name, platform), cl(cl), hasInitializedKernel(false) { IntegrateRPMDStepKernel(name, platform), cc(cc), hasInitializedKernels(false) {
} }
/** /**
* Initialize the kernel. * Initialize the kernel.
...@@ -71,11 +72,11 @@ public: ...@@ -71,11 +72,11 @@ public:
*/ */
double computeKineticEnergy(ContextImpl& context, const RPMDIntegrator& integrator); double computeKineticEnergy(ContextImpl& context, const RPMDIntegrator& integrator);
/** /**
* Get the positions of all particles in one copy of the system. * Set the positions of all particles in one copy of the system.
*/ */
void setPositions(int copy, const std::vector<Vec3>& positions); void setPositions(int copy, const std::vector<Vec3>& positions);
/** /**
* Get the velocities of all particles in one copy of the system. * Set the velocities of all particles in one copy of the system.
*/ */
void setVelocities(int copy, const std::vector<Vec3>& velocities); void setVelocities(int copy, const std::vector<Vec3>& velocities);
/** /**
...@@ -86,21 +87,21 @@ private: ...@@ -86,21 +87,21 @@ private:
void initializeKernels(ContextImpl& context); void initializeKernels(ContextImpl& context);
void computeForces(ContextImpl& context); void computeForces(ContextImpl& context);
std::string createFFT(int size, const std::string& variable, bool forward); std::string createFFT(int size, const std::string& variable, bool forward);
OpenCLContext& cl; ComputeContext& cc;
bool hasInitializedKernel; bool hasInitializedKernels;
int numCopies, numParticles, workgroupSize; int numCopies, numParticles, workgroupSize;
std::map<int, int> groupsByCopies; std::map<int, int> groupsByCopies;
int groupsNotContracted; int groupsNotContracted;
OpenCLArray forces; ComputeArray forces;
OpenCLArray positions; ComputeArray positions;
OpenCLArray velocities; ComputeArray velocities;
OpenCLArray contractedForces; ComputeArray contractedForces;
OpenCLArray contractedPositions; ComputeArray contractedPositions;
cl::Kernel pileKernel, stepKernel, velocitiesKernel, copyToContextKernel, copyFromContextKernel, translateKernel; ComputeKernel pileKernel, stepKernel, velocitiesKernel, copyToContextKernel, copyFromContextKernel, translateKernel;
std::map<int, cl::Kernel> positionContractionKernels; std::map<int, ComputeKernel> positionContractionKernels;
std::map<int, cl::Kernel> forceContractionKernels; std::map<int, ComputeKernel> forceContractionKernels;
}; };
} // namespace OpenMM } // namespace OpenMM
#endif /*OPENCL_RPMD_KERNELS_H_*/ #endif /*COMMON_RPMD_KERNELS_H_*/
__device__ mixed3 multiplyComplexRealPart(mixed2 c1, mixed3 c2r, mixed3 c2i) { DEVICE mixed3 multiplyComplexRealPart(mixed2 c1, mixed3 c2r, mixed3 c2i) {
return c1.x*c2r-c1.y*c2i; return c1.x*c2r-c1.y*c2i;
} }
__device__ mixed3 multiplyComplexImagPart(mixed2 c1, mixed3 c2r, mixed3 c2i) { DEVICE mixed3 multiplyComplexImagPart(mixed2 c1, mixed3 c2r, mixed3 c2i) {
return c1.x*c2i+c1.y*c2r; return c1.x*c2i+c1.y*c2r;
} }
__device__ mixed3 multiplyComplexRealPartConj(mixed2 c1, mixed3 c2r, mixed3 c2i) { DEVICE mixed3 multiplyComplexRealPartConj(mixed2 c1, mixed3 c2r, mixed3 c2i) {
return c1.x*c2r+c1.y*c2i; return c1.x*c2r+c1.y*c2i;
} }
__device__ mixed3 multiplyComplexImagPartConj(mixed2 c1, mixed3 c2r, mixed3 c2i) { DEVICE mixed3 multiplyComplexImagPartConj(mixed2 c1, mixed3 c2r, mixed3 c2i) {
return c1.x*c2i-c1.y*c2r; return c1.x*c2i-c1.y*c2r;
} }
/** /**
* Apply the PILE-L thermostat. * Apply the PILE-L thermostat.
*/ */
extern "C" __global__ void applyPileThermostat(mixed4* velm, float4* random, unsigned int randomIndex, KERNEL void applyPileThermostat(GLOBAL mixed4* velm, GLOBAL float4* random, unsigned int randomIndex,
mixed dt, mixed kT, mixed friction) { mixed dt, mixed kT, mixed friction) {
const int numBlocks = blockDim.x*gridDim.x/NUM_COPIES; const int numBlocks = GLOBAL_SIZE/NUM_COPIES;
const int blockStart = NUM_COPIES*(threadIdx.x/NUM_COPIES); const int blockStart = NUM_COPIES*(LOCAL_ID/NUM_COPIES);
const int indexInBlock = threadIdx.x-blockStart; const int indexInBlock = LOCAL_ID-blockStart;
const mixed nkT = NUM_COPIES*kT; const mixed nkT = NUM_COPIES*kT;
const mixed twown = 2.0f*nkT/HBAR; const mixed twown = 2.0f*nkT/HBAR;
const mixed c1_0 = EXP(-0.5f*dt*friction); const mixed c1_0 = exp(-0.5f*dt*friction);
const mixed c2_0 = SQRT(1.0f-c1_0*c1_0); const mixed c2_0 = sqrt(1.0f-c1_0*c1_0);
__shared__ mixed3 v[2*THREAD_BLOCK_SIZE]; LOCAL mixed3 v[2*THREAD_BLOCK_SIZE];
__shared__ mixed3 temp[2*THREAD_BLOCK_SIZE]; LOCAL mixed3 temp[2*THREAD_BLOCK_SIZE];
__shared__ mixed2 w[NUM_COPIES]; LOCAL mixed2 w[NUM_COPIES];
mixed3* vreal = &v[blockStart]; LOCAL_ARG mixed3* vreal = &v[blockStart];
mixed3* vimag = &v[blockStart+blockDim.x]; LOCAL_ARG mixed3* vimag = &v[blockStart+LOCAL_SIZE];
if (threadIdx.x < NUM_COPIES) if (LOCAL_ID < NUM_COPIES)
w[indexInBlock] = make_mixed2(cos(-indexInBlock*2*M_PI/NUM_COPIES), sin(-indexInBlock*2*M_PI/NUM_COPIES)); w[indexInBlock] = make_mixed2(cos(-indexInBlock*2*M_PI/NUM_COPIES), sin(-indexInBlock*2*M_PI/NUM_COPIES));
__syncthreads(); SYNC_THREADS;
randomIndex += NUM_COPIES*((blockIdx.x*blockDim.x+threadIdx.x)/NUM_COPIES); randomIndex += NUM_COPIES*((GLOBAL_ID)/NUM_COPIES);
for (int particle = (blockIdx.x*blockDim.x+threadIdx.x)/NUM_COPIES; particle < NUM_ATOMS; particle += numBlocks) { for (int particle = (GLOBAL_ID)/NUM_COPIES; particle < NUM_ATOMS; particle += numBlocks) {
mixed4 particleVelm = velm[particle+indexInBlock*PADDED_NUM_ATOMS]; mixed4 particleVelm = velm[particle+indexInBlock*PADDED_NUM_ATOMS];
mixed invMass = particleVelm.w; mixed invMass = particleVelm.w;
mixed c3_0 = c2_0*SQRT(nkT*invMass); mixed c3_0 = c2_0*sqrt(nkT*invMass);
// Forward FFT. // Forward FFT.
vreal[indexInBlock] = SCALE*make_mixed3(particleVelm.x, particleVelm.y, particleVelm.z); vreal[indexInBlock] = SCALE*make_mixed3(particleVelm.x, particleVelm.y, particleVelm.z);
vimag[indexInBlock] = make_mixed3(0); vimag[indexInBlock] = make_mixed3(0);
__syncthreads(); SYNC_THREADS;
FFT_V_FORWARD FFT_V_FORWARD
// Apply the thermostat. // Apply the thermostat.
...@@ -61,43 +61,43 @@ extern "C" __global__ void applyPileThermostat(mixed4* velm, float4* random, uns ...@@ -61,43 +61,43 @@ extern "C" __global__ void applyPileThermostat(mixed4* velm, float4* random, uns
int k = (indexInBlock <= NUM_COPIES/2 ? indexInBlock : NUM_COPIES-indexInBlock); int k = (indexInBlock <= NUM_COPIES/2 ? indexInBlock : NUM_COPIES-indexInBlock);
const bool isCenter = (NUM_COPIES%2 == 0 && k == NUM_COPIES/2); const bool isCenter = (NUM_COPIES%2 == 0 && k == NUM_COPIES/2);
const mixed wk = twown*sin(k*M_PI/NUM_COPIES); const mixed wk = twown*sin(k*M_PI/NUM_COPIES);
const mixed c1 = EXP(-wk*dt); const mixed c1 = exp(-wk*dt);
const mixed c2 = SQRT((1.0f-c1*c1)/2.0f) * (isCenter ? sqrt(2.0f) : 1.0f); const mixed c2 = sqrt((1.0f-c1*c1)/2.0f) * (isCenter ? sqrt(2.0f) : 1.0f);
const mixed c3 = c2*SQRT(nkT*invMass); const mixed c3 = c2*sqrt(nkT*invMass);
float4 rand1 = random[randomIndex+k]; float4 rand1 = random[randomIndex+k];
float4 rand2 = (isCenter ? make_float4(0) : random[randomIndex+NUM_COPIES-k]); float4 rand2 = (isCenter ? make_float4(0) : random[randomIndex+NUM_COPIES-k]);
vreal[indexInBlock] = c1*vreal[indexInBlock] + c3*make_mixed3(rand1.x, rand1.y, rand1.z); vreal[indexInBlock] = c1*vreal[indexInBlock] + c3*make_mixed3(rand1.x, rand1.y, rand1.z);
vimag[indexInBlock] = c1*vimag[indexInBlock] + c3*(indexInBlock < NUM_COPIES/2 ? make_mixed3(rand2.x, rand2.y, rand2.z) : make_mixed3(-rand2.x, -rand2.y, -rand2.z)); vimag[indexInBlock] = c1*vimag[indexInBlock] + c3*(indexInBlock < NUM_COPIES/2 ? make_mixed3(rand2.x, rand2.y, rand2.z) : make_mixed3(-rand2.x, -rand2.y, -rand2.z));
} }
__syncthreads(); SYNC_THREADS;
// Inverse FFT. // Inverse FFT.
FFT_V_BACKWARD FFT_V_BACKWARD
if (invMass != 0) if (invMass != 0)
velm[particle+indexInBlock*PADDED_NUM_ATOMS] = make_mixed4(SCALE*vreal[indexInBlock].x, SCALE*vreal[indexInBlock].y, SCALE*vreal[indexInBlock].z, particleVelm.w); velm[particle+indexInBlock*PADDED_NUM_ATOMS] = make_mixed4(SCALE*vreal[indexInBlock].x, SCALE*vreal[indexInBlock].y, SCALE*vreal[indexInBlock].z, particleVelm.w);
randomIndex += blockDim.x*gridDim.x; randomIndex += GLOBAL_SIZE;
} }
} }
/** /**
* Advance the positions and velocities. * Advance the positions and velocities.
*/ */
extern "C" __global__ void integrateStep(mixed4* posq, mixed4* velm, long long* force, mixed dt, mixed kT) { KERNEL void integrateStep(GLOBAL mixed4* posq, GLOBAL mixed4* velm, GLOBAL mm_long* force, mixed dt, mixed kT) {
const int numBlocks = (blockDim.x*gridDim.x)/NUM_COPIES; const int numBlocks = (GLOBAL_SIZE)/NUM_COPIES;
const int blockStart = NUM_COPIES*(threadIdx.x/NUM_COPIES); const int blockStart = NUM_COPIES*(LOCAL_ID/NUM_COPIES);
const int indexInBlock = threadIdx.x-blockStart; const int indexInBlock = LOCAL_ID-blockStart;
const mixed nkT = NUM_COPIES*kT; const mixed nkT = NUM_COPIES*kT;
const mixed twown = 2.0f*nkT/HBAR; const mixed twown = 2.0f*nkT/HBAR;
const mixed forceScale = 1/(mixed) 0x100000000; const mixed forceScale = 1/(mixed) 0x100000000;
__shared__ mixed3 q[2*THREAD_BLOCK_SIZE]; LOCAL mixed3 q[2*THREAD_BLOCK_SIZE];
__shared__ mixed3 v[2*THREAD_BLOCK_SIZE]; LOCAL mixed3 v[2*THREAD_BLOCK_SIZE];
__shared__ mixed3 temp[2*THREAD_BLOCK_SIZE]; LOCAL mixed3 temp[2*THREAD_BLOCK_SIZE];
__shared__ mixed2 w[NUM_COPIES]; LOCAL mixed2 w[NUM_COPIES];
// Update velocities. // Update velocities.
for (int particle = (blockIdx.x*blockDim.x+threadIdx.x)/NUM_COPIES; particle < NUM_ATOMS; particle += numBlocks) { for (int particle = (GLOBAL_ID)/NUM_COPIES; particle < NUM_ATOMS; particle += numBlocks) {
int index = particle+indexInBlock*PADDED_NUM_ATOMS; int index = particle+indexInBlock*PADDED_NUM_ATOMS;
int forceIndex = particle+indexInBlock*PADDED_NUM_ATOMS*3; int forceIndex = particle+indexInBlock*PADDED_NUM_ATOMS*3;
mixed4 particleVelm = velm[index]; mixed4 particleVelm = velm[index];
...@@ -110,14 +110,14 @@ extern "C" __global__ void integrateStep(mixed4* posq, mixed4* velm, long long* ...@@ -110,14 +110,14 @@ extern "C" __global__ void integrateStep(mixed4* posq, mixed4* velm, long long*
// Evolve the free ring polymer by transforming to the frequency domain. // Evolve the free ring polymer by transforming to the frequency domain.
mixed3* qreal = &q[blockStart]; LOCAL_ARG mixed3* qreal = &q[blockStart];
mixed3* qimag = &q[blockStart+blockDim.x]; LOCAL_ARG mixed3* qimag = &q[blockStart+LOCAL_SIZE];
mixed3* vreal = &v[blockStart]; LOCAL_ARG mixed3* vreal = &v[blockStart];
mixed3* vimag = &v[blockStart+blockDim.x]; LOCAL_ARG mixed3* vimag = &v[blockStart+LOCAL_SIZE];
if (threadIdx.x < NUM_COPIES) if (LOCAL_ID < NUM_COPIES)
w[indexInBlock] = make_mixed2(cos(-indexInBlock*2*M_PI/NUM_COPIES), sin(-indexInBlock*2*M_PI/NUM_COPIES)); w[indexInBlock] = make_mixed2(cos(-indexInBlock*2*M_PI/NUM_COPIES), sin(-indexInBlock*2*M_PI/NUM_COPIES));
__syncthreads(); SYNC_THREADS;
for (int particle = (blockIdx.x*blockDim.x+threadIdx.x)/NUM_COPIES; particle < NUM_ATOMS; particle += numBlocks) { for (int particle = (GLOBAL_ID)/NUM_COPIES; particle < NUM_ATOMS; particle += numBlocks) {
mixed4 particlePosq = posq[particle+indexInBlock*PADDED_NUM_ATOMS]; mixed4 particlePosq = posq[particle+indexInBlock*PADDED_NUM_ATOMS];
mixed4 particleVelm = velm[particle+indexInBlock*PADDED_NUM_ATOMS]; mixed4 particleVelm = velm[particle+indexInBlock*PADDED_NUM_ATOMS];
...@@ -127,7 +127,7 @@ extern "C" __global__ void integrateStep(mixed4* posq, mixed4* velm, long long* ...@@ -127,7 +127,7 @@ extern "C" __global__ void integrateStep(mixed4* posq, mixed4* velm, long long*
qimag[indexInBlock] = make_mixed3(0); qimag[indexInBlock] = make_mixed3(0);
vreal[indexInBlock] = SCALE*make_mixed3(particleVelm.x, particleVelm.y, particleVelm.z); vreal[indexInBlock] = SCALE*make_mixed3(particleVelm.x, particleVelm.y, particleVelm.z);
vimag[indexInBlock] = make_mixed3(0); vimag[indexInBlock] = make_mixed3(0);
__syncthreads(); SYNC_THREADS;
FFT_Q_FORWARD FFT_Q_FORWARD
FFT_V_FORWARD FFT_V_FORWARD
...@@ -149,7 +149,7 @@ extern "C" __global__ void integrateStep(mixed4* posq, mixed4* velm, long long* ...@@ -149,7 +149,7 @@ extern "C" __global__ void integrateStep(mixed4* posq, mixed4* velm, long long*
vreal[indexInBlock] = vprimereal; vreal[indexInBlock] = vprimereal;
vimag[indexInBlock] = vprimeimag; vimag[indexInBlock] = vprimeimag;
} }
__syncthreads(); SYNC_THREADS;
// Inverse FFT. // Inverse FFT.
...@@ -165,15 +165,15 @@ extern "C" __global__ void integrateStep(mixed4* posq, mixed4* velm, long long* ...@@ -165,15 +165,15 @@ extern "C" __global__ void integrateStep(mixed4* posq, mixed4* velm, long long*
/** /**
* Advance the velocities by a half step. * Advance the velocities by a half step.
*/ */
extern "C" __global__ void advanceVelocities(mixed4* velm, long long* force, mixed dt) { KERNEL void advanceVelocities(GLOBAL mixed4* velm, GLOBAL mm_long* force, mixed dt) {
const int numBlocks = (blockDim.x*gridDim.x)/NUM_COPIES; const int numBlocks = (GLOBAL_SIZE)/NUM_COPIES;
const int blockStart = NUM_COPIES*(threadIdx.x/NUM_COPIES); const int blockStart = NUM_COPIES*(LOCAL_ID/NUM_COPIES);
const int indexInBlock = threadIdx.x-blockStart; const int indexInBlock = LOCAL_ID-blockStart;
const mixed forceScale = 1/(mixed) 0x100000000; const mixed forceScale = 1/(mixed) 0x100000000;
// Update velocities. // Update velocities.
for (int particle = (blockIdx.x*blockDim.x+threadIdx.x)/NUM_COPIES; particle < NUM_ATOMS; particle += numBlocks) { for (int particle = (GLOBAL_ID)/NUM_COPIES; particle < NUM_ATOMS; particle += numBlocks) {
int index = particle+indexInBlock*PADDED_NUM_ATOMS; int index = particle+indexInBlock*PADDED_NUM_ATOMS;
int forceIndex = particle+indexInBlock*PADDED_NUM_ATOMS*3; int forceIndex = particle+indexInBlock*PADDED_NUM_ATOMS*3;
mixed4 particleVelm = velm[index]; mixed4 particleVelm = velm[index];
...@@ -188,9 +188,9 @@ extern "C" __global__ void advanceVelocities(mixed4* velm, long long* force, mix ...@@ -188,9 +188,9 @@ extern "C" __global__ void advanceVelocities(mixed4* velm, long long* force, mix
/** /**
* Copy a set of positions and velocities from the integrator's arrays to the context. * Copy a set of positions and velocities from the integrator's arrays to the context.
*/ */
extern "C" __global__ void copyDataToContext(mixed4* srcVel, mixed4* dstVel, mixed4* srcPos, real4* dstPos, int* order, int copy) { KERNEL void copyDataToContext(GLOBAL mixed4* srcVel, GLOBAL mixed4* dstVel, GLOBAL mixed4* srcPos, GLOBAL real4* dstPos, GLOBAL int* order, int copy) {
const int base = copy*PADDED_NUM_ATOMS; const int base = copy*PADDED_NUM_ATOMS;
for (int particle = blockIdx.x*blockDim.x+threadIdx.x; particle < NUM_ATOMS; particle += blockDim.x*gridDim.x) { for (int particle = GLOBAL_ID; particle < NUM_ATOMS; particle += GLOBAL_SIZE) {
int index = base+order[particle]; int index = base+order[particle];
dstVel[particle] = srcVel[index]; dstVel[particle] = srcVel[index];
mixed4 posq = srcPos[index]; mixed4 posq = srcPos[index];
...@@ -203,10 +203,10 @@ extern "C" __global__ void copyDataToContext(mixed4* srcVel, mixed4* dstVel, mix ...@@ -203,10 +203,10 @@ extern "C" __global__ void copyDataToContext(mixed4* srcVel, mixed4* dstVel, mix
/** /**
* Copy a set of positions, velocities, and forces from the context to the integrator's arrays. * Copy a set of positions, velocities, and forces from the context to the integrator's arrays.
*/ */
extern "C" __global__ void copyDataFromContext(long long* srcForce, long long* dstForce, mixed4* srcVel, mixed4* dstVel, KERNEL void copyDataFromContext(GLOBAL mm_long* srcForce, GLOBAL mm_long* dstForce, GLOBAL mixed4* srcVel, GLOBAL mixed4* dstVel,
real4* srcPos, mixed4* dstPos, int* order, int copy) { GLOBAL real4* srcPos, GLOBAL mixed4* dstPos, GLOBAL int* order, int copy) {
const int base = copy*PADDED_NUM_ATOMS; const int base = copy*PADDED_NUM_ATOMS;
for (int particle = blockIdx.x*blockDim.x+threadIdx.x; particle < NUM_ATOMS; particle += blockDim.x*gridDim.x) { for (int particle = GLOBAL_ID; particle < NUM_ATOMS; particle += GLOBAL_SIZE) {
int index = order[particle]; int index = order[particle];
dstForce[base*3+index] = srcForce[particle]; dstForce[base*3+index] = srcForce[particle];
dstForce[base*3+index+PADDED_NUM_ATOMS] = srcForce[particle+PADDED_NUM_ATOMS]; dstForce[base*3+index+PADDED_NUM_ATOMS] = srcForce[particle+PADDED_NUM_ATOMS];
...@@ -223,8 +223,8 @@ extern "C" __global__ void copyDataFromContext(long long* srcForce, long long* d ...@@ -223,8 +223,8 @@ extern "C" __global__ void copyDataFromContext(long long* srcForce, long long* d
/** /**
* Atom positions in one copy have been modified. Apply the same offsets to all the other copies. * Atom positions in one copy have been modified. Apply the same offsets to all the other copies.
*/ */
extern "C" __global__ void applyCellTranslations(mixed4* posq, real4* movedPos, int* order, int movedCopy) { KERNEL void applyCellTranslations(GLOBAL mixed4* posq, GLOBAL real4* movedPos, GLOBAL int* order, int movedCopy) {
for (int particle = blockIdx.x*blockDim.x+threadIdx.x; particle < NUM_ATOMS; particle += blockDim.x*gridDim.x) { for (int particle = GLOBAL_ID; particle < NUM_ATOMS; particle += GLOBAL_SIZE) {
int index = order[particle]; int index = order[particle];
real4 p = movedPos[particle]; real4 p = movedPos[particle];
mixed4 delta = make_mixed4(p.x, p.y, p.z, p.w)-posq[movedCopy*PADDED_NUM_ATOMS+index]; mixed4 delta = make_mixed4(p.x, p.y, p.z, p.w)-posq[movedCopy*PADDED_NUM_ATOMS+index];
......
__device__ mixed3 multiplyComplexRealPart(mixed2 c1, mixed3 c2r, mixed3 c2i) { DEVICE mixed3 multiplyComplexRealPart(mixed2 c1, mixed3 c2r, mixed3 c2i) {
return c1.x*c2r-c1.y*c2i; return c1.x*c2r-c1.y*c2i;
} }
__device__ mixed3 multiplyComplexImagPart(mixed2 c1, mixed3 c2r, mixed3 c2i) { DEVICE mixed3 multiplyComplexImagPart(mixed2 c1, mixed3 c2r, mixed3 c2i) {
return c1.x*c2i+c1.y*c2r; return c1.x*c2i+c1.y*c2r;
} }
__device__ mixed3 multiplyComplexRealPartConj(mixed2 c1, mixed3 c2r, mixed3 c2i) { DEVICE mixed3 multiplyComplexRealPartConj(mixed2 c1, mixed3 c2r, mixed3 c2i) {
return c1.x*c2r+c1.y*c2i; return c1.x*c2r+c1.y*c2i;
} }
__device__ mixed3 multiplyComplexImagPartConj(mixed2 c1, mixed3 c2r, mixed3 c2i) { DEVICE mixed3 multiplyComplexImagPartConj(mixed2 c1, mixed3 c2r, mixed3 c2i) {
return c1.x*c2i-c1.y*c2r; return c1.x*c2i-c1.y*c2r;
} }
/** /**
* Compute the contracted positions * Compute the contracted positions
*/ */
extern "C" __global__ void contractPositions(mixed4* posq, mixed4* contracted) { KERNEL void contractPositions(GLOBAL mixed4* posq, GLOBAL mixed4* contracted) {
const int numBlocks = (blockDim.x*gridDim.x)/NUM_COPIES; const int numBlocks = (GLOBAL_SIZE)/NUM_COPIES;
const int blockStart = NUM_COPIES*(threadIdx.x/NUM_COPIES); const int blockStart = NUM_COPIES*(LOCAL_ID/NUM_COPIES);
const int indexInBlock = threadIdx.x-blockStart; const int indexInBlock = LOCAL_ID-blockStart;
__shared__ mixed3 q[2*THREAD_BLOCK_SIZE]; LOCAL mixed3 q[2*THREAD_BLOCK_SIZE];
__shared__ mixed3 temp[2*THREAD_BLOCK_SIZE]; LOCAL mixed3 temp[2*THREAD_BLOCK_SIZE];
__shared__ mixed2 w1[NUM_COPIES]; LOCAL mixed2 w1[NUM_COPIES];
__shared__ mixed2 w2[NUM_CONTRACTED_COPIES]; LOCAL mixed2 w2[NUM_CONTRACTED_COPIES];
mixed3* qreal = &q[blockStart]; LOCAL_ARG mixed3* qreal = &q[blockStart];
mixed3* qimag = &q[blockStart+blockDim.x]; LOCAL_ARG mixed3* qimag = &q[blockStart+LOCAL_SIZE];
mixed3* tempreal = &temp[blockStart]; LOCAL_ARG mixed3* tempreal = &temp[blockStart];
mixed3* tempimag = &temp[blockStart+blockDim.x]; LOCAL_ARG mixed3* tempimag = &temp[blockStart+LOCAL_SIZE];
if (threadIdx.x < NUM_COPIES) if (LOCAL_ID < NUM_COPIES)
w1[indexInBlock] = make_mixed2(cos(-indexInBlock*2*M_PI/NUM_COPIES), sin(-indexInBlock*2*M_PI/NUM_COPIES)); w1[indexInBlock] = make_mixed2(cos(-indexInBlock*2*M_PI/NUM_COPIES), sin(-indexInBlock*2*M_PI/NUM_COPIES));
if (threadIdx.x < NUM_CONTRACTED_COPIES) if (LOCAL_ID < NUM_CONTRACTED_COPIES)
w2[indexInBlock] = make_mixed2(cos(-indexInBlock*2*M_PI/NUM_CONTRACTED_COPIES), sin(-indexInBlock*2*M_PI/NUM_CONTRACTED_COPIES)); w2[indexInBlock] = make_mixed2(cos(-indexInBlock*2*M_PI/NUM_CONTRACTED_COPIES), sin(-indexInBlock*2*M_PI/NUM_CONTRACTED_COPIES));
__syncthreads(); SYNC_THREADS;
for (int particle = (blockIdx.x*blockDim.x+threadIdx.x)/NUM_COPIES; particle < NUM_ATOMS; particle += numBlocks) { for (int particle = (GLOBAL_ID)/NUM_COPIES; particle < NUM_ATOMS; particle += numBlocks) {
// Load the particle position. // Load the particle position.
mixed4 particlePosq = posq[particle+indexInBlock*PADDED_NUM_ATOMS]; mixed4 particlePosq = posq[particle+indexInBlock*PADDED_NUM_ATOMS];
...@@ -43,8 +43,8 @@ extern "C" __global__ void contractPositions(mixed4* posq, mixed4* contracted) { ...@@ -43,8 +43,8 @@ extern "C" __global__ void contractPositions(mixed4* posq, mixed4* contracted) {
// Forward FFT. // Forward FFT.
__syncthreads(); SYNC_THREADS;
mixed2* w = w1; LOCAL_ARG mixed2* w = w1;
FFT_Q_FORWARD FFT_Q_FORWARD
if (NUM_CONTRACTED_COPIES > 1) { if (NUM_CONTRACTED_COPIES > 1) {
// Compress the data to remove high frequencies. // Compress the data to remove high frequencies.
...@@ -52,12 +52,12 @@ extern "C" __global__ void contractPositions(mixed4* posq, mixed4* contracted) { ...@@ -52,12 +52,12 @@ extern "C" __global__ void contractPositions(mixed4* posq, mixed4* contracted) {
int start = (NUM_CONTRACTED_COPIES+1)/2; int start = (NUM_CONTRACTED_COPIES+1)/2;
tempreal[indexInBlock] = qreal[indexInBlock]; tempreal[indexInBlock] = qreal[indexInBlock];
tempimag[indexInBlock] = qimag[indexInBlock]; tempimag[indexInBlock] = qimag[indexInBlock];
__syncthreads(); SYNC_THREADS;
if (indexInBlock < NUM_CONTRACTED_COPIES) { if (indexInBlock < NUM_CONTRACTED_COPIES) {
qreal[indexInBlock] = tempreal[indexInBlock < start ? indexInBlock : indexInBlock+(NUM_COPIES-NUM_CONTRACTED_COPIES)]; qreal[indexInBlock] = tempreal[indexInBlock < start ? indexInBlock : indexInBlock+(NUM_COPIES-NUM_CONTRACTED_COPIES)];
qimag[indexInBlock] = tempimag[indexInBlock < start ? indexInBlock : indexInBlock+(NUM_COPIES-NUM_CONTRACTED_COPIES)]; qimag[indexInBlock] = tempimag[indexInBlock < start ? indexInBlock : indexInBlock+(NUM_COPIES-NUM_CONTRACTED_COPIES)];
} }
__syncthreads(); SYNC_THREADS;
w = w2; w = w2;
FFT_Q_BACKWARD FFT_Q_BACKWARD
} }
...@@ -72,25 +72,25 @@ extern "C" __global__ void contractPositions(mixed4* posq, mixed4* contracted) { ...@@ -72,25 +72,25 @@ extern "C" __global__ void contractPositions(mixed4* posq, mixed4* contracted) {
/** /**
* Apply the contracted forces to all copies. * Apply the contracted forces to all copies.
*/ */
extern "C" __global__ void contractForces(long long* force, long long* contracted) { KERNEL void contractForces(GLOBAL mm_long* force, GLOBAL mm_long* contracted) {
const int numBlocks = (blockDim.x*gridDim.x)/NUM_COPIES; const int numBlocks = (GLOBAL_SIZE)/NUM_COPIES;
const int blockStart = NUM_COPIES*(threadIdx.x/NUM_COPIES); const int blockStart = NUM_COPIES*(LOCAL_ID/NUM_COPIES);
const int indexInBlock = threadIdx.x-blockStart; const int indexInBlock = LOCAL_ID-blockStart;
const mixed forceScale = 1/(mixed) 0x100000000; const mixed forceScale = 1/(mixed) 0x100000000;
__shared__ mixed3 f[2*THREAD_BLOCK_SIZE]; LOCAL mixed3 f[2*THREAD_BLOCK_SIZE];
__shared__ mixed3 temp[2*THREAD_BLOCK_SIZE]; LOCAL mixed3 temp[2*THREAD_BLOCK_SIZE];
__shared__ mixed2 w1[NUM_COPIES]; LOCAL mixed2 w1[NUM_COPIES];
__shared__ mixed2 w2[NUM_CONTRACTED_COPIES]; LOCAL mixed2 w2[NUM_CONTRACTED_COPIES];
mixed3* freal = &f[blockStart]; LOCAL_ARG mixed3* freal = &f[blockStart];
mixed3* fimag = &f[blockStart+blockDim.x]; LOCAL_ARG mixed3* fimag = &f[blockStart+LOCAL_SIZE];
mixed3* tempreal = &temp[blockStart]; LOCAL_ARG mixed3* tempreal = &temp[blockStart];
mixed3* tempimag = &temp[blockStart+blockDim.x]; LOCAL_ARG mixed3* tempimag = &temp[blockStart+LOCAL_SIZE];
if (threadIdx.x < NUM_COPIES) if (LOCAL_ID < NUM_COPIES)
w1[indexInBlock] = make_mixed2(cos(-indexInBlock*2*M_PI/NUM_COPIES), sin(-indexInBlock*2*M_PI/NUM_COPIES)); w1[indexInBlock] = make_mixed2(cos(-indexInBlock*2*M_PI/NUM_COPIES), sin(-indexInBlock*2*M_PI/NUM_COPIES));
if (threadIdx.x < NUM_CONTRACTED_COPIES) if (LOCAL_ID < NUM_CONTRACTED_COPIES)
w2[indexInBlock] = make_mixed2(cos(-indexInBlock*2*M_PI/NUM_CONTRACTED_COPIES), sin(-indexInBlock*2*M_PI/NUM_CONTRACTED_COPIES)); w2[indexInBlock] = make_mixed2(cos(-indexInBlock*2*M_PI/NUM_CONTRACTED_COPIES), sin(-indexInBlock*2*M_PI/NUM_CONTRACTED_COPIES));
__syncthreads(); SYNC_THREADS;
for (int particle = (blockIdx.x*blockDim.x+threadIdx.x)/NUM_COPIES; particle < NUM_ATOMS; particle += numBlocks) { for (int particle = (GLOBAL_ID)/NUM_COPIES; particle < NUM_ATOMS; particle += numBlocks) {
// Load the force. // Load the force.
int forceIndex = particle+indexInBlock*PADDED_NUM_ATOMS*3; int forceIndex = particle+indexInBlock*PADDED_NUM_ATOMS*3;
...@@ -98,11 +98,11 @@ extern "C" __global__ void contractForces(long long* force, long long* contracte ...@@ -98,11 +98,11 @@ extern "C" __global__ void contractForces(long long* force, long long* contracte
freal[indexInBlock] = make_mixed3(contracted[forceIndex]*forceScale, contracted[forceIndex+PADDED_NUM_ATOMS]*forceScale, contracted[forceIndex+PADDED_NUM_ATOMS*2]*forceScale); freal[indexInBlock] = make_mixed3(contracted[forceIndex]*forceScale, contracted[forceIndex+PADDED_NUM_ATOMS]*forceScale, contracted[forceIndex+PADDED_NUM_ATOMS*2]*forceScale);
fimag[indexInBlock] = make_mixed3(0); fimag[indexInBlock] = make_mixed3(0);
} }
__syncthreads(); SYNC_THREADS;
// Forward FFT. // Forward FFT.
mixed2* w = w2; LOCAL_ARG mixed2* w = w2;
if (NUM_CONTRACTED_COPIES > 1) { if (NUM_CONTRACTED_COPIES > 1) {
FFT_F_FORWARD FFT_F_FORWARD
} }
...@@ -113,19 +113,19 @@ extern "C" __global__ void contractForces(long long* force, long long* contracte ...@@ -113,19 +113,19 @@ extern "C" __global__ void contractForces(long long* force, long long* contracte
int end = NUM_COPIES-NUM_CONTRACTED_COPIES+start; int end = NUM_COPIES-NUM_CONTRACTED_COPIES+start;
tempreal[indexInBlock] = freal[indexInBlock]; tempreal[indexInBlock] = freal[indexInBlock];
tempimag[indexInBlock] = fimag[indexInBlock]; tempimag[indexInBlock] = fimag[indexInBlock];
__syncthreads(); SYNC_THREADS;
if (indexInBlock >= start) { if (indexInBlock >= start) {
freal[indexInBlock] = (indexInBlock < end ? make_mixed3(0) : tempreal[indexInBlock-(NUM_COPIES-NUM_CONTRACTED_COPIES)]); freal[indexInBlock] = (indexInBlock < end ? make_mixed3(0) : tempreal[indexInBlock-(NUM_COPIES-NUM_CONTRACTED_COPIES)]);
fimag[indexInBlock] = (indexInBlock < end ? make_mixed3(0) : tempimag[indexInBlock-(NUM_COPIES-NUM_CONTRACTED_COPIES)]); fimag[indexInBlock] = (indexInBlock < end ? make_mixed3(0) : tempimag[indexInBlock-(NUM_COPIES-NUM_CONTRACTED_COPIES)]);
} }
__syncthreads(); SYNC_THREADS;
w = w1; w = w1;
FFT_F_BACKWARD FFT_F_BACKWARD
// Store results. // Store results.
force[forceIndex] += (long long) (FORCE_SCALE*freal[indexInBlock].x); force[forceIndex] += (mm_long) (FORCE_SCALE*freal[indexInBlock].x);
force[forceIndex+PADDED_NUM_ATOMS] += (long long) (FORCE_SCALE*freal[indexInBlock].y); force[forceIndex+PADDED_NUM_ATOMS] += (mm_long) (FORCE_SCALE*freal[indexInBlock].y);
force[forceIndex+PADDED_NUM_ATOMS*2] += (long long) (FORCE_SCALE*freal[indexInBlock].z); force[forceIndex+PADDED_NUM_ATOMS*2] += (mm_long) (FORCE_SCALE*freal[indexInBlock].z);
} }
} }
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
# The source is organized into subdirectories, but we handle them all from # The source is organized into subdirectories, but we handle them all from
# this CMakeLists file rather than letting CMake visit them as SUBDIRS. # this CMakeLists file rather than letting CMake visit them as SUBDIRS.
SET(OPENMM_SOURCE_SUBDIRS .) SET(OPENMM_SOURCE_SUBDIRS . ../common)
# Collect up information about the version of the OpenMM library we're building # Collect up information about the version of the OpenMM library we're building
...@@ -59,33 +59,25 @@ FOREACH(subdir ${OPENMM_SOURCE_SUBDIRS}) ...@@ -59,33 +59,25 @@ FOREACH(subdir ${OPENMM_SOURCE_SUBDIRS})
INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/${subdir}/include) INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/${subdir}/include)
ENDFOREACH(subdir) ENDFOREACH(subdir)
SET(COMMON_KERNELS_CPP ${CMAKE_CURRENT_BINARY_DIR}/../common/src/CommonRpmdKernelSources.cpp)
SET(SOURCE_FILES ${SOURCE_FILES} ${COMMON_KERNELS_CPP})
INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/src) INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/src)
INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/../common/src)
INCLUDE_DIRECTORIES(BEFORE ${CMAKE_SOURCE_DIR}/platforms/cuda/include) INCLUDE_DIRECTORIES(BEFORE ${CMAKE_SOURCE_DIR}/platforms/cuda/include)
INCLUDE_DIRECTORIES(BEFORE ${CMAKE_SOURCE_DIR}/platforms/cuda/src) INCLUDE_DIRECTORIES(BEFORE ${CMAKE_SOURCE_DIR}/platforms/cuda/src)
INCLUDE_DIRECTORIES(BEFORE ${CMAKE_BINARY_DIR}/platforms/cuda/src) INCLUDE_DIRECTORIES(BEFORE ${CMAKE_BINARY_DIR}/platforms/cuda/src)
INCLUDE_DIRECTORIES(BEFORE ${CMAKE_SOURCE_DIR}/platforms/common/include) INCLUDE_DIRECTORIES(BEFORE ${CMAKE_SOURCE_DIR}/platforms/common/include)
INCLUDE_DIRECTORIES(BEFORE ${CMAKE_BINARY_DIR}/platforms/common/src)
# Set variables needed for encoding kernel sources into a C++ class INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/../common/src)
SET(KERNEL_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
SET(KERNEL_SOURCE_CLASS CudaRpmdKernelSources)
SET(KERNELS_CPP ${CMAKE_CURRENT_BINARY_DIR}/src/${KERNEL_SOURCE_CLASS}.cpp)
SET(KERNELS_H ${CMAKE_CURRENT_BINARY_DIR}/src/${KERNEL_SOURCE_CLASS}.h)
SET(SOURCE_FILES ${SOURCE_FILES} ${KERNELS_CPP} ${KERNELS_H})
INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/src)
# Create the library # Create the library
INCLUDE_DIRECTORIES(${CUDA_TOOLKIT_INCLUDE}) INCLUDE_DIRECTORIES(${CUDA_TOOLKIT_INCLUDE})
FILE(GLOB CUDA_KERNELS ${KERNEL_SOURCE_DIR}/kernels/*.cu) SET_SOURCE_FILES_PROPERTIES(${COMMON_KERNELS_CPP} PROPERTIES GENERATED TRUE)
ADD_CUSTOM_COMMAND(OUTPUT ${KERNELS_CPP} ${KERNELS_H}
COMMAND ${CMAKE_COMMAND}
ARGS -D KERNEL_SOURCE_DIR=${KERNEL_SOURCE_DIR} -D KERNELS_CPP=${KERNELS_CPP} -D KERNELS_H=${KERNELS_H} -D KERNEL_SOURCE_CLASS=${KERNEL_SOURCE_CLASS} -D KERNEL_FILE_EXTENSION=cu -P ${CMAKE_SOURCE_DIR}/cmake_modules/EncodeKernelFiles.cmake
DEPENDS ${CUDA_KERNELS}
)
SET_SOURCE_FILES_PROPERTIES(${KERNELS_CPP} ${KERNELS_H} PROPERTIES GENERATED TRUE)
ADD_LIBRARY(${SHARED_TARGET} SHARED ${SOURCE_FILES} ${SOURCE_INCLUDE_FILES} ${API_ABS_INCLUDE_FILES}) ADD_LIBRARY(${SHARED_TARGET} SHARED ${SOURCE_FILES} ${SOURCE_INCLUDE_FILES} ${API_ABS_INCLUDE_FILES})
ADD_DEPENDENCIES(${SHARED_TARGET} RpmdCommonKernels)
TARGET_LINK_LIBRARIES(${SHARED_TARGET} ${OPENMM_LIBRARY_NAME} ${PTHREADS_LIB}) TARGET_LINK_LIBRARIES(${SHARED_TARGET} ${OPENMM_LIBRARY_NAME} ${PTHREADS_LIB})
TARGET_LINK_LIBRARIES(${SHARED_TARGET} ${OPENMM_LIBRARY_NAME}CUDA) TARGET_LINK_LIBRARIES(${SHARED_TARGET} ${OPENMM_LIBRARY_NAME}CUDA)
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * Medical Research, grant U54 GM072970. See https://simtk.org. *
* * * *
* Portions copyright (c) 2011-2012 Stanford University and the Authors. * * Portions copyright (c) 2011-2021 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -27,7 +27,8 @@ ...@@ -27,7 +27,8 @@
#include <exception> #include <exception>
#include "CudaRpmdKernelFactory.h" #include "CudaRpmdKernelFactory.h"
#include "CudaRpmdKernels.h" #include "CommonRpmdKernels.h"
#include "CudaContext.h"
#include "openmm/internal/windowsExport.h" #include "openmm/internal/windowsExport.h"
#include "openmm/internal/ContextImpl.h" #include "openmm/internal/ContextImpl.h"
#include "openmm/OpenMMException.h" #include "openmm/OpenMMException.h"
...@@ -61,6 +62,6 @@ extern "C" OPENMM_EXPORT void registerRPMDCudaKernelFactories() { ...@@ -61,6 +62,6 @@ extern "C" OPENMM_EXPORT void registerRPMDCudaKernelFactories() {
KernelImpl* CudaRpmdKernelFactory::createKernelImpl(std::string name, const Platform& platform, ContextImpl& context) const { KernelImpl* CudaRpmdKernelFactory::createKernelImpl(std::string name, const Platform& platform, ContextImpl& context) const {
CudaContext& cl = *static_cast<CudaPlatform::PlatformData*>(context.getPlatformData())->contexts[0]; CudaContext& cl = *static_cast<CudaPlatform::PlatformData*>(context.getPlatformData())->contexts[0];
if (name == IntegrateRPMDStepKernel::Name()) if (name == IntegrateRPMDStepKernel::Name())
return new CudaIntegrateRPMDStepKernel(name, platform, cl); return new CommonIntegrateRPMDStepKernel(name, platform, cl);
throw OpenMMException((std::string("Tried to create kernel with illegal kernel name '")+name+"'").c_str()); throw OpenMMException((std::string("Tried to create kernel with illegal kernel name '")+name+"'").c_str());
} }
#ifndef CUDA_RPMD_KERNELS_H_
#define CUDA_RPMD_KERNELS_H_
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2011-2018 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "openmm/RpmdKernels.h"
#include "CudaContext.h"
#include "CudaArray.h"
#include <map>
namespace OpenMM {
/**
* This kernel is invoked by RPMDIntegrator to take one time step, and to get and
* set the state of system copies.
*/
class CudaIntegrateRPMDStepKernel : public IntegrateRPMDStepKernel {
public:
CudaIntegrateRPMDStepKernel(const std::string& name, const Platform& platform, CudaContext& cu) :
IntegrateRPMDStepKernel(name, platform), cu(cu) {
}
/**
* Initialize the kernel.
*
* @param system the System this kernel will be applied to
* @param integrator the RPMDIntegrator this kernel will be used for
*/
void initialize(const System& system, const RPMDIntegrator& integrator);
/**
* Execute the kernel.
*
* @param context the context in which to execute this kernel
* @param integrator the RPMDIntegrator this kernel is being used for
* @param forcesAreValid if the context has been modified since the last time step, this will be
* false to show that cached forces are invalid and must be recalculated
*/
void execute(ContextImpl& context, const RPMDIntegrator& integrator, bool forcesAreValid);
/**
* Compute the kinetic energy.
*
* @param context the context in which to execute this kernel
* @param integrator the RPMDIntegrator this kernel is being used for
*/
double computeKineticEnergy(ContextImpl& context, const RPMDIntegrator& integrator);
/**
* Get the positions of all particles in one copy of the system.
*/
void setPositions(int copy, const std::vector<Vec3>& positions);
/**
* Get the velocities of all particles in one copy of the system.
*/
void setVelocities(int copy, const std::vector<Vec3>& velocities);
/**
* Copy positions and velocities for one copy into the context.
*/
void copyToContext(int copy, ContextImpl& context);
private:
void computeForces(ContextImpl& context);
std::string createFFT(int size, const std::string& variable, bool forward);
CudaContext& cu;
int numCopies, numParticles, workgroupSize;
std::map<int, int> groupsByCopies;
int groupsNotContracted;
CudaArray forces;
CudaArray positions;
CudaArray velocities;
CudaArray contractedForces;
CudaArray contractedPositions;
CUfunction pileKernel, stepKernel, velocitiesKernel, copyToContextKernel, copyFromContextKernel, translateKernel;
std::map<int, CUfunction> positionContractionKernels;
std::map<int, CUfunction> forceContractionKernels;
};
} // namespace OpenMM
#endif /*CUDA_RPMD_KERNELS_H_*/
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
ENABLE_TESTING() ENABLE_TESTING()
INCLUDE_DIRECTORIES(${CUDA_INCLUDE_DIR}) INCLUDE_DIRECTORIES(${CUDA_INCLUDE_DIR})
INCLUDE_DIRECTORIES(${OPENMM_DIR}/plugins/rpmd/tests)
INCLUDE_DIRECTORIES(${OPENMM_DIR}/platforms/cuda/tests)
# Automatically create tests using files named "Test*.cpp" # Automatically create tests using files named "Test*.cpp"
FILE(GLOB TEST_PROGS "*Test*.cpp") FILE(GLOB TEST_PROGS "*Test*.cpp")
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment