Unverified Commit adfd84c2 authored by Evan Pretti's avatar Evan Pretti Committed by GitHub
Browse files

Add LCPO method (#5130)

* Basic LCPO support

* Add basic test for LCPO from a prmtop file

* API for LCPOForce

* Started LCPO reference implementation

* Finished reference forces & test cases

* Use other test for finite difference since grid might have discontinuous forces

* Reference platform formatting

* Initial implementation of CPU platform

* Bugfixes

* More vectorization and improve neighbor list query speed

* Parallelize part of neighbor search

* Check box size for LCPO with periodic boundary conditions

* Fixes for updating parameters in context

* GBSAOBCForce doesn't use first & last indices for updates, so no need for this optimization here

* Changes to neighbor checking and optimization

* Fixes and minor changes

* Add global surface tension parameter

* Only process half of the pairs in the neighbor list

* Remove unnecessary checks

* Initial version of common platform implementation

* Asynchronously download neighbor list size

* Debugging

* Do pair precomputation in copyPairsToNeighborList

* Recompute interactions instead of scanning neighbor list in inner loop

* Condense position array before computations

* Also make neighbor count download asynchronous on device

* Fixes for kernel launching

* Topology-based LCPO parameter assignment

* Fixes, and use test system for LCPO with nucleic acids

* Always raise instead of warn when LCPO parameters can't be assigned

* Use Amber convention for phosphates
parent ccb83f1d
......@@ -411,6 +411,17 @@ private:
CpuNeighborList::CpuNeighborList(int blockSize) : blockSize(blockSize) {
}
void CpuNeighborList::computeNeighborList(int numAtoms, const AlignedArray<float>& atomLocations, const vector<set<int> >& exclusions,
const Vec3* periodicBoxVectors, bool usePeriodic, float maxDistance, ThreadPool& threads, const std::vector<int>* indices) {
if (indices != NULL) {
this->indices = indices->data();
computeNeighborList<true>(numAtoms, atomLocations, exclusions, periodicBoxVectors, usePeriodic, maxDistance, threads);
} else {
computeNeighborList<false>(numAtoms, atomLocations, exclusions, periodicBoxVectors, usePeriodic, maxDistance, threads);
}
}
template<bool USE_INDICES>
void CpuNeighborList::computeNeighborList(int numAtoms, const AlignedArray<float>& atomLocations, const vector<set<int> >& exclusions,
const Vec3* periodicBoxVectors, bool usePeriodic, float maxDistance, ThreadPool& threads) {
dense = false;
......@@ -433,10 +444,12 @@ void CpuNeighborList::computeNeighborList(int numAtoms, const AlignedArray<float
// Identify the range of atom positions along each axis.
fvec4 minPos(&atomLocations[0]);
int minPosIndex = USE_INDICES ? indices[0] : 0;
fvec4 minPos(&atomLocations[4*minPosIndex]);
fvec4 maxPos = minPos;
for (int i = 0; i < numAtoms; i++) {
fvec4 pos(&atomLocations[4*i]);
for (int i = 1; i < numAtoms; i++) {
int posIndex = USE_INDICES ? indices[i] : i;
fvec4 pos(&atomLocations[4*posIndex]);
minPos = min(minPos, pos);
maxPos = max(maxPos, pos);
}
......@@ -450,7 +463,7 @@ void CpuNeighborList::computeNeighborList(int numAtoms, const AlignedArray<float
// Sort the atoms based on a Hilbert curve.
atomBins.resize(numAtoms);
threads.execute([&] (ThreadPool& threads, int threadIndex) { threadComputeNeighborList(threads, threadIndex); });
threads.execute([&] (ThreadPool& threads, int threadIndex) { threadComputeNeighborList<USE_INDICES>(threads, threadIndex); });
threads.waitForThreads();
sort(atomBins.begin(), atomBins.end());
......@@ -467,9 +480,10 @@ void CpuNeighborList::computeNeighborList(int numAtoms, const AlignedArray<float
for (int i = 0; i < numAtoms; i++) {
int atomIndex = atomBins[i].second;
sortedAtoms[i] = atomIndex;
fvec4 atomPos(&atomLocations[4*atomIndex]);
int atomPosIndex = USE_INDICES ? indices[atomIndex] : atomIndex;
fvec4 atomPos(&atomLocations[4*atomPosIndex]);
atomPos.store(&sortedPositions[4*i]);
voxels.insert(i, &atomLocations[4*atomIndex]);
voxels.insert(i, &atomLocations[4*atomPosIndex]);
}
voxels.sortItems();
this->voxels = &voxels;
......@@ -573,6 +587,7 @@ CpuNeighborList::NeighborIterator CpuNeighborList::getNeighborIterator(int block
return NeighborIterator(blockNeighbors[blockIndex], blockExclusions[blockIndex]);
}
template<bool USE_INDICES>
void CpuNeighborList::threadComputeNeighborList(ThreadPool& threads, int threadIndex) {
// Compute the positions of atoms along the Hilbert curve.
......@@ -581,7 +596,8 @@ void CpuNeighborList::threadComputeNeighborList(ThreadPool& threads, int threadI
bitmask_t coords[3];
int numThreads = threads.getNumThreads();
for (int i = threadIndex; i < numAtoms; i += numThreads) {
const float* pos = &atomLocations[4*i];
int posIndex = USE_INDICES ? indices[i] : i;
const float* pos = &atomLocations[4*posIndex];
coords[0] = (bitmask_t) ((pos[0]-minx)*invBinWidth);
coords[1] = (bitmask_t) ((pos[1]-miny)*invBinWidth);
coords[2] = (bitmask_t) ((pos[2]-minz)*invBinWidth);
......@@ -609,7 +625,8 @@ void CpuNeighborList::threadComputeNeighborList(ThreadPool& threads, int threadI
atomVoxelIndex.resize(atomsInBlock);
for (int j = 0; j < atomsInBlock; j++) {
blockAtoms[j] = sortedAtoms[firstIndex+j];
atomVoxelIndex[j] = voxels->getVoxelIndex(&atomLocations[4*blockAtoms[j]]);
int posIndex = USE_INDICES ? indices[blockAtoms[j]] : blockAtoms[j];
atomVoxelIndex[j] = voxels->getVoxelIndex(&atomLocations[4*posIndex]);
}
fvec4 minPos(&sortedPositions[4*firstIndex]);
fvec4 maxPos = minPos;
......
......@@ -73,6 +73,7 @@ CpuPlatform::CpuPlatform() {
registerKernelFactory(CalcGBSAOBCForceKernel::Name(), factory);
registerKernelFactory(CalcCustomGBForceKernel::Name(), factory);
registerKernelFactory(CalcGayBerneForceKernel::Name(), factory);
registerKernelFactory(CalcLCPOForceKernel::Name(), factory);
registerKernelFactory(IntegrateLangevinMiddleStepKernel::Name(), factory);
platformProperties.push_back(CpuThreads());
platformProperties.push_back(CpuDeterministicForces());
......
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit. *
* See https://openmm.org/development. *
* *
* Portions copyright (c) 2025 Stanford University and the Authors. *
* Authors: Peter Eastman, Evan Pretti *
* 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 "CpuTests.h"
#include "TestLCPOForce.h"
void runPlatformTests() {
}
......@@ -135,6 +135,8 @@ KernelImpl* CudaKernelFactory::createKernelImpl(std::string name, const Platform
return new CommonCalcCustomManyParticleForceKernel(name, platform, cu, context.getSystem());
if (name == CalcGayBerneForceKernel::Name())
return new CommonCalcGayBerneForceKernel(name, platform, cu);
if (name == CalcLCPOForceKernel::Name())
return new CommonCalcLCPOForceKernel(name, platform, cu);
if (name == IntegrateVerletStepKernel::Name())
return new CommonIntegrateVerletStepKernel(name, platform, cu);
if (name == IntegrateLangevinMiddleStepKernel::Name())
......
......@@ -99,6 +99,7 @@ CudaPlatform::CudaPlatform() {
registerKernelFactory(CalcRMSDForceKernel::Name(), factory);
registerKernelFactory(CalcCustomManyParticleForceKernel::Name(), factory);
registerKernelFactory(CalcGayBerneForceKernel::Name(), factory);
registerKernelFactory(CalcLCPOForceKernel::Name(), factory);
registerKernelFactory(IntegrateVerletStepKernel::Name(), factory);
registerKernelFactory(IntegrateNoseHooverStepKernel::Name(), factory);
registerKernelFactory(IntegrateLangevinMiddleStepKernel::Name(), factory);
......
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit. *
* See https://openmm.org/development. *
* *
* Portions copyright (c) 2025 Stanford University and the Authors. *
* Authors: Peter Eastman, Evan Pretti *
* 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 "TestLCPOForce.h"
void runPlatformTests() {
}
......@@ -134,6 +134,8 @@ KernelImpl* HipKernelFactory::createKernelImpl(std::string name, const Platform&
return new CommonCalcCustomManyParticleForceKernel(name, platform, cu, context.getSystem());
if (name == CalcGayBerneForceKernel::Name())
return new CommonCalcGayBerneForceKernel(name, platform, cu);
if (name == CalcLCPOForceKernel::Name())
return new CommonCalcLCPOForceKernel(name, platform, cu);
if (name == IntegrateVerletStepKernel::Name())
return new CommonIntegrateVerletStepKernel(name, platform, cu);
if (name == IntegrateLangevinMiddleStepKernel::Name())
......
......@@ -99,6 +99,7 @@ HipPlatform::HipPlatform() {
registerKernelFactory(CalcRMSDForceKernel::Name(), factory);
registerKernelFactory(CalcCustomManyParticleForceKernel::Name(), factory);
registerKernelFactory(CalcGayBerneForceKernel::Name(), factory);
registerKernelFactory(CalcLCPOForceKernel::Name(), factory);
registerKernelFactory(IntegrateVerletStepKernel::Name(), factory);
registerKernelFactory(IntegrateNoseHooverStepKernel::Name(), factory);
registerKernelFactory(IntegrateLangevinMiddleStepKernel::Name(), factory);
......
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit. *
* See https://openmm.org/development. *
* *
* Portions copyright (c) 2025 Stanford University and the Authors. *
* Authors: Peter Eastman, Evan Pretti *
* 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 "TestLCPOForce.h"
void runPlatformTests() {
}
......@@ -133,6 +133,8 @@ KernelImpl* OpenCLKernelFactory::createKernelImpl(std::string name, const Platfo
return new CommonCalcCustomManyParticleForceKernel(name, platform, cl, context.getSystem());
if (name == CalcGayBerneForceKernel::Name())
return new CommonCalcGayBerneForceKernel(name, platform, cl);
if (name == CalcLCPOForceKernel::Name())
return new CommonCalcLCPOForceKernel(name, platform, cl);
if (name == IntegrateVerletStepKernel::Name())
return new CommonIntegrateVerletStepKernel(name, platform, cl);
if (name == IntegrateLangevinMiddleStepKernel::Name())
......
......@@ -90,6 +90,7 @@ OpenCLPlatform::OpenCLPlatform() {
registerKernelFactory(CalcRMSDForceKernel::Name(), factory);
registerKernelFactory(CalcCustomManyParticleForceKernel::Name(), factory);
registerKernelFactory(CalcGayBerneForceKernel::Name(), factory);
registerKernelFactory(CalcLCPOForceKernel::Name(), factory);
registerKernelFactory(IntegrateVerletStepKernel::Name(), factory);
registerKernelFactory(IntegrateNoseHooverStepKernel::Name(), factory);
registerKernelFactory(IntegrateLangevinMiddleStepKernel::Name(), factory);
......
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit. *
* See https://openmm.org/development. *
* *
* Portions copyright (c) 2025 Stanford University and the Authors. *
* Authors: Peter Eastman, Evan Pretti *
* 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 "TestLCPOForce.h"
void runPlatformTests() {
}
......@@ -1142,6 +1142,45 @@ private:
ReferenceGayBerneForce* ixn;
};
/**
* This kernel is invoked by LCPOForce to calculate the forces acting on the system and the energy of the system.
*/
class ReferenceCalcLCPOForceKernel : public CalcLCPOForceKernel {
public:
ReferenceCalcLCPOForceKernel(std::string name, const Platform& platform) : CalcLCPOForceKernel(name, platform) {
}
/**
* Initialize the kernel.
*
* @param system the System this kernel will be applied to
* @param force the LCPOForce this kernel will be used for
*/
void initialize(const System& system, const LCPOForce& 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);
/**
* Copy changed parameters over to a context.
*
* @param context the context to copy parameters to
* @param force the LCPOForce to copy the parameters from
*/
void copyParametersToContext(ContextImpl& context, const LCPOForce& force);
private:
double oneBodyEnergy;
std::vector<int> activeParticles;
std::vector<int> activeParticlesInv;
std::vector<std::array<double, 4> > parameters;
double cutoff;
bool usePeriodic;
};
/**
* This kernel is invoked by CustomCVForce to calculate the forces acting on the system and the energy of the system.
*/
......
#ifndef OPENMM_REFERENCELCPOIXN_H_
#define OPENMM_REFERENCELCPOIXN_H_
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit. *
* See https://openmm.org/development. *
* *
* Portions copyright (c) 2025 Stanford University and the Authors. *
* Authors: Evan Pretti *
* 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 <array>
#include <vector>
#include "openmm/Vec3.h"
namespace OpenMM {
/**
* Performs energy and force calculations for the reference LCPOForce kernel.
*/
class ReferenceLCPOIxn {
private:
struct NeighborInfo {
double Aij;
Vec3 dAij;
};
public:
ReferenceLCPOIxn(const std::vector<int>& activeParticles, const std::vector<int>& activeParticlesInv, const std::vector<std::array<double, 4> >& parameters, double cutoff, bool usePeriodic);
double execute(const Vec3* boxVectors, const std::vector<Vec3>& posData, std::vector<Vec3>& forceData, bool includeForces, bool includeEnergy);
private:
static const int RadiusIndex = 0;
static const int P2Index = 1;
static const int P3Index = 2;
static const int P4Index = 3;
int numParticles;
int numActiveParticles;
const std::vector<int>& activeParticles;
const std::vector<int>& activeParticlesInv;
const std::vector<std::array<double, 4> >& parameters;
double cutoff;
bool usePeriodic;
};
} // namespace OpenMM
#endif // OPENMM_REFERENCELCPOIXN_H_
......@@ -96,6 +96,8 @@ KernelImpl* ReferenceKernelFactory::createKernelImpl(std::string name, const Pla
return new ReferenceCalcCustomManyParticleForceKernel(name, platform);
if (name == CalcGayBerneForceKernel::Name())
return new ReferenceCalcGayBerneForceKernel(name, platform);
if (name == CalcLCPOForceKernel::Name())
return new ReferenceCalcLCPOForceKernel(name, platform);
if (name == IntegrateVerletStepKernel::Name())
return new ReferenceIntegrateVerletStepKernel(name, platform, data);
if (name == IntegrateNoseHooverStepKernel::Name())
......
......@@ -53,6 +53,7 @@
#include "ReferenceGayBerneForce.h"
#include "ReferenceHarmonicBondIxn.h"
#include "ReferenceLangevinMiddleDynamics.h"
#include "ReferenceLCPOIxn.h"
#include "ReferenceLJCoulomb14.h"
#include "ReferenceLJCoulombIxn.h"
#include "ReferenceMonteCarloBarostat.h"
......@@ -2438,6 +2439,60 @@ void ReferenceCalcGayBerneForceKernel::copyParametersToContext(ContextImpl& cont
ixn = new ReferenceGayBerneForce(force);
}
void ReferenceCalcLCPOForceKernel::initialize(const System& system, const LCPOForce& force) {
oneBodyEnergy = 0.0;
double maxRadius = 0.0;
double surfaceTension = force.getSurfaceTension();
for (int i = 0; i < force.getNumParticles(); i++) {
double radius, p1, p2, p3, p4;
force.getParticleParameters(i, radius, p1, p2, p3, p4);
p1 *= surfaceTension;
p2 *= surfaceTension;
p3 *= surfaceTension;
p4 *= surfaceTension;
oneBodyEnergy += 4.0 * PI_M * p1 * radius * radius;
if (radius != 0.0) {
activeParticlesInv.push_back(activeParticles.size());
activeParticles.push_back(i);
parameters.push_back({radius, p2, p3, p4});
maxRadius = max(maxRadius, radius);
}
else {
activeParticlesInv.push_back(-1);
}
}
cutoff = 2.0 * maxRadius;
usePeriodic = force.usesPeriodicBoundaryConditions();
}
double ReferenceCalcLCPOForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
Vec3* boxVectors = extractBoxVectors(context);
vector<Vec3>& posData = extractPositions(context);
vector<Vec3>& forceData = extractForces(context);
if (usePeriodic) {
double minAllowedSize = 1.999999 * cutoff;
if (boxVectors[0][0] < minAllowedSize || boxVectors[1][1] < minAllowedSize || boxVectors[2][2] < minAllowedSize) {
throw OpenMMException("The periodic box size is less than twice the required cutoff for LCPO.");
}
}
ReferenceLCPOIxn lcpo(activeParticles, activeParticlesInv, parameters, cutoff, usePeriodic);
return oneBodyEnergy + lcpo.execute(boxVectors, posData, forceData, includeForces, includeEnergy);
}
void ReferenceCalcLCPOForceKernel::copyParametersToContext(ContextImpl& context, const LCPOForce& force) {
// For the reference implementation, just reinitialize everything.
activeParticles.clear();
activeParticlesInv.clear();
parameters.clear();
initialize(context.getSystem(), force);
}
ReferenceCalcCustomCVForceKernel::~ReferenceCalcCustomCVForceKernel() {
if (ixn != NULL)
delete ixn;
......
......@@ -70,6 +70,7 @@ ReferencePlatform::ReferencePlatform() {
registerKernelFactory(CalcRMSDForceKernel::Name(), factory);
registerKernelFactory(CalcCustomManyParticleForceKernel::Name(), factory);
registerKernelFactory(CalcGayBerneForceKernel::Name(), factory);
registerKernelFactory(CalcLCPOForceKernel::Name(), factory);
registerKernelFactory(IntegrateVerletStepKernel::Name(), factory);
registerKernelFactory(IntegrateNoseHooverStepKernel::Name(), factory);
registerKernelFactory(IntegrateLangevinMiddleStepKernel::Name(), factory);
......
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit. *
* See https://openmm.org/development. *
* *
* Portions copyright (c) 2025 Stanford University and the Authors. *
* Authors: Evan Pretti *
* 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 "ReferenceForce.h"
#include "ReferenceLCPOIxn.h"
#include "ReferenceNeighborList.h"
#include "SimTKOpenMMRealType.h"
using namespace OpenMM;
using namespace std;
ReferenceLCPOIxn::ReferenceLCPOIxn(const vector<int>& activeParticles, const vector<int>& activeParticlesInv, const vector<array<double, 4> >& parameters, double cutoff, bool usePeriodic) :
activeParticles(activeParticles), activeParticlesInv(activeParticlesInv), parameters(parameters), cutoff(cutoff), usePeriodic(usePeriodic) {
numParticles = activeParticlesInv.size();
numActiveParticles = activeParticles.size();
}
double ReferenceLCPOIxn::execute(const Vec3* boxVectors, const std::vector<Vec3>& posData, std::vector<Vec3>& forceData, bool includeForces, bool includeEnergy) {
if (!numActiveParticles) {
return 0.0;
}
// We want a neighbor list in a form allowing us to query neighbors of each
// particle. Here, we use a NeighborList and then process its output:
// inefficient, but simple, so suitable for this reference implementation.
NeighborList neighborList;
computeNeighborListVoxelHash(neighborList, numParticles, posData, vector<set<int> >(numParticles), boxVectors, usePeriodic, cutoff, 0.0, false);
vector<map<int, NeighborInfo> > neighbors(numActiveParticles);
for (auto atomPair : neighborList) {
// Only include particles participating in the LCPO interaction.
int i = activeParticlesInv[atomPair.first];
int j = activeParticlesInv[atomPair.second];
if (i == -1 || j == -1) {
continue;
}
double iRadius = parameters[i][RadiusIndex];
double jRadius = parameters[j][RadiusIndex];
// Only include particles close enough to each other.
double deltaR[ReferenceForce::LastDeltaRIndex];
if (usePeriodic) {
ReferenceForce::getDeltaRPeriodic(posData[atomPair.first], posData[atomPair.second], boxVectors, deltaR);
}
else {
ReferenceForce::getDeltaR(posData[atomPair.first], posData[atomPair.second], deltaR);
}
double r = deltaR[ReferenceForce::RIndex];
if (r >= iRadius + jRadius) {
continue;
}
double rRecip = 1.0 / r;
// Precompute and store the buried areas and their derivatives.
double iRadiusPi = PI_M * iRadius;
double jRadiusPi = PI_M * jRadius;
double deltaRadiusR = (iRadius * iRadius - jRadius * jRadius) * rRecip;
double deltaRadiusRSq = deltaRadiusR * rRecip;
Vec3 direction = Vec3(deltaR[ReferenceForce::XIndex], deltaR[ReferenceForce::YIndex], deltaR[ReferenceForce::ZIndex]) * rRecip;
neighbors[i][j] = {iRadiusPi * (2.0 * iRadius - r - deltaRadiusR), iRadiusPi * (deltaRadiusRSq - 1.0) * direction};
neighbors[j][i] = {jRadiusPi * (2.0 * jRadius - r + deltaRadiusR), jRadiusPi * (deltaRadiusRSq + 1.0) * direction};
}
double energy = 0.0;
// Compute LCPO two- and three-body energy and forces.
for (int i = 0; i < numActiveParticles; i++) {
double p2 = parameters[i][P2Index];
double p3 = parameters[i][P3Index];
double p4 = parameters[i][P4Index];
double term2 = 0.0;
double term3 = 0.0;
double term4 = 0.0;
Vec3 iForce;
for (auto jNeighbor : neighbors[i]) {
int j = jNeighbor.first;
double Aij = jNeighbor.second.Aij;
Vec3 dAij = jNeighbor.second.dAij;
Vec3 jForce;
// Two-body term.
term2 += Aij;
if (includeForces) {
Vec3 ijForce2Body = p2 * dAij;
iForce += ijForce2Body;
jForce -= ijForce2Body;
}
// Three-body term: includes all pairs (j, k) of neighbors of i that
// are also neighbors of each other.
for (auto kNeighbor : neighbors[j]) {
int k = kNeighbor.first;
double Ajk = kNeighbor.second.Aij;
Vec3 dAjk = kNeighbor.second.dAij;
if (neighbors[i].find(k) == neighbors[i].end()) {
continue;
}
term3 += Ajk;
term4 += Aij * Ajk;
if (includeForces) {
Vec3 jkForce3Body = (p3 + p4 * Aij) * dAjk;
Vec3 ijForce3Body = p4 * dAij * Ajk;
iForce += ijForce3Body;
jForce += jkForce3Body - ijForce3Body;
forceData[activeParticles[k]] -= jkForce3Body;
}
}
if (includeForces) {
forceData[activeParticles[j]] += jForce;
}
}
energy += p2 * term2 + p3 * term3 + p4 * term4;
if (includeForces) {
forceData[activeParticles[i]] += iForce;
}
}
return energy;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit. *
* See https://openmm.org/development. *
* *
* Portions copyright (c) 2025 Stanford University and the Authors. *
* Authors: Peter Eastman, Evan Pretti *
* 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 "ReferenceTests.h"
#include "TestLCPOForce.h"
void runPlatformTests() {
}
\ No newline at end of file
#ifndef OPENMM_LCPOFORCE_PROXY_H_
#define OPENMM_LCPOFORCE_PROXY_H_
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit. *
* See https://openmm.org/development. *
* *
* Portions copyright (c) 2025 Stanford University and the Authors. *
* Authors: Peter Eastman, Evan Pretti *
* 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/internal/windowsExport.h"
#include "openmm/serialization/SerializationProxy.h"
namespace OpenMM {
/**
* This is a proxy for serializing LCPOForce objects.
*/
class OPENMM_EXPORT LCPOForceProxy : public SerializationProxy {
public:
LCPOForceProxy();
void serialize(const void* object, SerializationNode& node) const;
void* deserialize(const SerializationNode& node) const;
};
} // namespace OpenMM
#endif /*OPENMM_LCPOFORCE_PROXY_H_*/
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