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

Created OrientationRestraintForce (#5048)

* Created OrientationRestraintForce

* Python API

* Documentation

* Serialization

* GPU implementation of OrientationRestraintForce

* Bug fix

* Remove unused code
parent 44524bd1
...@@ -55,10 +55,8 @@ Pseudo-forces ...@@ -55,10 +55,8 @@ Pseudo-forces
============= =============
These inherit from ``Force``, but do not describe physical forces. They are used These inherit from ``Force``, but do not describe physical forces. They are used
to implement thermostats or barostats, or otherwise modify the simulation from for a variety of purposes: to implement thermostats or barostats, to apply biasing
step to step. They are conceptually closer to modifications to the integrator, potentials, or to otherwise modify the simulation from step to step.
but providing them as a ``Force`` simplifies implementation and allows them to
be combined in arbitrary ways.
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
...@@ -70,6 +68,7 @@ be combined in arbitrary ways. ...@@ -70,6 +68,7 @@ be combined in arbitrary ways.
generated/MonteCarloBarostat generated/MonteCarloBarostat
generated/MonteCarloFlexibleBarostat generated/MonteCarloFlexibleBarostat
generated/MonteCarloMembraneBarostat generated/MonteCarloMembraneBarostat
generated/OrientationRestraintForce
generated/RGForce generated/RGForce
generated/RMSDForce generated/RMSDForce
generated/RPMDMonteCarloBarostat generated/RPMDMonteCarloBarostat
......
...@@ -791,6 +791,27 @@ One rarely wants a force whose energy exactly equals the RMSD, but there are man ...@@ -791,6 +791,27 @@ One rarely wants a force whose energy exactly equals the RMSD, but there are man
situations where it is useful to have a restraining or biasing force that depends situations where it is useful to have a restraining or biasing force that depends
on the RMSD in some way. on the RMSD in some way.
OrientationRestraintForce
*************************
OrientationRestraintForce is used to keep a group of particles in a fixed
orientation. The calculation is closely related to the one in RMSD force. Both
forces begin by finding the translation and rotation that optimally superimpose
the current particle positions on a set of reference positions. Whereas
RMSDForce computes the deviation after removing the translation and rotation,
OrientationRestraintForce applies a force based on the rotation itself:
.. math::
E = 2 k \mathrm{sin}^2(\theta/2)
where :math:`k` is the force constant and :math:`\theta` is the rotation angle.
For small rotations, :math:`E \approx \frac{k}{2}\theta^2`, giving a harmonic
restraint. For large rotations, the restraint is weaker than harmonic, and the
force vanishes at :math:`\theta = \frac{\pi}{2}`. This ensures that the force
is continuous everywhere; a simple harmonic restraint would have a discontinuous
force at :math:`\frac{\pi}{2}`.
RGForce RGForce
********* *********
......
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
#include "openmm/HarmonicBondForce.h" #include "openmm/HarmonicBondForce.h"
#include "openmm/KernelImpl.h" #include "openmm/KernelImpl.h"
#include "openmm/MonteCarloBarostat.h" #include "openmm/MonteCarloBarostat.h"
#include "openmm/OrientationRestraintForce.h"
#include "openmm/PeriodicTorsionForce.h" #include "openmm/PeriodicTorsionForce.h"
#include "openmm/QTBIntegrator.h" #include "openmm/QTBIntegrator.h"
#include "openmm/RBTorsionForce.h" #include "openmm/RBTorsionForce.h"
...@@ -1100,6 +1101,41 @@ public: ...@@ -1100,6 +1101,41 @@ public:
virtual double execute(ContextImpl& context, bool includeForces, bool includeEnergy) = 0; virtual double execute(ContextImpl& context, bool includeForces, bool includeEnergy) = 0;
}; };
/**
* This kernel is invoked by OrientationRestraintForce to calculate the forces acting on the system and the energy of the system.
*/
class CalcOrientationRestraintForceKernel : public KernelImpl {
public:
static std::string Name() {
return "CalcOrientationRestraintForce";
}
CalcOrientationRestraintForceKernel(std::string name, const Platform& platform) : KernelImpl(name, platform) {
}
/**
* Initialize the kernel.
*
* @param system the System this kernel will be applied to
* @param force the OrientationRestraintForce this kernel will be used for
*/
virtual void initialize(const System& system, const OrientationRestraintForce& force) = 0;
/**
* Execute the kernel to calculate the forces and/or energy.
*
* @param context the context in which to execute this kernel
* @param includeForces true if forces should be calculated
* @param includeEnergy true if the energy should be calculated
* @return the potential energy due to the force
*/
virtual double execute(ContextImpl& context, bool includeForces, bool includeEnergy) = 0;
/**
* Copy changed parameters over to a context.
*
* @param context the context to copy parameters to
* @param force the OrientationRestraintForce to copy the parameters from
*/
virtual void copyParametersToContext(ContextImpl& context, const OrientationRestraintForce& force) = 0;
};
/** /**
* This kernel is invoked by VerletIntegrator to take one time step. * This kernel is invoked by VerletIntegrator to take one time step.
*/ */
......
...@@ -67,6 +67,7 @@ ...@@ -67,6 +67,7 @@
#include "openmm/NonbondedForce.h" #include "openmm/NonbondedForce.h"
#include "openmm/Context.h" #include "openmm/Context.h"
#include "openmm/OpenMMException.h" #include "openmm/OpenMMException.h"
#include "openmm/OrientationRestraintForce.h"
#include "openmm/PeriodicTorsionForce.h" #include "openmm/PeriodicTorsionForce.h"
#include "openmm/QTBIntegrator.h" #include "openmm/QTBIntegrator.h"
#include "openmm/RBTorsionForce.h" #include "openmm/RBTorsionForce.h"
......
#ifndef OPENMM_ORIENTATIONRESTRAINTFORCE_H_
#define OPENMM_ORIENTATIONRESTRAINTFORCE_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) 2025 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 "Force.h"
#include "Vec3.h"
#include <vector>
#include "internal/windowsExport.h"
namespace OpenMM {
/**
* This is an approximately harmonic restraint force for keeping a group of particles
* in a particular orientation. You specify a set of particles and reference positions
* for them. It finds the rigid transformation that optimally aligns the particles
* to the reference positions, consisting of a translation followed by a rotation.
* The interaction energy is 2*k*sin^2(theta/2), where theta is the rotation angle
* and k is a user defined force constant. When the particles are close to the target
* orientation, this approximately equals the harmonic form (k/2)*theta^2. For larger
* angles, the force is reduced from the harmonic form, and it goes to zero at theta=pi/2.
* This avoids the discontinuity in the force that would be present if the force were
* nonzero at pi/2.
*/
class OPENMM_EXPORT OrientationRestraintForce : public Force {
public:
/**
* Create an OrientationRestraintForce.
*
* @param k the force constant, measured in kJ/mol
* @param referencePositions the reference positions to compute the rotation
* from. The length of this vector must equal the
* number of particles in the system, even if not
* all particles are used in computing the rotation.
* @param particles the indices of the particles to use when computing
* the rotation. If this is empty (the default), all
* particles in the system will be used.
*/
explicit OrientationRestraintForce(double k, const std::vector<Vec3>& referencePositions,
const std::vector<int>& particles=std::vector<int>());
/**
* Get the force constant.
*
* @returns the force constant in kJ/mol
*/
double getK() const {
return k;
}
/**
* Set the force constant.
*
* @param k the force constant, measured in kJ/mol
*/
void setK(double k);
/**
* Get the reference positions to compute the rotation from.
*/
const std::vector<Vec3>& getReferencePositions() const {
return referencePositions;
}
/**
* Set the reference positions to compute the rotation from.
*/
void setReferencePositions(const std::vector<Vec3>& positions);
/**
* Get the indices of the particles to use when computing the rotation. If this
* is empty, all particles in the system will be used.
*/
const std::vector<int>& getParticles() const {
return particles;
}
/**
* Set the indices of the particles to use when computing the rotation. If this
* is empty, all particles in the system will be used.
*/
void setParticles(const std::vector<int>& particles);
/**
* Update the reference positions and particle indices in a Context to match those stored
* in this Force object. This method provides an efficient method to update certain parameters
* in an existing Context without needing to reinitialize it. Simply call setReferencePositions()
* setParticles(), and setK() to modify this object's parameters, then call updateParametersInContext()
* to copy them over to the Context.
*/
void updateParametersInContext(Context& context);
/**
* Returns whether or not this force makes use of periodic boundary
* conditions.
*
* @returns true if force uses PBC and false otherwise
*/
bool usesPeriodicBoundaryConditions() const {
return false;
}
protected:
ForceImpl* createImpl() const;
private:
double k;
std::vector<Vec3> referencePositions;
std::vector<int> particles;
};
} // namespace OpenMM
#endif /*OPENMM_ORIENTATIONRESTRAINTFORCE_H_*/
#ifndef OPENMM_ORIENTATIONRESTRAINTFORCEIMPL_H_
#define OPENMM_ORIENTATIONRESTRAINTFORCEIMPL_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) 2025 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 "ForceImpl.h"
#include "openmm/OrientationRestraintForce.h"
#include "openmm/Kernel.h"
#include <utility>
#include <map>
#include <string>
namespace OpenMM {
/**
* This is the internal implementation of OrientationRestraintForce.
*/
class OrientationRestraintForceImpl : public ForceImpl {
public:
OrientationRestraintForceImpl(const OrientationRestraintForce& owner);
~OrientationRestraintForceImpl();
void initialize(ContextImpl& context);
const OrientationRestraintForce& getOwner() const {
return owner;
}
void updateContextState(ContextImpl& context, bool& forcesInvalid) {
// This force field doesn't update the state directly.
}
double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups);
std::map<std::string, double> getDefaultParameters() {
return std::map<std::string, double>(); // This force doesn't define any parameters.
}
std::vector<std::string> getKernelNames();
void updateParametersInContext(ContextImpl& context);
private:
const OrientationRestraintForce& owner;
Kernel kernel;
};
} // namespace OpenMM
#endif /*OPENMM_ORIENTATIONRESTRAINTFORCEIMPL_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) 2025 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/OrientationRestraintForce.h"
#include "openmm/internal/OrientationRestraintForceImpl.h"
using namespace OpenMM;
using namespace std;
OrientationRestraintForce::OrientationRestraintForce(double k, const vector<Vec3>& referencePositions, const vector<int>& particles) :
k(k), referencePositions(referencePositions), particles(particles) {
}
void OrientationRestraintForce::setK(double k) {
this->k = k;
}
void OrientationRestraintForce::setReferencePositions(const std::vector<Vec3>& positions) {
referencePositions = positions;
}
void OrientationRestraintForce::setParticles(const std::vector<int>& particles) {
this->particles = particles;
}
void OrientationRestraintForce::updateParametersInContext(Context& context) {
dynamic_cast<OrientationRestraintForceImpl&>(getImplInContext(context)).updateParametersInContext(getContextImpl(context));
}
ForceImpl* OrientationRestraintForce::createImpl() const {
return new OrientationRestraintForceImpl(*this);
}
/* -------------------------------------------------------------------------- *
* 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) 2025 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/OpenMMException.h"
#include "openmm/internal/ContextImpl.h"
#include "openmm/internal/OrientationRestraintForceImpl.h"
#include "openmm/kernels.h"
#include <set>
#include <sstream>
using namespace OpenMM;
using namespace std;
OrientationRestraintForceImpl::OrientationRestraintForceImpl(const OrientationRestraintForce& owner) : owner(owner) {
forceGroup = owner.getForceGroup();
}
OrientationRestraintForceImpl::~OrientationRestraintForceImpl() {
}
void OrientationRestraintForceImpl::initialize(ContextImpl& context) {
kernel = context.getPlatform().createKernel(CalcOrientationRestraintForceKernel::Name(), context);
// Check for errors in the specification of particles.
const System& system = context.getSystem();
int numParticles = system.getNumParticles();
if (owner.getReferencePositions().size() != numParticles)
throw OpenMMException("OrientationRestraintForce: Number of reference positions does not equal number of particles in the System");
set<int> particles;
for (int i : owner.getParticles()) {
if (i < 0 || i >= numParticles) {
stringstream msg;
msg << "OrientationRestraintForce: Illegal particle index: ";
msg << i;
throw OpenMMException(msg.str());
}
if (particles.find(i) != particles.end()) {
stringstream msg;
msg << "OrientationRestraintForce: Duplicated particle index: ";
msg << i;
throw OpenMMException(msg.str());
}
particles.insert(i);
}
kernel.getAs<CalcOrientationRestraintForceKernel>().initialize(context.getSystem(), owner);
}
double OrientationRestraintForceImpl::calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups) {
if ((groups&(1<<forceGroup)) != 0)
return kernel.getAs<CalcOrientationRestraintForceKernel>().execute(context, includeForces, includeEnergy);
return 0.0;
}
vector<string> OrientationRestraintForceImpl::getKernelNames() {
vector<string> names;
names.push_back(CalcOrientationRestraintForceKernel::Name());
return names;
}
void OrientationRestraintForceImpl::updateParametersInContext(ContextImpl& context) {
kernel.getAs<CalcOrientationRestraintForceKernel>().copyParametersToContext(context, owner);
context.systemChanged();
}
...@@ -1150,12 +1150,16 @@ public: ...@@ -1150,12 +1150,16 @@ public:
void copyParametersToContext(ContextImpl& context, const RMSDForce& force); void copyParametersToContext(ContextImpl& context, const RMSDForce& force);
private: private:
class ForceInfo; class ForceInfo;
class ReorderListener;
ComputeContext& cc; ComputeContext& cc;
ForceInfo* info; ForceInfo* info;
int blockSize; int blockSize;
double sumNormRef; double sumNormRef;
std::vector<int> particleVec;
std::vector<Vec3> centeredPositions;
ComputeArray referencePos, particles, buffer; ComputeArray referencePos, particles, buffer;
ComputeKernel kernel1, kernel2; ComputeKernel kernel1, kernel2;
ReorderListener* listener;
}; };
/** /**
...@@ -1189,6 +1193,60 @@ private: ...@@ -1189,6 +1193,60 @@ private:
ComputeKernel centerKernel, rgKernel, forceKernel; ComputeKernel centerKernel, rgKernel, forceKernel;
}; };
/**
* This kernel is invoked by OrientationRestraintForce to calculate the forces acting on the system and the energy of the system.
*/
class CommonCalcOrientationRestraintForceKernel : public CalcOrientationRestraintForceKernel {
public:
CommonCalcOrientationRestraintForceKernel(std::string name, const Platform& platform, ComputeContext& cc) : CalcOrientationRestraintForceKernel(name, platform), cc(cc) {
}
/**
* Initialize the kernel.
*
* @param system the System this kernel will be applied to
* @param force the OrientationRestraintForce this kernel will be used for
*/
void initialize(const System& system, const OrientationRestraintForce& force);
/**
* Record the reference positions and particle indices.
*/
void recordParameters(const OrientationRestraintForce& force);
/**
* Execute the kernel to calculate the forces and/or energy.
*
* @param context the context in which to execute this kernel
* @param includeForces true if forces should be calculated
* @param includeEnergy true if the energy should be calculated
* @return the potential energy due to the force
*/
double execute(ContextImpl& context, bool includeForces, bool includeEnergy);
/**
* This is the internal implementation of execute(), templatized on whether we're
* using single or double precision.
*/
template <class REAL>
double executeImpl(ContextImpl& context, bool includeForces);
/**
* Copy changed parameters over to a context.
*
* @param context the context to copy parameters to
* @param force the OrientationRestraintForce to copy the parameters from
*/
void copyParametersToContext(ContextImpl& context, const OrientationRestraintForce& force);
private:
class ForceInfo;
class ReorderListener;
ComputeContext& cc;
ForceInfo* info;
int blockSize;
double k;
std::vector<int> particleVec;
std::vector<Vec3> centeredPositions;
ComputeArray referencePos, particles, buffer, eigenvectors;
ComputeKernel kernel1, kernel2;
ReorderListener* listener;
};
/** /**
* This kernel is invoked by AndersenThermostat at the start of each time step to adjust the particle velocities. * This kernel is invoked by AndersenThermostat at the start of each time step to adjust the particle velocities.
*/ */
......
...@@ -3419,6 +3419,27 @@ private: ...@@ -3419,6 +3419,27 @@ private:
set<int> particles; set<int> particles;
}; };
class CommonCalcRMSDForceKernel::ReorderListener : public ComputeContext::ReorderListener {
public:
ReorderListener(ComputeContext& cc, const vector<int>& particleIndices, const vector<Vec3>& centeredPositions, ArrayInterface& referencePos) : cc(cc),
particleIndices(particleIndices), centeredPositions(centeredPositions), referencePos(referencePos) {
}
void execute() {
const vector<int>& order = cc.getAtomIndex();
vector<mm_double4> pos(centeredPositions.size());
for (int i = 0; i < particleIndices.size(); i++) {
Vec3 p = centeredPositions[order[particleIndices[i]]];
pos[particleIndices[i]] = mm_double4(p[0], p[1], p[2], 0);
}
referencePos.upload(pos, true);
}
private:
ComputeContext& cc;
const vector<int>& particleIndices;
const vector<Vec3>& centeredPositions;
ArrayInterface& referencePos;
};
void CommonCalcRMSDForceKernel::initialize(const System& system, const RMSDForce& force) { void CommonCalcRMSDForceKernel::initialize(const System& system, const RMSDForce& force) {
// Create data structures. // Create data structures.
...@@ -3431,6 +3452,8 @@ void CommonCalcRMSDForceKernel::initialize(const System& system, const RMSDForce ...@@ -3431,6 +3452,8 @@ void CommonCalcRMSDForceKernel::initialize(const System& system, const RMSDForce
referencePos.initialize(cc, system.getNumParticles(), 4*elementSize, "referencePos"); referencePos.initialize(cc, system.getNumParticles(), 4*elementSize, "referencePos");
particles.initialize<int>(cc, numParticles, "particles"); particles.initialize<int>(cc, numParticles, "particles");
buffer.initialize(cc, 13, elementSize, "buffer"); buffer.initialize(cc, 13, elementSize, "buffer");
listener = new ReorderListener(cc, particleVec, centeredPositions, referencePos);
cc.addReorderListener(listener);
recordParameters(force); recordParameters(force);
info = new ForceInfo(force); info = new ForceInfo(force);
cc.addForce(info); cc.addForce(info);
...@@ -3460,25 +3483,19 @@ void CommonCalcRMSDForceKernel::initialize(const System& system, const RMSDForce ...@@ -3460,25 +3483,19 @@ void CommonCalcRMSDForceKernel::initialize(const System& system, const RMSDForce
void CommonCalcRMSDForceKernel::recordParameters(const RMSDForce& force) { void CommonCalcRMSDForceKernel::recordParameters(const RMSDForce& force) {
// Record the parameters and center the reference positions. // Record the parameters and center the reference positions.
vector<int> particleVec = force.getParticles(); particleVec = force.getParticles();
if (particleVec.size() == 0) if (particleVec.size() == 0)
for (int i = 0; i < cc.getNumAtoms(); i++) for (int i = 0; i < cc.getNumAtoms(); i++)
particleVec.push_back(i); particleVec.push_back(i);
vector<Vec3> centeredPositions = force.getReferencePositions(); centeredPositions = force.getReferencePositions();
Vec3 center; Vec3 center;
for (int i : particleVec) for (int i : particleVec)
center += centeredPositions[i]; center += centeredPositions[i];
center /= particleVec.size(); center /= particleVec.size();
for (Vec3& p : centeredPositions) for (Vec3& p : centeredPositions)
p -= center; p -= center;
// Upload them to the device.
particles.upload(particleVec); particles.upload(particleVec);
vector<mm_double4> pos; listener->execute();
for (Vec3 p : centeredPositions)
pos.push_back(mm_double4(p[0], p[1], p[2], 0));
referencePos.upload(pos, true);
// Record the sum of the norms of the reference positions. // Record the sum of the norms of the reference positions.
...@@ -3676,6 +3693,215 @@ double CommonCalcRGForceKernel::execute(ContextImpl& context, bool includeForces ...@@ -3676,6 +3693,215 @@ double CommonCalcRGForceKernel::execute(ContextImpl& context, bool includeForces
return 0.0; return 0.0;
} }
class CommonCalcOrientationRestraintForceKernel::ForceInfo : public ComputeForceInfo {
public:
ForceInfo(const OrientationRestraintForce& force) : force(force) {
updateParticles();
}
void updateParticles() {
particles.clear();
for (int i : force.getParticles())
particles.insert(i);
}
bool areParticlesIdentical(int particle1, int particle2) {
bool include1 = (particles.find(particle1) != particles.end());
bool include2 = (particles.find(particle2) != particles.end());
return (include1 == include2);
}
private:
const OrientationRestraintForce& force;
set<int> particles;
};
class CommonCalcOrientationRestraintForceKernel::ReorderListener : public ComputeContext::ReorderListener {
public:
ReorderListener(ComputeContext& cc, const vector<int>& particleIndices, const vector<Vec3>& centeredPositions, ArrayInterface& referencePos) : cc(cc),
particleIndices(particleIndices), centeredPositions(centeredPositions), referencePos(referencePos) {
}
void execute() {
const vector<int>& order = cc.getAtomIndex();
vector<mm_double4> pos(centeredPositions.size());
for (int i = 0; i < particleIndices.size(); i++) {
Vec3 p = centeredPositions[order[particleIndices[i]]];
pos[particleIndices[i]] = mm_double4(p[0], p[1], p[2], 0);
}
referencePos.upload(pos, true);
}
private:
ComputeContext& cc;
const vector<int>& particleIndices;
const vector<Vec3>& centeredPositions;
ArrayInterface& referencePos;
};
void CommonCalcOrientationRestraintForceKernel::initialize(const System& system, const OrientationRestraintForce& force) {
// Create data structures.
ContextSelector selector(cc);
bool useDouble = cc.getUseDoublePrecision();
int elementSize = (useDouble ? sizeof(double) : sizeof(float));
int numParticles = force.getParticles().size();
if (numParticles == 0)
numParticles = system.getNumParticles();
referencePos.initialize(cc, system.getNumParticles(), 4*elementSize, "referencePos");
particles.initialize<int>(cc, numParticles, "particles");
buffer.initialize(cc, 9, elementSize, "buffer");
eigenvectors.initialize(cc, 4, 4*elementSize, "eigenvectors");
listener = new ReorderListener(cc, particleVec, centeredPositions, referencePos);
cc.addReorderListener(listener);
recordParameters(force);
info = new ForceInfo(force);
cc.addForce(info);
// Create the kernels.
blockSize = min(256, cc.getMaxThreadBlockSize());
map<string, string> defines;
defines["THREAD_BLOCK_SIZE"] = cc.intToString(blockSize);
ComputeProgram program = cc.compileProgram(CommonKernelSources::orientationRestraintForce, defines);
kernel1 = program->createKernel("computeCorrelationMatrix");
kernel2 = program->createKernel("computeOrientationForces");
kernel1->addArg();
kernel1->addArg(cc.getPosq());
kernel1->addArg(referencePos);
kernel1->addArg(particles);
kernel1->addArg(buffer);
kernel2->addArg();
kernel2->addArg(cc.getPaddedNumAtoms());
kernel2->addArg(referencePos);
kernel2->addArg(particles);
kernel2->addArg();
kernel2->addArg();
kernel2->addArg(eigenvectors);
kernel2->addArg(cc.getLongForceBuffer());
}
void CommonCalcOrientationRestraintForceKernel::recordParameters(const OrientationRestraintForce& force) {
// Record the parameters and center the reference positions.
k = force.getK();
particleVec = force.getParticles();
if (particleVec.size() == 0)
for (int i = 0; i < cc.getNumAtoms(); i++)
particleVec.push_back(i);
centeredPositions = force.getReferencePositions();
Vec3 center;
for (int i : particleVec)
center += centeredPositions[i];
center /= particleVec.size();
for (Vec3& p : centeredPositions)
p -= center;
particles.upload(particleVec);
listener->execute();
}
double CommonCalcOrientationRestraintForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
ContextSelector selector(cc);
if (cc.getUseDoublePrecision())
return executeImpl<double>(context, includeForces);
return executeImpl<float>(context, includeForces);
}
template <class REAL>
double CommonCalcOrientationRestraintForceKernel::executeImpl(ContextImpl& context, bool includeForces) {
// Execute the first kernel.
int numParticles = particles.getSize();
kernel1->setArg(0, numParticles);
kernel1->execute(blockSize, blockSize);
// Download the results, build the F matrix, and find the maximum eigenvalue
// and eigenvector.
vector<REAL> b;
buffer.download(b);
// JAMA::Eigenvalue may run into an infinite loop if we have any NaN
for (int i = 0; i < 9; i++) {
if (b[i] != b[i])
throw OpenMMException("NaN encountered during orientation restraint force calculation");
}
Array2D<double> F(4, 4);
F[0][0] = b[0*3+0] + b[1*3+1] + b[2*3+2];
F[1][0] = b[1*3+2] - b[2*3+1];
F[2][0] = b[2*3+0] - b[0*3+2];
F[3][0] = b[0*3+1] - b[1*3+0];
F[0][1] = b[1*3+2] - b[2*3+1];
F[1][1] = b[0*3+0] - b[1*3+1] - b[2*3+2];
F[2][1] = b[0*3+1] + b[1*3+0];
F[3][1] = b[0*3+2] + b[2*3+0];
F[0][2] = b[2*3+0] - b[0*3+2];
F[1][2] = b[0*3+1] + b[1*3+0];
F[2][2] = -b[0*3+0] + b[1*3+1] - b[2*3+2];
F[3][2] = b[1*3+2] + b[2*3+1];
F[0][3] = b[0*3+1] - b[1*3+0];
F[1][3] = b[0*3+2] + b[2*3+0];
F[2][3] = b[1*3+2] + b[2*3+1];
F[3][3] = -b[0*3+0] - b[1*3+1] + b[2*3+2];
JAMA::Eigenvalue<double> eigen(F);
Array1D<double> values;
eigen.getRealEigenvalues(values);
Array2D<double> vectors;
eigen.getV(vectors);
// Construct the quaternion and use it to compute the energy.
double q[] = {vectors[0][3], vectors[1][3], vectors[2][3], vectors[3][3]};
double energy = 2*k*(1.0-q[0]*q[0]);
// Invoke the kernel to apply forces.
if (q[0]*q[0] < 1.0 && includeForces) {
double theta = 2*asin(sqrt(1.0-q[0]*q[0]));
double dxdq = 4.0*k*sin(theta/2)*cos(theta/2)/sqrt(1.0-q[0]*q[0]);
if (vectors[0][3] > 0)
dxdq = -dxdq;
kernel2->setArg(0, numParticles);
if (cc.getUseDoublePrecision()) {
kernel2->setArg(4, dxdq);
kernel2->setArg(5, mm_double4(values[0], values[1], values[2], values[3]));
vector<mm_double4> v = {
mm_double4(vectors[0][0], vectors[0][1], vectors[0][2], vectors[0][3]),
mm_double4(vectors[1][0], vectors[1][1], vectors[1][2], vectors[1][3]),
mm_double4(vectors[2][0], vectors[2][1], vectors[2][2], vectors[2][3]),
mm_double4(vectors[3][0], vectors[3][1], vectors[3][2], vectors[3][3])
};
eigenvectors.upload(v);
}
else {
kernel2->setArg(4, (float) dxdq);
kernel2->setArg(5, mm_float4(values[0], values[1], values[2], values[3]));
vector<mm_float4> v = {
mm_float4(vectors[0][0], vectors[0][1], vectors[0][2], vectors[0][3]),
mm_float4(vectors[1][0], vectors[1][1], vectors[1][2], vectors[1][3]),
mm_float4(vectors[2][0], vectors[2][1], vectors[2][2], vectors[2][3]),
mm_float4(vectors[3][0], vectors[3][1], vectors[3][2], vectors[3][3])
};
eigenvectors.upload(v);
}
kernel2->execute(numParticles);
}
return energy;
}
void CommonCalcOrientationRestraintForceKernel::copyParametersToContext(ContextImpl& context, const OrientationRestraintForce& force) {
ContextSelector selector(cc);
if (referencePos.getSize() != force.getReferencePositions().size())
throw OpenMMException("updateParametersInContext: The number of reference positions has changed");
int numParticles = force.getParticles().size();
if (numParticles == 0)
numParticles = context.getSystem().getNumParticles();
if (numParticles != particles.getSize())
particles.resize(numParticles);
recordParameters(force);
// Mark that the current reordering may be invalid.
info->updateParticles();
cc.invalidateMolecules(info);
}
void CommonApplyAndersenThermostatKernel::initialize(const System& system, const AndersenThermostat& thermostat) { void CommonApplyAndersenThermostatKernel::initialize(const System& system, const AndersenThermostat& thermostat) {
ContextSelector selector(cc); ContextSelector selector(cc);
randomSeed = thermostat.getRandomNumberSeed(); randomSeed = thermostat.getRandomNumberSeed();
......
/**
* Sum a value over all threads.
*/
DEVICE real reduceValue(real value, LOCAL_ARG volatile real* temp) {
const int thread = LOCAL_ID;
SYNC_THREADS;
temp[thread] = value;
SYNC_THREADS;
for (int step = 1; step < 32; step *= 2) {
if (thread+step < LOCAL_SIZE && thread%(2*step) == 0)
temp[thread] = temp[thread] + temp[thread+step];
SYNC_WARPS;
}
for (int step = 32; step < LOCAL_SIZE; step *= 2) {
if (thread+step < LOCAL_SIZE && thread%(2*step) == 0)
temp[thread] = temp[thread] + temp[thread+step];
SYNC_THREADS;
}
return temp[0];
}
/**
* Compute the correlation matrix, used in finding the optimal rotation. This is executed as a single work group.
*/
KERNEL void computeCorrelationMatrix(int numParticles, GLOBAL const real4* RESTRICT posq, GLOBAL const real4* RESTRICT referencePos,
GLOBAL const int* RESTRICT particles, GLOBAL real* buffer) {
LOCAL volatile real temp[THREAD_BLOCK_SIZE];
// Compute the center of the particle positions.
real3 center = make_real3(0);
for (int i = LOCAL_ID; i < numParticles; i += LOCAL_SIZE)
center += trimTo3(posq[particles[i]]);
center.x = reduceValue(center.x, temp)/numParticles;
center.y = reduceValue(center.y, temp)/numParticles;
center.z = reduceValue(center.z, temp)/numParticles;
// Compute the correlation matrix.
real R[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
for (int i = LOCAL_ID; i < numParticles; i += LOCAL_SIZE) {
int index = particles[i];
real3 pos = trimTo3(posq[index]) - center;
real3 refPos = trimTo3(referencePos[index]);
R[0][0] += refPos.x*pos.x;
R[0][1] += refPos.x*pos.y;
R[0][2] += refPos.x*pos.z;
R[1][0] += refPos.y*pos.x;
R[1][1] += refPos.y*pos.y;
R[1][2] += refPos.y*pos.z;
R[2][0] += refPos.z*pos.x;
R[2][1] += refPos.z*pos.y;
R[2][2] += refPos.z*pos.z;
}
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
R[i][j] = reduceValue(R[i][j], temp);
// Copy everything into the output buffer to send back to the host.
if (LOCAL_ID == 0)
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
buffer[3*i+j] = R[i][j];
}
/**
* Apply forces based on the orientation.
*/
KERNEL void computeOrientationForces(int numParticles, int paddedNumAtoms, GLOBAL const real4* RESTRICT referencePos,
GLOBAL const int* RESTRICT particles, const real dxdq, const real4 eigenvalues, GLOBAL const real4* RESTRICT eigenvectors,
GLOBAL mm_long* RESTRICT forceBuffers) {
const int3 dsIndex[4][4] = {
{make_int3(0, 1, 2), make_int3(0, 2, 1), make_int3(2, 0, 0), make_int3(1, 0, 0)},
{make_int3(0, 2, 1), make_int3(0, 1, 2), make_int3(1, 0, 0), make_int3(2, 0, 0)},
{make_int3(2, 0, 0), make_int3(1, 0, 0), make_int3(0, 1, 2), make_int3(0, 2, 1)},
{make_int3(1, 0, 0), make_int3(2, 0, 0), make_int3(0, 2, 1), make_int3(0, 1, 2)}
};
const int3 dsScale[4][4] = {
{make_int3(1, 1, 1), make_int3(0, -1, 1), make_int3(1, 0, -1), make_int3(-1, 1, 0)},
{make_int3(0, -1, 1), make_int3(1, -1, -1), make_int3(1, 1, 0), make_int3(1, 0, 1)},
{make_int3(1, 0, -1), make_int3(1, 1, 0), make_int3(-1, 1, -1), make_int3(0, 1, 1)},
{make_int3(-1, 1, 0), make_int3(1, 0, 1), make_int3(0, 1, 1), make_int3(-1, -1, 1)}
};
for (int index = GLOBAL_ID; index < numParticles; index += GLOBAL_SIZE) {
int particle = particles[index];
real3 refPos = trimTo3(referencePos[particle]);
real p[3] = {refPos.x, refPos.y, refPos.z};
real3 dq = make_real3(0);
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++) {
real scale = ((eigenvectors[i].z*eigenvectors[0].z) / (eigenvalues.w-eigenvalues.z) +
(eigenvectors[i].y*eigenvectors[0].y) / (eigenvalues.w-eigenvalues.y) +
(eigenvectors[i].x*eigenvectors[0].x) / (eigenvalues.w-eigenvalues.x)) * eigenvectors[j].w;
real3 ds = make_real3(dsScale[i][j].x*p[dsIndex[i][j].x],
dsScale[i][j].y*p[dsIndex[i][j].y],
dsScale[i][j].z*p[dsIndex[i][j].z]);
dq += scale*ds;
}
real3 force = -dxdq*dq;
forceBuffers[particle] += realToFixedPoint(force.x);
forceBuffers[particle+paddedNumAtoms] += realToFixedPoint(force.y);
forceBuffers[particle+2*paddedNumAtoms] += realToFixedPoint(force.z);
}
}
...@@ -123,6 +123,8 @@ KernelImpl* CudaKernelFactory::createKernelImpl(std::string name, const Platform ...@@ -123,6 +123,8 @@ KernelImpl* CudaKernelFactory::createKernelImpl(std::string name, const Platform
return new CudaCalcATMForceKernel(name, platform, cu); return new CudaCalcATMForceKernel(name, platform, cu);
if (name == CalcCustomCPPForceKernel::Name()) if (name == CalcCustomCPPForceKernel::Name())
return new CommonCalcCustomCPPForceKernel(name, platform, context, cu); return new CommonCalcCustomCPPForceKernel(name, platform, context, cu);
if (name == CalcOrientationRestraintForceKernel::Name())
return new CommonCalcOrientationRestraintForceKernel(name, platform, cu);
if (name == CalcRGForceKernel::Name()) if (name == CalcRGForceKernel::Name())
return new CommonCalcRGForceKernel(name, platform, cu); return new CommonCalcRGForceKernel(name, platform, cu);
if (name == CalcRMSDForceKernel::Name()) if (name == CalcRMSDForceKernel::Name())
......
...@@ -94,6 +94,7 @@ CudaPlatform::CudaPlatform() { ...@@ -94,6 +94,7 @@ CudaPlatform::CudaPlatform() {
registerKernelFactory(CalcCustomCPPForceKernel::Name(), factory); registerKernelFactory(CalcCustomCPPForceKernel::Name(), factory);
registerKernelFactory(CalcCustomCVForceKernel::Name(), factory); registerKernelFactory(CalcCustomCVForceKernel::Name(), factory);
registerKernelFactory(CalcATMForceKernel::Name(), factory); registerKernelFactory(CalcATMForceKernel::Name(), factory);
registerKernelFactory(CalcOrientationRestraintForceKernel::Name(), factory);
registerKernelFactory(CalcRGForceKernel::Name(), factory); registerKernelFactory(CalcRGForceKernel::Name(), factory);
registerKernelFactory(CalcRMSDForceKernel::Name(), factory); registerKernelFactory(CalcRMSDForceKernel::Name(), factory);
registerKernelFactory(CalcCustomManyParticleForceKernel::Name(), factory); registerKernelFactory(CalcCustomManyParticleForceKernel::Name(), factory);
......
/* -------------------------------------------------------------------------- *
* 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) 2025 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 "CudaTests.h"
#include "TestOrientationRestraintForce.h"
void runPlatformTests() {
}
...@@ -122,6 +122,8 @@ KernelImpl* HipKernelFactory::createKernelImpl(std::string name, const Platform& ...@@ -122,6 +122,8 @@ KernelImpl* HipKernelFactory::createKernelImpl(std::string name, const Platform&
return new HipCalcCustomCVForceKernel(name, platform, cu); return new HipCalcCustomCVForceKernel(name, platform, cu);
if (name == CalcCustomCPPForceKernel::Name()) if (name == CalcCustomCPPForceKernel::Name())
return new CommonCalcCustomCPPForceKernel(name, platform, context, cu); return new CommonCalcCustomCPPForceKernel(name, platform, context, cu);
if (name == CalcOrientationRestraintForceKernel::Name())
return new CommonCalcOrientationRestraintForceKernel(name, platform, cu);
if (name == CalcRGForceKernel::Name()) if (name == CalcRGForceKernel::Name())
return new CommonCalcRGForceKernel(name, platform, cu); return new CommonCalcRGForceKernel(name, platform, cu);
if (name == CalcRMSDForceKernel::Name()) if (name == CalcRMSDForceKernel::Name())
......
...@@ -94,6 +94,7 @@ HipPlatform::HipPlatform() { ...@@ -94,6 +94,7 @@ HipPlatform::HipPlatform() {
registerKernelFactory(CalcCustomCompoundBondForceKernel::Name(), factory); registerKernelFactory(CalcCustomCompoundBondForceKernel::Name(), factory);
registerKernelFactory(CalcCustomCPPForceKernel::Name(), factory); registerKernelFactory(CalcCustomCPPForceKernel::Name(), factory);
registerKernelFactory(CalcCustomCVForceKernel::Name(), factory); registerKernelFactory(CalcCustomCVForceKernel::Name(), factory);
registerKernelFactory(CalcOrientationRestraintForceKernel::Name(), factory);
registerKernelFactory(CalcRGForceKernel::Name(), factory); registerKernelFactory(CalcRGForceKernel::Name(), factory);
registerKernelFactory(CalcRMSDForceKernel::Name(), factory); registerKernelFactory(CalcRMSDForceKernel::Name(), factory);
registerKernelFactory(CalcCustomManyParticleForceKernel::Name(), factory); registerKernelFactory(CalcCustomManyParticleForceKernel::Name(), factory);
......
/* -------------------------------------------------------------------------- *
* 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) 2025 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 "HipTests.h"
#include "TestOrientationRestraintForce.h"
void runPlatformTests() {
}
...@@ -121,6 +121,8 @@ KernelImpl* OpenCLKernelFactory::createKernelImpl(std::string name, const Platfo ...@@ -121,6 +121,8 @@ KernelImpl* OpenCLKernelFactory::createKernelImpl(std::string name, const Platfo
return new OpenCLCalcATMForceKernel(name, platform, cl); return new OpenCLCalcATMForceKernel(name, platform, cl);
if (name == CalcCustomCPPForceKernel::Name()) if (name == CalcCustomCPPForceKernel::Name())
return new CommonCalcCustomCPPForceKernel(name, platform, context, cl); return new CommonCalcCustomCPPForceKernel(name, platform, context, cl);
if (name == CalcOrientationRestraintForceKernel::Name())
return new CommonCalcOrientationRestraintForceKernel(name, platform, cl);
if (name == CalcRGForceKernel::Name()) if (name == CalcRGForceKernel::Name())
return new CommonCalcRGForceKernel(name, platform, cl); return new CommonCalcRGForceKernel(name, platform, cl);
if (name == CalcRMSDForceKernel::Name()) if (name == CalcRMSDForceKernel::Name())
......
...@@ -85,6 +85,7 @@ OpenCLPlatform::OpenCLPlatform() { ...@@ -85,6 +85,7 @@ OpenCLPlatform::OpenCLPlatform() {
registerKernelFactory(CalcCustomCPPForceKernel::Name(), factory); registerKernelFactory(CalcCustomCPPForceKernel::Name(), factory);
registerKernelFactory(CalcCustomCVForceKernel::Name(), factory); registerKernelFactory(CalcCustomCVForceKernel::Name(), factory);
registerKernelFactory(CalcATMForceKernel::Name(), factory); registerKernelFactory(CalcATMForceKernel::Name(), factory);
registerKernelFactory(CalcOrientationRestraintForceKernel::Name(), factory);
registerKernelFactory(CalcRGForceKernel::Name(), factory); registerKernelFactory(CalcRGForceKernel::Name(), factory);
registerKernelFactory(CalcRMSDForceKernel::Name(), factory); registerKernelFactory(CalcRMSDForceKernel::Name(), factory);
registerKernelFactory(CalcCustomManyParticleForceKernel::Name(), factory); registerKernelFactory(CalcCustomManyParticleForceKernel::Name(), factory);
......
/* -------------------------------------------------------------------------- *
* 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) 2025 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 "OpenCLTests.h"
#include "TestOrientationRestraintForce.h"
void runPlatformTests() {
}
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