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

Merge fixes for 8.5.1 (#5253)



* Fix leaked variable causing spurious template constraint assignment (#5236)

* fix 5234 and add test

* clean up docstring and standardize test name

* Take line search energy difference on CPU before reducing precision (#5242)

* Avoid multiple forces running on the worker thread at once (#5243)

* Fixed pressure calculation in MOnteCarloFlexibleBarostat (#5251)

---------
Co-authored-by: default avatarJeff Wagner <jwagnerjpl@gmail.com>
Co-authored-by: default avatarEvan Pretti <pretti@stanford.edu>
parent b55e6088
...@@ -1994,10 +1994,10 @@ public: ...@@ -1994,10 +1994,10 @@ public:
/** /**
* Initialize the kernel. * Initialize the kernel.
* *
* @param system the System this kernel will be applied to * @param context the ContextImpl this kernel will be applied to
* @param force the CustomCPPForceImpl this kernel will be used for * @param force the CustomCPPForceImpl this kernel will be used for
*/ */
virtual void initialize(const System& system, CustomCPPForceImpl& force) = 0; virtual void initialize(const ContextImpl& context, CustomCPPForceImpl& force) = 0;
/** /**
* Execute the kernel to calculate the forces and/or energy. * Execute the kernel to calculate the forces and/or energy.
* *
...@@ -2022,10 +2022,10 @@ public: ...@@ -2022,10 +2022,10 @@ public:
/** /**
* Initialize the kernel. * Initialize the kernel.
* *
* @param system the System this kernel will be applied to * @param context the ContextImpl this kernel will be applied to
* @param force the PythonForce this kernel will be used for * @param force the PythonForce this kernel will be used for
*/ */
virtual void initialize(const System& system, const PythonForce& force) = 0; virtual void initialize(const ContextImpl& context, const PythonForce& force) = 0;
/** /**
* Execute the kernel to calculate the forces and/or energy. * Execute the kernel to calculate the forces and/or energy.
* *
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* This is part of the OpenMM molecular simulation toolkit. * * This is part of the OpenMM molecular simulation toolkit. *
* See https://openmm.org/development. * * See https://openmm.org/development. *
* * * *
* Portions copyright (c) 2008-2021 Stanford University and the Authors. * * Portions copyright (c) 2008-2026 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -40,7 +40,7 @@ CustomCPPForceImpl::CustomCPPForceImpl(const Force& owner) { ...@@ -40,7 +40,7 @@ CustomCPPForceImpl::CustomCPPForceImpl(const Force& owner) {
void CustomCPPForceImpl::initialize(ContextImpl& context) { void CustomCPPForceImpl::initialize(ContextImpl& context) {
kernel = context.getPlatform().createKernel(CalcCustomCPPForceKernel::Name(), context); kernel = context.getPlatform().createKernel(CalcCustomCPPForceKernel::Name(), context);
kernel.getAs<CalcCustomCPPForceKernel>().initialize(context.getSystem(), *this); kernel.getAs<CalcCustomCPPForceKernel>().initialize(context, *this);
} }
double CustomCPPForceImpl::calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups) { double CustomCPPForceImpl::calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups) {
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* This is part of the OpenMM molecular simulation toolkit. * * This is part of the OpenMM molecular simulation toolkit. *
* See https://openmm.org/development. * * See https://openmm.org/development. *
* * * *
* Portions copyright (c) 2010-2025 Stanford University and the Authors. * * Portions copyright (c) 2010-2026 Stanford University and the Authors. *
* Authors: Peter Eastman, Sander Vandenhaute * * Authors: Peter Eastman, Sander Vandenhaute *
* Contributors: * * Contributors: *
* * * *
...@@ -159,7 +159,7 @@ void MonteCarloFlexibleBarostatImpl::computeCurrentPressure(ContextImpl& context ...@@ -159,7 +159,7 @@ void MonteCarloFlexibleBarostatImpl::computeCurrentPressure(ContextImpl& context
// Compute each component of the pressure tensor. // Compute each component of the pressure tensor.
for (int component = 0; component < 6; component++) for (int component = 0; component < 6; component++)
pressure[component] = (2.0*ke[component] - computePressureComponent(context, delta, component))/(volume*AVOGADRO*1e-25); pressure[component] = (2.0*ke[component]/volume - computePressureComponent(context, delta, component))/(AVOGADRO*1e-25);
// Restore the context to its original state. // Restore the context to its original state.
...@@ -223,7 +223,7 @@ double MonteCarloFlexibleBarostatImpl::computePressureComponent(ContextImpl& con ...@@ -223,7 +223,7 @@ double MonteCarloFlexibleBarostatImpl::computePressureComponent(ContextImpl& con
// Compute the potential energy contribution to this element of the pressure tensor. // Compute the potential energy contribution to this element of the pressure tensor.
double volume = box[0][0]*box[1][1]*box[2][2]; double volume = box[0][0]*box[1][1]*box[2][2];
return (energy2-energy1)/(volume*2*delta); return (energy1-energy2)/(volume*2*delta);
} }
void MonteCarloFlexibleBarostatImpl::setBoxVectors(ContextImpl& context, Vec3 a, Vec3 b, Vec3 c) { void MonteCarloFlexibleBarostatImpl::setBoxVectors(ContextImpl& context, Vec3 a, Vec3 b, Vec3 c) {
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* This is part of the OpenMM molecular simulation toolkit. * * This is part of the OpenMM molecular simulation toolkit. *
* See https://openmm.org/development. * * See https://openmm.org/development. *
* * * *
* Portions copyright (c) 2025 Stanford University and the Authors. * * Portions copyright (c) 2025-2026 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -47,7 +47,7 @@ PythonForceImpl::~PythonForceImpl() { ...@@ -47,7 +47,7 @@ PythonForceImpl::~PythonForceImpl() {
void PythonForceImpl::initialize(ContextImpl& context) { void PythonForceImpl::initialize(ContextImpl& context) {
kernel = context.getPlatform().createKernel(CalcPythonForceKernel::Name(), context); kernel = context.getPlatform().createKernel(CalcPythonForceKernel::Name(), context);
kernel.getAs<CalcPythonForceKernel>().initialize(context.getSystem(), owner); kernel.getAs<CalcPythonForceKernel>().initialize(context, owner);
} }
double PythonForceImpl::calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups) { double PythonForceImpl::calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups) {
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* This is part of the OpenMM molecular simulation toolkit. * * This is part of the OpenMM molecular simulation toolkit. *
* See https://openmm.org/development. * * See https://openmm.org/development. *
* * * *
* Portions copyright (c) 2008-2025 Stanford University and the Authors. * * Portions copyright (c) 2008-2026 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -1469,10 +1469,10 @@ public: ...@@ -1469,10 +1469,10 @@ public:
/** /**
* Initialize the kernel. * Initialize the kernel.
* *
* @param system the System this kernel will be applied to * @param context the ContextImpl this kernel will be applied to
* @param force the CustomCPPForceImpl this kernel will be used for * @param force the CustomCPPForceImpl this kernel will be used for
*/ */
void initialize(const System& system, CustomCPPForceImpl& force); void initialize(const ContextImpl& context, CustomCPPForceImpl& force);
/** /**
* Execute the kernel to calculate the forces and/or energy. * Execute the kernel to calculate the forces and/or energy.
* *
...@@ -1507,6 +1507,7 @@ private: ...@@ -1507,6 +1507,7 @@ private:
std::vector<float> floatForces; std::vector<float> floatForces;
int forceGroupFlag; int forceGroupFlag;
double energy; double energy;
bool useWorkerThread;
}; };
/** /**
...@@ -1520,10 +1521,10 @@ public: ...@@ -1520,10 +1521,10 @@ public:
/** /**
* Initialize the kernel. * Initialize the kernel.
* *
* @param system the System this kernel will be applied to * @param context the ContextImpl this kernel will be applied to
* @param force the PythonForce this kernel will be used for * @param force the PythonForce this kernel will be used for
*/ */
void initialize(const System& system, const PythonForce& force); void initialize(const ContextImpl& context, const PythonForce& force);
/** /**
* Execute the kernel to calculate the forces and/or energy. * Execute the kernel to calculate the forces and/or energy.
* *
...@@ -1558,7 +1559,7 @@ private: ...@@ -1558,7 +1559,7 @@ private:
std::vector<double> forcesVec; std::vector<double> forcesVec;
int forceGroupFlag; int forceGroupFlag;
double energy; double energy;
bool usePeriodic; bool usePeriodic, useWorkerThread;
}; };
} // namespace OpenMM } // namespace OpenMM
......
...@@ -98,7 +98,7 @@ private: ...@@ -98,7 +98,7 @@ private:
int maxIterations; int maxIterations;
MinimizationReporter* reporter; MinimizationReporter* reporter;
double kRestraint, energy; double kRestraint, energy, energyStart;
bool largeGrad; bool largeGrad;
ComputeArray constraintIndices, constraintDistances; ComputeArray constraintIndices, constraintDistances;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* This is part of the OpenMM molecular simulation toolkit. * * This is part of the OpenMM molecular simulation toolkit. *
* See https://openmm.org/development. * * See https://openmm.org/development. *
* * * *
* Portions copyright (c) 2008-2025 Stanford University and the Authors. * * Portions copyright (c) 2008-2026 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "openmm/internal/CustomCompoundBondForceImpl.h" #include "openmm/internal/CustomCompoundBondForceImpl.h"
#include "openmm/internal/DPDIntegratorUtilities.h" #include "openmm/internal/DPDIntegratorUtilities.h"
#include "openmm/internal/OSRngSeed.h" #include "openmm/internal/OSRngSeed.h"
#include "openmm/internal/PythonForceImpl.h"
#include "openmm/internal/ThreadPool.h" #include "openmm/internal/ThreadPool.h"
#include "openmm/internal/timer.h" #include "openmm/internal/timer.h"
#include "CommonKernelSources.h" #include "CommonKernelSources.h"
...@@ -4688,10 +4689,10 @@ public: ...@@ -4688,10 +4689,10 @@ public:
CommonCalcCustomCPPForceKernel& owner; CommonCalcCustomCPPForceKernel& owner;
}; };
void CommonCalcCustomCPPForceKernel::initialize(const System& system, CustomCPPForceImpl& force) { void CommonCalcCustomCPPForceKernel::initialize(const ContextImpl& context, CustomCPPForceImpl& force) {
ContextSelector selector(cc); ContextSelector selector(cc);
this->force = &force; this->force = &force;
int numParticles = system.getNumParticles(); int numParticles = context.getSystem().getNumParticles();
forcesVec.resize(numParticles); forcesVec.resize(numParticles);
positionsVec.resize(numParticles); positionsVec.resize(numParticles);
floatForces.resize(3*numParticles); floatForces.resize(3*numParticles);
...@@ -4706,14 +4707,18 @@ void CommonCalcCustomCPPForceKernel::initialize(const System& system, CustomCPPF ...@@ -4706,14 +4707,18 @@ void CommonCalcCustomCPPForceKernel::initialize(const System& system, CustomCPPF
addForcesKernel->addArg(cc.getLongForceBuffer()); addForcesKernel->addArg(cc.getLongForceBuffer());
addForcesKernel->addArg(cc.getAtomIndexArray()); addForcesKernel->addArg(cc.getAtomIndexArray());
forceGroupFlag = (1<<force.getOwner().getForceGroup()); forceGroupFlag = (1<<force.getOwner().getForceGroup());
if (cc.getNumContexts() == 1) { useWorkerThread = (cc.getNumContexts() == 1);
for (const ForceImpl* impl : context.getForceImpls())
if (dynamic_cast<const CustomCPPForceImpl*>(impl) != NULL || dynamic_cast<const PythonForceImpl*>(impl) != NULL)
useWorkerThread = false;
if (useWorkerThread) {
cc.addPreComputation(new StartCalculationPreComputation(*this)); cc.addPreComputation(new StartCalculationPreComputation(*this));
cc.addPostComputation(new AddForcesPostComputation(*this)); cc.addPostComputation(new AddForcesPostComputation(*this));
} }
} }
double CommonCalcCustomCPPForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { double CommonCalcCustomCPPForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
if (cc.getNumContexts() == 1) { if (useWorkerThread) {
// This method does nothing. The actual calculation is started by the pre-computation, continued on // This method does nothing. The actual calculation is started by the pre-computation, continued on
// the worker thread, and finished by the post-computation. // the worker thread, and finished by the post-computation.
...@@ -4765,7 +4770,7 @@ double CommonCalcCustomCPPForceKernel::addForces(bool includeForces, bool includ ...@@ -4765,7 +4770,7 @@ double CommonCalcCustomCPPForceKernel::addForces(bool includeForces, bool includ
// Wait until executeOnWorkerThread() is finished. // Wait until executeOnWorkerThread() is finished.
if (cc.getNumContexts() == 1) if (useWorkerThread)
cc.getWorkThread().flush(); cc.getWorkThread().flush();
// Add in the forces. // Add in the forces.
...@@ -4811,11 +4816,11 @@ public: ...@@ -4811,11 +4816,11 @@ public:
CommonCalcPythonForceKernel& owner; CommonCalcPythonForceKernel& owner;
}; };
void CommonCalcPythonForceKernel::initialize(const System& system, const PythonForce& force) { void CommonCalcPythonForceKernel::initialize(const ContextImpl& context, const PythonForce& force) {
ContextSelector selector(cc); ContextSelector selector(cc);
computation = &force.getComputation(); computation = &force.getComputation();
usePeriodic = force.usesPeriodicBoundaryConditions(); usePeriodic = force.usesPeriodicBoundaryConditions();
int numParticles = system.getNumParticles(); int numParticles = context.getSystem().getNumParticles();
positionsVec.resize(numParticles); positionsVec.resize(numParticles);
forcesVec.resize(3*numParticles); forcesVec.resize(3*numParticles);
int elementSize = (cc.getUseDoublePrecision() ? sizeof(double) : sizeof(float)); int elementSize = (cc.getUseDoublePrecision() ? sizeof(double) : sizeof(float));
...@@ -4829,14 +4834,18 @@ void CommonCalcPythonForceKernel::initialize(const System& system, const PythonF ...@@ -4829,14 +4834,18 @@ void CommonCalcPythonForceKernel::initialize(const System& system, const PythonF
addForcesKernel->addArg(cc.getLongForceBuffer()); addForcesKernel->addArg(cc.getLongForceBuffer());
addForcesKernel->addArg(cc.getAtomIndexArray()); addForcesKernel->addArg(cc.getAtomIndexArray());
forceGroupFlag = (1<<force.getForceGroup()); forceGroupFlag = (1<<force.getForceGroup());
if (cc.getNumContexts() == 1) { useWorkerThread = (cc.getNumContexts() == 1);
for (const ForceImpl* impl : context.getForceImpls())
if (dynamic_cast<const CustomCPPForceImpl*>(impl) != NULL || dynamic_cast<const PythonForceImpl*>(impl) != NULL)
useWorkerThread = false;
if (useWorkerThread) {
cc.addPreComputation(new StartCalculationPreComputation(*this)); cc.addPreComputation(new StartCalculationPreComputation(*this));
cc.addPostComputation(new AddForcesPostComputation(*this)); cc.addPostComputation(new AddForcesPostComputation(*this));
} }
} }
double CommonCalcPythonForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { double CommonCalcPythonForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
if (cc.getNumContexts() == 1) { if (useWorkerThread) {
// This method does nothing. The actual calculation is started by the pre-computation, continued on // This method does nothing. The actual calculation is started by the pre-computation, continued on
// the worker thread, and finished by the post-computation. // the worker thread, and finished by the post-computation.
...@@ -4887,7 +4896,7 @@ double CommonCalcPythonForceKernel::addForces(bool includeForces, bool includeEn ...@@ -4887,7 +4896,7 @@ double CommonCalcPythonForceKernel::addForces(bool includeForces, bool includeEn
// Wait until executeOnWorkerThread() is finished. // Wait until executeOnWorkerThread() is finished.
if (cc.getNumContexts() == 1) if (useWorkerThread)
cc.getWorkThread().flush(); cc.getWorkThread().flush();
// Add in the forces. // Add in the forces.
......
...@@ -173,8 +173,8 @@ void CommonMinimizeKernel::setup(ContextImpl& context) { ...@@ -173,8 +173,8 @@ void CommonMinimizeKernel::setup(ContextImpl& context) {
returnFlag.initialize<int>(cc, 1, "returnFlag"); returnFlag.initialize<int>(cc, 1, "returnFlag");
returnValue.initialize(cc, 1, elementSize, "returnValue"); returnValue.initialize(cc, 1, elementSize, "returnValue");
gradNorm.initialize(cc, 1, elementSize, "gradNorm"); gradNorm.initialize(cc, 1, elementSize, "gradNorm");
lineSearchData.initialize(cc, 4, elementSize, "lineSearchData"); lineSearchData.initialize(cc, 3, elementSize, "lineSearchData");
lineSearchDataBackup.initialize(cc, 4, elementSize, "lineSearchDataBackup"); lineSearchDataBackup.initialize(cc, 3, elementSize, "lineSearchDataBackup");
// Compile kernels and set arguments. // Compile kernels and set arguments.
...@@ -341,7 +341,6 @@ void CommonMinimizeKernel::setup(ContextImpl& context) { ...@@ -341,7 +341,6 @@ void CommonMinimizeKernel::setup(ContextImpl& context) {
lineSearchSetupKernel->addArg(gradNorm); lineSearchSetupKernel->addArg(gradNorm);
lineSearchSetupKernel->addArg(lineSearchData); lineSearchSetupKernel->addArg(lineSearchData);
lineSearchSetupKernel->addArg(numVariables); lineSearchSetupKernel->addArg(numVariables);
lineSearchSetupKernel->addArg(); // energyStart
lineSearchStepKernel = program->createKernel("lineSearchStep"); lineSearchStepKernel = program->createKernel("lineSearchStep");
lineSearchStepKernel->addArg(x); lineSearchStepKernel->addArg(x);
...@@ -405,12 +404,7 @@ void CommonMinimizeKernel::lbfgs(ContextImpl& context) { ...@@ -405,12 +404,7 @@ void CommonMinimizeKernel::lbfgs(ContextImpl& context) {
for (int iteration = 1, end = 0;;) { for (int iteration = 1, end = 0;;) {
// Prepare for a line search. // Prepare for a line search.
if (mixedIsDouble) { energyStart = energy;
lineSearchSetupKernel->setArg(9, energy);
}
else {
lineSearchSetupKernel->setArg(9, (float) energy);
}
lineSearchSetupKernel->execute(numVariables); lineSearchSetupKernel->execute(numVariables);
// Take line search steps. // Take line search steps.
...@@ -746,11 +740,10 @@ double CommonMinimizeKernel::downloadGradNormSync() { ...@@ -746,11 +740,10 @@ double CommonMinimizeKernel::downloadGradNormSync() {
void CommonMinimizeKernel::runLineSearchKernels() { void CommonMinimizeKernel::runLineSearchKernels() {
if (mixedIsDouble) { if (mixedIsDouble) {
lineSearchDotKernel->setArg(6, isfinite(energy) ? energy : (double) std::numeric_limits<float>::max()); lineSearchDotKernel->setArg(6, isfinite(energy) ? energy - energyStart : (double) std::numeric_limits<float>::max());
} }
else { else {
float hostEnergy = (float) energy; lineSearchDotKernel->setArg(6, isfinite((float) energy) ? (float) (energy - energyStart) : std::numeric_limits<float>::max());
lineSearchDotKernel->setArg(6, isfinite(hostEnergy) ? hostEnergy : std::numeric_limits<float>::max());
} }
lineSearchDotKernel->execute(numVariables); lineSearchDotKernel->execute(numVariables);
lineSearchContinueKernel->execute(1); lineSearchContinueKernel->execute(1);
......
#define LS_DOT_START 0 #define LS_DOT_START 0
#define LS_DOT 1 #define LS_DOT 1
#define LS_ENERGY 2 #define LS_STEP 2
#define LS_STEP 3
#define LS_FAIL 0 #define LS_FAIL 0
#define LS_SUCCEED 1 #define LS_SUCCEED 1
...@@ -668,8 +667,7 @@ KERNEL void lineSearchSetup( ...@@ -668,8 +667,7 @@ KERNEL void lineSearchSetup(
GLOBAL int* RESTRICT returnFlag, GLOBAL int* RESTRICT returnFlag,
GLOBAL mixed* RESTRICT gradNorm, GLOBAL mixed* RESTRICT gradNorm,
GLOBAL mixed* RESTRICT lineSearchData, GLOBAL mixed* RESTRICT lineSearchData,
const int numVariables, const int numVariables
const mixed energyStart
) { ) {
LOCAL volatile mixed temp[TEMP_SIZE]; LOCAL volatile mixed temp[TEMP_SIZE];
...@@ -694,7 +692,6 @@ KERNEL void lineSearchSetup( ...@@ -694,7 +692,6 @@ KERNEL void lineSearchSetup(
if (GLOBAL_ID == 0) { if (GLOBAL_ID == 0) {
*returnFlag = LS_CONTINUE; *returnFlag = LS_CONTINUE;
*gradNorm = 0; *gradNorm = 0;
lineSearchData[LS_ENERGY] = energyStart;
} }
} }
...@@ -758,7 +755,6 @@ KERNEL void lineSearchStep( ...@@ -758,7 +755,6 @@ KERNEL void lineSearchStep(
lineSearchDataBackup[LS_DOT_START] = lineSearchData[LS_DOT_START]; lineSearchDataBackup[LS_DOT_START] = lineSearchData[LS_DOT_START];
lineSearchDataBackup[LS_DOT] = lineSearchData[LS_DOT] = 0; lineSearchDataBackup[LS_DOT] = lineSearchData[LS_DOT] = 0;
lineSearchDataBackup[LS_ENERGY] = lineSearchData[LS_ENERGY];
lineSearchDataBackup[LS_STEP] = lineSearchData[LS_STEP]; lineSearchDataBackup[LS_STEP] = lineSearchData[LS_STEP];
} }
} }
...@@ -770,7 +766,7 @@ KERNEL void lineSearchDot( ...@@ -770,7 +766,7 @@ KERNEL void lineSearchDot(
GLOBAL int* RESTRICT returnFlag, GLOBAL int* RESTRICT returnFlag,
GLOBAL const mixed* RESTRICT returnValue, GLOBAL const mixed* RESTRICT returnValue,
const int numVariables, const int numVariables,
mixed energy mixed deltaEnergy
) { ) {
LOCAL volatile mixed temp[TEMP_SIZE]; LOCAL volatile mixed temp[TEMP_SIZE];
...@@ -781,13 +777,13 @@ KERNEL void lineSearchDot( ...@@ -781,13 +777,13 @@ KERNEL void lineSearchDot(
// Any restraint energy in returnValue hasn't been downloaded yet to be // Any restraint energy in returnValue hasn't been downloaded yet to be
// passed back up in the energy parameter, so add it in here. // passed back up in the energy parameter, so add it in here.
energy += *returnValue; deltaEnergy += *returnValue;
// The energy may be such that we don't need to do a dot product and can // The energy may be such that we don't need to do a dot product and can
// immediately decide to scale the step, so mark this case with LS_SUCCEED. // immediately decide to scale the step, so mark this case with LS_SUCCEED.
// This will be checked in the following kernel. // This will be checked in the following kernel.
if (!(FABS_MIXED(energy) < FLT_MAX) || energy > lineSearchData[LS_ENERGY] + lineSearchData[LS_STEP] * LBFGS_FTOL * lineSearchData[LS_DOT_START]) { if (!(FABS_MIXED(deltaEnergy) < FLT_MAX) || deltaEnergy > lineSearchData[LS_STEP] * LBFGS_FTOL * lineSearchData[LS_DOT_START]) {
if (GLOBAL_ID == 0) { if (GLOBAL_ID == 0) {
*returnFlag = LS_SUCCEED; *returnFlag = LS_SUCCEED;
} }
......
...@@ -1992,10 +1992,10 @@ public: ...@@ -1992,10 +1992,10 @@ public:
/** /**
* Initialize the kernel. * Initialize the kernel.
* *
* @param system the System this kernel will be applied to * @param context the ContextImpl this kernel will be applied to
* @param force the CustomCPPForceImpl this kernel will be used for * @param force the CustomCPPForceImpl this kernel will be used for
*/ */
void initialize(const System& system, CustomCPPForceImpl& force); void initialize(const ContextImpl& context, CustomCPPForceImpl& force);
/** /**
* Execute the kernel to calculate the forces and/or energy. * Execute the kernel to calculate the forces and/or energy.
* *
...@@ -2020,10 +2020,10 @@ public: ...@@ -2020,10 +2020,10 @@ public:
/** /**
* Initialize the kernel. * Initialize the kernel.
* *
* @param system the System this kernel will be applied to * @param context the ContextImpl this kernel will be applied to
* @param force the PythonForce this kernel will be used for * @param force the PythonForce this kernel will be used for
*/ */
void initialize(const System& system, const PythonForce& force); void initialize(const ContextImpl& context, const PythonForce& force);
/** /**
* Execute the kernel to calculate the forces and/or energy. * Execute the kernel to calculate the forces and/or energy.
* *
......
...@@ -3535,9 +3535,9 @@ void ReferenceCalcATMForceKernel::copyParametersToContext(ContextImpl& context, ...@@ -3535,9 +3535,9 @@ void ReferenceCalcATMForceKernel::copyParametersToContext(ContextImpl& context,
loadParams(numParticles, force); loadParams(numParticles, force);
} }
void ReferenceCalcCustomCPPForceKernel::initialize(const System& system, CustomCPPForceImpl& force) { void ReferenceCalcCustomCPPForceKernel::initialize(const ContextImpl& context, CustomCPPForceImpl& force) {
this->force = &force; this->force = &force;
forces.resize(system.getNumParticles()); forces.resize(context.getSystem().getNumParticles());
} }
double ReferenceCalcCustomCPPForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { double ReferenceCalcCustomCPPForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
...@@ -3550,9 +3550,9 @@ double ReferenceCalcCustomCPPForceKernel::execute(ContextImpl& context, bool inc ...@@ -3550,9 +3550,9 @@ double ReferenceCalcCustomCPPForceKernel::execute(ContextImpl& context, bool inc
return energy; return energy;
} }
void ReferenceCalcPythonForceKernel::initialize(const System& system, const PythonForce& force) { void ReferenceCalcPythonForceKernel::initialize(const ContextImpl& context, const PythonForce& force) {
computation = &force.getComputation(); computation = &force.getComputation();
forces.resize(system.getNumParticles()); forces.resize(context.getSystem().getNumParticles());
usePeriodic = force.usesPeriodicBoundaryConditions(); usePeriodic = force.usesPeriodicBoundaryConditions();
} }
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* This is part of the OpenMM molecular simulation toolkit. * * This is part of the OpenMM molecular simulation toolkit. *
* See https://openmm.org/development. * * See https://openmm.org/development. *
* * * *
* Portions copyright (c) 2008-2021 Stanford University and the Authors. * * Portions copyright (c) 2008-2026 Stanford University and the Authors. *
* Authors: Peter Eastman, Lee-Ping Wang * * Authors: Peter Eastman, Lee-Ping Wang *
* Contributors: * * Contributors: *
* * * *
...@@ -180,12 +180,12 @@ void testMoleculeScaling(bool rigid) { ...@@ -180,12 +180,12 @@ void testMoleculeScaling(bool rigid) {
} }
void testMolecularGas(bool rigid) { void testMolecularGas(bool rigid) {
const int numMolecules = 64; const int numMolecules = 256;
const int frequency = 5; const int frequency = 5;
const int steps = 5000; const int steps = 5000;
const double pressure = 3.0; const double pressure = 3.0;
const double pressureInMD = pressure*(AVOGADRO*1e-25); // pressure in kJ/mol/nm^3 const double pressureInMD = pressure*(AVOGADRO*1e-25); // pressure in kJ/mol/nm^3
const double temp =300.0; const double temp = 300.0;
const double initialVolume = numMolecules*BOLTZ*temp/pressureInMD; const double initialVolume = numMolecules*BOLTZ*temp/pressureInMD;
const double initialLength = std::pow(initialVolume, 1.0/3.0); const double initialLength = std::pow(initialVolume, 1.0/3.0);
...@@ -206,8 +206,8 @@ void testMolecularGas(bool rigid) { ...@@ -206,8 +206,8 @@ void testMolecularGas(bool rigid) {
system.addParticle(1.0); system.addParticle(1.0);
system.addParticle(1.0); system.addParticle(1.0);
Vec3 pos(initialLength*genrand_real2(sfmt), 0.5*initialLength*genrand_real2(sfmt), 2*initialLength*genrand_real2(sfmt)); Vec3 pos(initialLength*genrand_real2(sfmt), 0.5*initialLength*genrand_real2(sfmt), 2*initialLength*genrand_real2(sfmt));
bonds->addBond(positions.size(), positions.size()+1, 0.1, 0.0); bonds->addBond(positions.size(), positions.size()+1, 0.1, 1.0);
bonds->addBond(positions.size(), positions.size()+2, 0.1, 0.0); bonds->addBond(positions.size(), positions.size()+2, 0.1, 1.0);
positions.push_back(pos); positions.push_back(pos);
positions.push_back(pos+Vec3(0.1, 0.0, 0.0)); positions.push_back(pos+Vec3(0.1, 0.0, 0.0));
positions.push_back(pos+Vec3(0.0, 0.1, 0.0)); positions.push_back(pos+Vec3(0.0, 0.1, 0.0));
......
...@@ -1423,7 +1423,7 @@ class ForceField(object): ...@@ -1423,7 +1423,7 @@ class ForceField(object):
continue continue
t1 = data.atomTemplateIndexes[atom1] t1 = data.atomTemplateIndexes[atom1]
t2 = data.atomTemplateIndexes[atom2] t2 = data.atomTemplateIndexes[atom2]
for constraint in template.constraints: for constraint in matchedTemplateForResidue[atom1.residue].constraints:
if sorted((t1, t2)) == sorted((constraint[0], constraint[1])): if sorted((t1, t2)) == sorted((constraint[0], constraint[1])):
bond.isConstrained = True bond.isConstrained = True
......
...@@ -262,6 +262,75 @@ class TestForceField(unittest.TestCase): ...@@ -262,6 +262,75 @@ class TestForceField(unittest.TestCase):
self.assertEqual(1.0, lengths[(0, 4)]) self.assertEqual(1.0, lengths[(0, 4)])
self.assertEqual(1.0, lengths[(0, 5)]) self.assertEqual(1.0, lengths[(0, 5)])
def testTemplateConstraintsMultipleMols(self):
"""Test that constraints defined by a residue template don't leak into
other residues.
See https://github.com/openmm/openmm/issues/5234
"""
MOL_A = """<ForceField>
<AtomTypes>
<Type name="A0" mass="12" class="A0" element="C"/>
<Type name="A1" mass="12" class="A1" element="C"/>
</AtomTypes>
<HarmonicBondForce>
<Bond class1="A0" class2="A1" length="0.15" k="200000"/>
</HarmonicBondForce>
<NonbondedForce coulomb14scale="1" lj14scale="1">
<Atom class="A0" sigma="0.3" epsilon="0.1" charge="0"/>
<Atom class="A1" sigma="0.3" epsilon="0.1" charge="0"/>
</NonbondedForce>
<Residues>
<Residue name="MOLA">
<Atom name="a0" type="A0"/><Atom name="a1" type="A1"/>
<Bond atomName1="a0" atomName2="a1"/>
</Residue>
</Residues>
</ForceField>"""
MOL_B = """<ForceField>
<AtomTypes>
<Type name="B0" mass="12" class="B0" element="C"/>
<Type name="B1" mass="1" class="B1" element="H"/>
</AtomTypes>
<HarmonicBondForce>
<Bond class1="B0" class2="B1" length="0.11" k="300000"/>
</HarmonicBondForce>
<NonbondedForce coulomb14scale="1" lj14scale="1">
<Atom class="B0" sigma="0.3" epsilon="0.1" charge="0"/>
<Atom class="B1" sigma="0.1" epsilon="0.01" charge="0"/>
</NonbondedForce>
<Residues>
<Residue name="MOLB">
<Atom name="b0" type="B0"/><Atom name="b1" type="B1"/>
<Bond atomName1="b0" atomName2="b1"/>
<Constraint atomName1="b0" atomName2="b1" distance="0.11"/>
</Residue>
</Residues>
</ForceField>"""
top = Topology()
c = top.addChain()
C, H = Element.getBySymbol('C'), Element.getBySymbol('H')
r1 = top.addResidue('MOLA', c)
a0, a1 = top.addAtom('a0', C, r1), top.addAtom('a1', C, r1)
top.addBond(a0, a1)
r2 = top.addResidue('MOLB', c)
b0, b1 = top.addAtom('b0', C, r2), top.addAtom('b1', H, r2)
top.addBond(b0, b1)
ff = ForceField()
ff.loadFile(StringIO(MOL_A))
ff.loadFile(StringIO(MOL_B))
sys = ff.createSystem(top,
nonbondedMethod=NoCutoff,
constraints=None)
self.assertEqual(sys.getNumConstraints(), 1)
constraintParameters = sys.getConstraintParameters(0)
self.assertEqual(constraintParameters[0], 2)
self.assertEqual(constraintParameters[1], 3)
self.assertEqual(constraintParameters[2], 0.11 * nanometer)
def test_ImplicitSolvent(self): def test_ImplicitSolvent(self):
"""Test the four types of implicit solvents using the implicitSolvent """Test the four types of implicit solvents using the implicitSolvent
parameter. parameter.
......
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