Commit a416009a authored by Peter Eastman's avatar Peter Eastman
Browse files

Implemented dynamic loading of platforms from DLLs. Also fixed a lot of...

Implemented dynamic loading of platforms from DLLs.  Also fixed a lot of compilation errors and warnings under Windows.
parent 8f2f6e39
......@@ -168,24 +168,37 @@ public:
* Platform exists which supports all of them, this will throw an exception.
*/
static Platform& findPlatform(std::vector<std::string> kernelNames);
/**
* Load a dynamic library (DLL) which contains an OpenMM plugin. Typically, each Platform
* is distributed as a separate dynamic library. This method can then be called at runtime
* to load each available library. Each library should contain an initializer function to
* register any Platforms and KernelFactories that it contains.
*
* If the file does not exist or cannot be loaded, an exception is thrown.
*
* @param file the path to the dynamic library file. This is interpreted using the operating
* system's rules for loading libraries. Typically it may be either an absolute path
* or relative to a set of standard locations.
*/
static void loadPluginLibrary(std::string file);
private:
// Retarded visual studio compiler complains about being unable to
// export private stl class members.
// This stanza explains that it should temporarily shut up.
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4251)
// Retarded visual studio compiler complains about being unable to
// export private stl class members.
// This stanza explains that it should temporarily shut up.
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4251)
#endif
std::map<std::string, KernelFactory*> kernelFactories;
std::map<std::string, StreamFactory*> streamFactories;
static std::vector<Platform*> platforms;
static std::vector<Platform*>& getPlatforms();
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
};
} // namespace OpenMM
......
#ifndef OPENMM_PLATFORMEXCEPTION_H_
#define OPENMM_PLATFORMEXCEPTION_H_
#ifndef OPENMM_PLUGININITIALIZER_H_
#define OPENMM_PLUGININITIALIZER_H_
/* -------------------------------------------------------------------------- *
* OpenMM *
......@@ -32,28 +32,28 @@
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include <exception>
#include <string>
namespace OpenMM {
/**
* This class represents an exception thrown by a platform implementation.
* This file should be included once in each dynamic library that contains an OpenMM
* plugin. The library should define a function with the signature
*
* extern "C" void initOpenMMPlugin();
*
* that registers any Platforms and KernelFactories it contains. Including this file
* will cause that function to be invoked when the library is loaded.
*/
class PlatformException : public std::exception {
public:
PlatformException(std::string message) : message(message) {
}
~PlatformException() throw() {
}
const char* what() const throw() {
return message.c_str();
}
private:
std::string message;
};
} // namespace OpenMM
#if defined(OPENMM_BUILDING_SHARED_LIBRARY)
#if defined(WIN32)
#include <windows.h>
extern "C" void initOpenMMPlugin();
BOOL WINAPI DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
initOpenMMPlugin();
return TRUE;
}
#else
extern "C" void __attribute__((constructor)) initOpenMMPlugin();
#endif
#endif
#endif /*OPENMM_PLATFORMEXCEPTION_H_*/
#endif /*OPENMM_PLUGININITIALIZER_H_*/
......@@ -30,11 +30,17 @@
* -------------------------------------------------------------------------- */
#include "Platform.h"
#include "PlatformException.h"
#include "OpenMMException.h"
#include "Kernel.h"
#include "Stream.h"
#include "KernelFactory.h"
#include "StreamFactory.h"
#ifdef WIN32
#include <windows.h>
#include <sstream>
#else
#include <dlfcn.h>
#endif
#include <set>
#include "ReferencePlatform.h"
......@@ -42,8 +48,6 @@
using namespace OpenMM;
using namespace std;
std::vector<Platform*> Platform::platforms;
static int registerPlatforms() {
// Register the Platforms built into the main library. This should eventually be moved elsewhere.
......@@ -74,47 +78,53 @@ void Platform::contextCreated(OpenMMContextImpl& context) const {
void Platform::contextDestroyed(OpenMMContextImpl& context) const {
}
void Platform::registerKernelFactory(std::string name, KernelFactory* factory) {
void Platform::registerKernelFactory(string name, KernelFactory* factory) {
kernelFactories[name] = factory;
}
void Platform::registerStreamFactory(std::string name, StreamFactory* factory) {
void Platform::registerStreamFactory(string name, StreamFactory* factory) {
streamFactories[name] = factory;
}
bool Platform::supportsKernels(std::vector<std::string> kernelNames) const {
bool Platform::supportsKernels(vector<string> kernelNames) const {
for (int i = 0; i < (int) kernelNames.size(); ++i)
if (kernelFactories.find(kernelNames[i]) == kernelFactories.end())
return false;
return true;
}
Kernel Platform::createKernel(std::string name, OpenMMContextImpl& context) const {
Kernel Platform::createKernel(string name, OpenMMContextImpl& context) const {
if (kernelFactories.find(name) == kernelFactories.end())
throw PlatformException("Called createKernel() on a Platform which does not support the requested kernel");
throw OpenMMException("Called createKernel() on a Platform which does not support the requested kernel");
return Kernel(kernelFactories.find(name)->second->createKernelImpl(name, *this, context));
}
Stream Platform::createStream(std::string name, int size, Stream::DataType type, OpenMMContextImpl& context) const {
Stream Platform::createStream(string name, int size, Stream::DataType type, OpenMMContextImpl& context) const {
if (streamFactories.find(name) == streamFactories.end())
return Stream(getDefaultStreamFactory().createStreamImpl(name, size, type, *this, context));
return Stream(streamFactories.find(name)->second->createStreamImpl(name, size, type, *this, context));
}
vector<Platform*>& Platform::getPlatforms() {
static vector<Platform*> platforms;
return platforms;
}
void Platform::registerPlatform(Platform* platform) {
platforms.push_back(platform);
getPlatforms().push_back(platform);
}
int Platform::getNumPlatforms() {
return platforms.size();
return getPlatforms().size();
}
Platform& Platform::getPlatform(int index) {
return *platforms[index];
return *getPlatforms()[index];
}
Platform& Platform::findPlatform(std::vector<std::string> kernelNames) {
Platform& Platform::findPlatform(vector<string> kernelNames) {
Platform* best = 0;
vector<Platform*>& platforms = getPlatforms();
double speed = 0.0;
for (int i = 0; i < (int) platforms.size(); ++i) {
if (platforms[i]->supportsKernels(kernelNames) && platforms[i]->getSpeed() > speed) {
......@@ -123,6 +133,21 @@ Platform& Platform::findPlatform(std::vector<std::string> kernelNames) {
}
}
if (best == 0)
throw PlatformException("No Platform supports all the requested kernels");
throw OpenMMException("No Platform supports all the requested kernels");
return *best;
}
void Platform::loadPluginLibrary(string file) {
#ifdef WIN32
HMODULE handle = LoadLibrary(file.c_str());
if (handle == NULL) {
string message;
stringstream(message) << "Error loading library " << file << ": " << GetLastError();
throw OpenMMException(message);
}
#else
void *handle = dlopen(file.c_str(), RTLD_LAZY | RTLD_GLOBAL);
if (handle == NULL)
throw OpenMMException("Error loading library "+file+": "+dlerror());
#endif
}
......@@ -48,11 +48,15 @@ public:
* This is the name of the parameter which stores the current temperature of the
* heat bath (in Kelvin).
*/
static const std::string Temperature;
static std::string Temperature() {
return "AndersenTemperature";
}
/**
* This is the name of the parameter which store the current collision frequency (in 1/ps).
*/
static const std::string CollisionFrequency;
static std::string CollisionFrequency() {
return "AndersenCollisionFrequency";
}
/**
* Create an AndersenThermostat.
*
......
......@@ -34,9 +34,6 @@
using namespace OpenMM;
const std::string AndersenThermostat::Temperature = "AndersenTemperature";
const std::string AndersenThermostat::CollisionFrequency = "AndersenCollisionFrequency";
AndersenThermostat::AndersenThermostat(double defaultTemperature, double defaultCollisionFrequency) :
defaultTemp(defaultTemperature), defaultFreq(defaultCollisionFrequency) {
}
......
......@@ -53,8 +53,8 @@ void AndersenThermostatImpl::updateContextState(OpenMMContextImpl& context) {
std::map<std::string, double> AndersenThermostatImpl::getDefaultParameters() {
std::map<std::string, double> parameters;
parameters[AndersenThermostat::Temperature] = getOwner().getDefaultTemperature();
parameters[AndersenThermostat::CollisionFrequency] = getOwner().getDefaultCollisionFrequency();
parameters[AndersenThermostat::Temperature()] = getOwner().getDefaultTemperature();
parameters[AndersenThermostat::CollisionFrequency()] = getOwner().getDefaultCollisionFrequency();
return parameters;
}
......
......@@ -118,7 +118,7 @@ void CudaCalcHarmonicAngleForceKernel::initialize(const System& system, const Ha
data.primaryKernel = this;
data.hasAngles = true;
numAngles = force.getNumAngles();
const float RadiansToDegrees = 180.0/3.14159265;
const float RadiansToDegrees = (float) (180.0/3.14159265);
vector<int> particle1(numAngles);
vector<int> particle2(numAngles);
vector<int> particle3(numAngles);
......@@ -304,7 +304,7 @@ void CudaCalcGBSAOBCForceKernel::initialize(const System& system, const GBSAOBCF
radius[i] = (float) particleRadius;
scale[i] = (float) scalingFactor;
}
gpuSetObcParameters(gpu, force.getSoluteDielectric(), force.getSolventDielectric(), particle, radius, scale);
gpuSetObcParameters(gpu, (float) force.getSoluteDielectric(), (float) force.getSolventDielectric(), particle, radius, scale);
data.useOBC = true;
}
......@@ -372,6 +372,7 @@ static void initializeIntegration(const System& system, CudaPlatform::PlatformDa
}
double CudaCalcGBSAOBCForceKernel::executeEnergy(OpenMMContextImpl& context) {
return 0.0;
}
CudaIntegrateVerletStepKernel::~CudaIntegrateVerletStepKernel() {
......@@ -388,7 +389,7 @@ void CudaIntegrateVerletStepKernel::execute(OpenMMContextImpl& context, const Ve
if (stepSize != prevStepSize) {
// Initialize the GPU parameters.
gpuSetVerletIntegrationParameters(gpu, stepSize);
gpuSetVerletIntegrationParameters(gpu, (float) stepSize);
gpuSetConstants(gpu);
kGenerateRandoms(gpu);
prevStepSize = stepSize;
......@@ -396,7 +397,7 @@ void CudaIntegrateVerletStepKernel::execute(OpenMMContextImpl& context, const Ve
kVerletUpdatePart1(gpu);
kApplyFirstShake(gpu);
if (data.removeCM) {
int step = context.getTime()/stepSize;
int step = (int) (context.getTime()/stepSize);
if (step%data.cmMotionFrequency == 0)
gpu->bCalculateCM = true;
}
......@@ -420,7 +421,7 @@ void CudaIntegrateLangevinStepKernel::execute(OpenMMContextImpl& context, const
// Initialize the GPU parameters.
double tau = (friction == 0.0 ? 0.0 : 1.0/friction);
gpuSetIntegrationParameters(gpu, tau, stepSize, temperature);
gpuSetIntegrationParameters(gpu, (float) tau, (float) stepSize, (float) temperature);
gpuSetConstants(gpu);
kGenerateRandoms(gpu);
prevTemp = temperature;
......@@ -430,7 +431,7 @@ void CudaIntegrateLangevinStepKernel::execute(OpenMMContextImpl& context, const
kUpdatePart1(gpu);
kApplyFirstShake(gpu);
if (data.removeCM) {
int step = context.getTime()/stepSize;
int step = (int) (context.getTime()/stepSize);
if (step%data.cmMotionFrequency == 0)
gpu->bCalculateCM = true;
}
......@@ -455,7 +456,7 @@ void CudaIntegrateBrownianStepKernel::execute(OpenMMContextImpl& context, const
// Initialize the GPU parameters.
double tau = (friction == 0.0 ? 0.0 : 1.0/friction);
gpuSetBrownianIntegrationParameters(gpu, tau, stepSize, temperature);
gpuSetBrownianIntegrationParameters(gpu, (float) tau, (float) stepSize, (float) temperature);
gpuSetConstants(gpu);
kGenerateRandoms(gpu);
prevTemp = temperature;
......@@ -465,7 +466,7 @@ void CudaIntegrateBrownianStepKernel::execute(OpenMMContextImpl& context, const
kBrownianUpdatePart1(gpu);
kApplyFirstShake(gpu);
if (data.removeCM) {
int step = context.getTime()/stepSize;
int step = (int) (context.getTime()/stepSize);
if (step%data.cmMotionFrequency == 0)
gpu->bCalculateCM = true;
}
......@@ -481,13 +482,13 @@ void CudaApplyAndersenThermostatKernel::initialize(const System& system, const A
void CudaApplyAndersenThermostatKernel::execute(OpenMMContextImpl& context) {
_gpuContext* gpu = data.gpu;
double temperature = context.getParameter(AndersenThermostat::Temperature);
double frequency = context.getParameter(AndersenThermostat::CollisionFrequency);
double temperature = context.getParameter(AndersenThermostat::Temperature());
double frequency = context.getParameter(AndersenThermostat::CollisionFrequency());
double stepSize = context.getIntegrator().getStepSize();
if (temperature != prevTemp || frequency != prevFrequency || stepSize != prevStepSize) {
// Initialize the GPU parameters.
gpuSetAndersenThermostatParameters(gpu, temperature, frequency*stepSize);
gpuSetAndersenThermostatParameters(gpu, (float) temperature, (float) (frequency*stepSize));
gpuSetConstants(gpu);
kGenerateRandoms(gpu);
prevTemp = temperature;
......@@ -500,7 +501,7 @@ void CudaApplyAndersenThermostatKernel::execute(OpenMMContextImpl& context) {
void CudaCalcKineticEnergyKernel::initialize(const System& system) {
int numParticles = system.getNumParticles();
masses.resize(numParticles);
for (size_t i = 0; i < numParticles; ++i)
for (int i = 0; i < numParticles; ++i)
masses[i] = system.getParticleMass(i);
}
......
......@@ -32,12 +32,17 @@
#include "CudaPlatform.h"
#include "CudaKernelFactory.h"
#include "CudaKernels.h"
#include "PluginInitializer.h"
#include "internal/OpenMMContextImpl.h"
#include "kernels/gputypes.h"
#include "System.h"
using namespace OpenMM;
extern "C" void initOpenMMPlugin() {
Platform::registerPlatform(new CudaPlatform());
}
CudaPlatform::CudaPlatform() {
CudaKernelFactory* factory = new CudaKernelFactory();
registerKernelFactory(CalcHarmonicBondForceKernel::Name(), factory);
......
......@@ -121,7 +121,7 @@ void testTemperature() {
}
pe /= steps;
double expected = 0.5*numBonds*BOLTZ*temp;
ASSERT_EQUAL_TOL(expected, pe, 20*expected/std::sqrt(steps));
ASSERT_EQUAL_TOL(expected, pe, 20*expected/std::sqrt((double) steps));
}
void testConstraints() {
......
......@@ -119,8 +119,8 @@ void ReferenceCalcHarmonicBondForceKernel::initialize(const System& system, cons
force.getBondParameters(i, particle1, particle2, length, k);
bondIndexArray[i][0] = particle1;
bondIndexArray[i][1] = particle2;
bondParamArray[i][0] = length;
bondParamArray[i][1] = k;
bondParamArray[i][0] = (RealOpenMM) length;
bondParamArray[i][1] = (RealOpenMM) k;
}
}
......@@ -163,8 +163,8 @@ void ReferenceCalcHarmonicAngleForceKernel::initialize(const System& system, con
angleIndexArray[i][0] = particle1;
angleIndexArray[i][1] = particle2;
angleIndexArray[i][2] = particle3;
angleParamArray[i][0] = angle;
angleParamArray[i][1] = k;
angleParamArray[i][0] = (RealOpenMM) angle;
angleParamArray[i][1] = (RealOpenMM) k;
}
}
......@@ -208,9 +208,9 @@ void ReferenceCalcPeriodicTorsionForceKernel::initialize(const System& system, c
torsionIndexArray[i][1] = particle2;
torsionIndexArray[i][2] = particle3;
torsionIndexArray[i][3] = particle4;
torsionParamArray[i][0] = k;
torsionParamArray[i][1] = phase;
torsionParamArray[i][2] = periodicity;
torsionParamArray[i][0] = (RealOpenMM) k;
torsionParamArray[i][1] = (RealOpenMM) phase;
torsionParamArray[i][2] = (RealOpenMM) periodicity;
}
}
......@@ -254,12 +254,12 @@ void ReferenceCalcRBTorsionForceKernel::initialize(const System& system, const R
torsionIndexArray[i][1] = particle2;
torsionIndexArray[i][2] = particle3;
torsionIndexArray[i][3] = particle4;
torsionParamArray[i][0] = c0;
torsionParamArray[i][1] = c1;
torsionParamArray[i][2] = c2;
torsionParamArray[i][3] = c3;
torsionParamArray[i][4] = c4;
torsionParamArray[i][5] = c5;
torsionParamArray[i][0] = (RealOpenMM) c0;
torsionParamArray[i][1] = (RealOpenMM) c1;
torsionParamArray[i][2] = (RealOpenMM) c2;
torsionParamArray[i][3] = (RealOpenMM) c3;
torsionParamArray[i][4] = (RealOpenMM) c4;
torsionParamArray[i][5] = (RealOpenMM) c5;
}
}
......@@ -445,7 +445,7 @@ ReferenceIntegrateVerletStepKernel::~ReferenceIntegrateVerletStepKernel() {
void ReferenceIntegrateVerletStepKernel::initialize(const System& system, const VerletIntegrator& integrator) {
int numParticles = system.getNumParticles();
masses = new RealOpenMM[numParticles];
for (size_t i = 0; i < numParticles; ++i)
for (int i = 0; i < numParticles; ++i)
masses[i] = static_cast<RealOpenMM>(system.getParticleMass(i));
numConstraints = system.getNumConstraints();
constraintIndices = allocateIntArray(numConstraints, 2);
......@@ -496,7 +496,7 @@ ReferenceIntegrateLangevinStepKernel::~ReferenceIntegrateLangevinStepKernel() {
void ReferenceIntegrateLangevinStepKernel::initialize(const System& system, const LangevinIntegrator& integrator) {
int numParticles = system.getNumParticles();
masses = new RealOpenMM[numParticles];
for (size_t i = 0; i < numParticles; ++i)
for (int i = 0; i < numParticles; ++i)
masses[i] = static_cast<RealOpenMM>(system.getParticleMass(i));
numConstraints = system.getNumConstraints();
constraintIndices = allocateIntArray(numConstraints, 2);
......@@ -556,7 +556,7 @@ ReferenceIntegrateBrownianStepKernel::~ReferenceIntegrateBrownianStepKernel() {
void ReferenceIntegrateBrownianStepKernel::initialize(const System& system, const BrownianIntegrator& integrator) {
int numParticles = system.getNumParticles();
masses = new RealOpenMM[numParticles];
for (size_t i = 0; i < numParticles; ++i)
for (int i = 0; i < numParticles; ++i)
masses[i] = static_cast<RealOpenMM>(system.getParticleMass(i));
numConstraints = system.getNumConstraints();
constraintIndices = allocateIntArray(numConstraints, 2);
......@@ -609,7 +609,7 @@ ReferenceApplyAndersenThermostatKernel::~ReferenceApplyAndersenThermostatKernel(
void ReferenceApplyAndersenThermostatKernel::initialize(const System& system, const AndersenThermostat& thermostat) {
int numParticles = system.getNumParticles();
masses = new RealOpenMM[numParticles];
for (size_t i = 0; i < numParticles; ++i)
for (int i = 0; i < numParticles; ++i)
masses[i] = static_cast<RealOpenMM>(system.getParticleMass(i));
this->thermostat = new ReferenceAndersenThermostat();
}
......@@ -620,15 +620,15 @@ void ReferenceApplyAndersenThermostatKernel::execute(OpenMMContextImpl& context)
context.getVelocities().getSize(),
velData,
masses,
static_cast<RealOpenMM>(context.getParameter(AndersenThermostat::Temperature)),
static_cast<RealOpenMM>(context.getParameter(AndersenThermostat::CollisionFrequency)),
static_cast<RealOpenMM>(context.getParameter(AndersenThermostat::Temperature())),
static_cast<RealOpenMM>(context.getParameter(AndersenThermostat::CollisionFrequency())),
static_cast<RealOpenMM>(context.getIntegrator().getStepSize()) );
}
void ReferenceCalcKineticEnergyKernel::initialize(const System& system) {
int numParticles = system.getNumParticles();
masses.resize(numParticles);
for (size_t i = 0; i < numParticles; ++i)
for (int i = 0; i < numParticles; ++i)
masses[i] = system.getParticleMass(i);
}
......
......@@ -119,7 +119,7 @@ void testTemperature() {
}
pe /= steps;
double expected = 0.5*numBonds*BOLTZ*temp;
ASSERT_EQUAL_TOL(expected, pe, 20*expected/std::sqrt(steps));
ASSERT_EQUAL_TOL(expected, pe, 20*expected/std::sqrt((double) steps));
}
void testConstraints() {
......
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