Unverified Commit d8c67699 authored by Emilio Gallicchio's avatar Emilio Gallicchio Committed by GitHub
Browse files

Draft integration of the Alchemical Transfer Method (ATM) plugin (#4110)



* Draft integration of the Alchemical Transfer Method (ATM) plugin

* Attempt to store and retrieve forces--does not compile

* Implement addForce()/getForce() methods

* Throw exception when specifying properties without a Platform (#4130)

* Fixed DOF calculation for NoseHooverIntegrator (#4128)

* Fix variance in documentation of VerletIntegrator (#4138)

* Python API for ATMForce

* Fixed compilation error

* Minor cleanup of formatting and documentation

* Files for ATMForce test cases

* More cleanup

* Removed variable groups

* Test ATMForce with two particles

* More tests for ATMForce plus fixes

* Added missing header

* Rework interface to pass displacements as vector of parameters

* Revert "Rework interface to pass displacements as vector of parameters"

This reverts commit 5e092031f31ded1137b677588f007add1c2d6f82.

* Test with nonbonded force

* Allow energy expression to be customized

* Optional displacements at the initial state

* Fixed compilation error build C wrapper

* Address edge case of default energy expression

* Consistent naming of the variables of the displacement states

* Test of soft core function of the default energy expression

* Mark addForce() as taking ownership

* initial python test for ATMForce

* Test custom expressions

* Expanded C++ API documentation for ATMForce

* Energy parameter derivatives

* Serialization for ATMForce

* Documentation, cleanup, and fixes

* Fixed typos

* getPerturbationEnergy() computes energy

* Another test case

* Minor edits

---------
Co-authored-by: default avatarPeter Eastman <peastman@stanford.edu>
Co-authored-by: default avatarMichael Plainer <plainer@ymail.com>
parent 889baef6
/* -------------------------------------------------------------------------- *
* 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) 2023 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 "TestATMForce.h"
void runPlatformTests() {
}
...@@ -1633,6 +1633,53 @@ private: ...@@ -1633,6 +1633,53 @@ private:
int frequency; int frequency;
}; };
/**
* This kernel is invoked by ATMForce to calculate the forces acting on the system and the energy of the system.
*/
class ReferenceCalcATMForceKernel : public CalcATMForceKernel {
public:
ReferenceCalcATMForceKernel(std::string name, const Platform& platform) : CalcATMForceKernel(name, platform) {
}
/**
* Initialize the kernel.
*
* @param system the System this kernel will be applied to
* @param force the ATMForce this kernel will be used for
*/
void initialize(const System& system, const ATMForce& force);
/**
* Scale the forces from the inner contexts and apply them to the main context.
*
* @param context the context in which to execute this kernel
* @param innerContext1 the first inner context
* @param innerContext2 the second inner context
* @param dEdu0 the derivative of the final energy with respect to the first inner context's energy
* @param dEdu1 the derivative of the final energy with respect to the second inner context's energy
* @param energyParamDerivs derivatives of the final energy with respect to global parameters
*/
void applyForces(ContextImpl& context, ContextImpl& innerContext0, ContextImpl& innerContext1,
double dEdu0, double dEdu1, const std::map<std::string, double>& energyParamDerivs);
/**
* Copy changed parameters over to a context.
*
* @param context the context to copy parameters to
* @param force the ATMForce to copy the parameters from
*/
void copyParametersToContext(ContextImpl& context, const ATMForce& force);
/**
* Copy state information to the inner contexts.
*
* @param context the context in which to execute this kernel
* @param innerContext1 the first context created by the ATMForce for computing displaced energy
* @param innerContext2 the second context created by the ATMForce for computing displaced energy
*/
void copyState(ContextImpl& context, ContextImpl& innerContext0, ContextImpl& innerContext1);
private:
int numParticles;
std::vector<Vec3> displ1;
std::vector<Vec3> displ0;
};
} // namespace OpenMM } // namespace OpenMM
#endif /*OPENMM_REFERENCEKERNELS_H_*/ #endif /*OPENMM_REFERENCEKERNELS_H_*/
...@@ -80,6 +80,8 @@ KernelImpl* ReferenceKernelFactory::createKernelImpl(std::string name, const Pla ...@@ -80,6 +80,8 @@ KernelImpl* ReferenceKernelFactory::createKernelImpl(std::string name, const Pla
return new ReferenceCalcCustomCompoundBondForceKernel(name, platform); return new ReferenceCalcCustomCompoundBondForceKernel(name, platform);
if (name == CalcCustomCVForceKernel::Name()) if (name == CalcCustomCVForceKernel::Name())
return new ReferenceCalcCustomCVForceKernel(name, platform); return new ReferenceCalcCustomCVForceKernel(name, platform);
if (name == CalcATMForceKernel::Name())
return new ReferenceCalcATMForceKernel(name, platform);
if (name == CalcRMSDForceKernel::Name()) if (name == CalcRMSDForceKernel::Name())
return new ReferenceCalcRMSDForceKernel(name, platform); return new ReferenceCalcRMSDForceKernel(name, platform);
if (name == CalcCustomManyParticleForceKernel::Name()) if (name == CalcCustomManyParticleForceKernel::Name())
......
...@@ -2958,3 +2958,77 @@ void ReferenceRemoveCMMotionKernel::execute(ContextImpl& context) { ...@@ -2958,3 +2958,77 @@ void ReferenceRemoveCMMotionKernel::execute(ContextImpl& context) {
} }
} }
} }
void ReferenceCalcATMForceKernel::initialize(const System& system, const ATMForce& force) {
numParticles = force.getNumParticles();
//displacement map
displ1.resize(numParticles);
displ0.resize(numParticles);
for (int i = 0; i < numParticles; i++) {
Vec3 displacement1, displacement0;
force.getParticleParameters(i, displacement1, displacement0 );
displ1[i] = displacement1;
displ0[i] = displacement0;
}
}
void ReferenceCalcATMForceKernel::applyForces(ContextImpl& context, ContextImpl& innerContext0, ContextImpl& innerContext1,
double dEdu0, double dEdu1, const map<string, double>& energyParamDerivs) {
vector<Vec3>& force = extractForces(context);
vector<Vec3>& force0 = extractForces(innerContext0);
vector<Vec3>& force1 = extractForces(innerContext1);
for (int i = 0; i < force.size(); i++)
force[i] += dEdu0*force0[i] + dEdu1*force1[i];
map<string, double>& derivs = extractEnergyParameterDerivatives(context);
for (auto deriv : energyParamDerivs)
derivs[deriv.first] += deriv.second;
}
void ReferenceCalcATMForceKernel::copyState(ContextImpl& context, ContextImpl& innerContext0, ContextImpl& innerContext1) {
vector<Vec3>& pos = extractPositions(context);
//in the initial state, particles are displaced by displ0
vector<Vec3> pos0(pos);
for (int i = 0; i < pos0.size(); i++)
pos0[i] += displ0[i];
extractPositions(innerContext0) = pos0;
//in the target state, particles are displaced by displ1
vector<Vec3> pos1(pos);
for (int i = 0; i < pos1.size(); i++)
pos1[i] += displ1[i];
extractPositions(innerContext1) = pos1;
Vec3 a, b, c;
context.getPeriodicBoxVectors(a, b, c);
innerContext0.setPeriodicBoxVectors(a, b, c);
innerContext1.setPeriodicBoxVectors(a, b, c);
innerContext0.setTime(context.getTime());
innerContext1.setTime(context.getTime());
map<string, double> innerParameters;
innerParameters = innerContext0.getParameters();
for (auto& param : innerParameters)
innerContext0.setParameter(param.first, context.getParameter(param.first));
innerParameters = innerContext1.getParameters();
for (auto& param : innerParameters)
innerContext1.setParameter(param.first, context.getParameter(param.first));
}
void ReferenceCalcATMForceKernel::copyParametersToContext(ContextImpl& context, const ATMForce& force) {
if (force.getNumParticles() != numParticles)
throw OpenMMException("copyParametersToContext: The number of ATMForce particles has changed");
displ1.resize(numParticles);
displ0.resize(numParticles);
for (int i = 0; i < numParticles; i++) {
Vec3 displacement1, displacement0;
force.getParticleParameters(i, displacement1, displacement0 );
displ1[i] = displacement1;
displ0[i] = displacement0;
}
}
...@@ -62,6 +62,7 @@ ReferencePlatform::ReferencePlatform() { ...@@ -62,6 +62,7 @@ ReferencePlatform::ReferencePlatform() {
registerKernelFactory(CalcCustomCentroidBondForceKernel::Name(), factory); registerKernelFactory(CalcCustomCentroidBondForceKernel::Name(), factory);
registerKernelFactory(CalcCustomCompoundBondForceKernel::Name(), factory); registerKernelFactory(CalcCustomCompoundBondForceKernel::Name(), factory);
registerKernelFactory(CalcCustomCVForceKernel::Name(), factory); registerKernelFactory(CalcCustomCVForceKernel::Name(), factory);
registerKernelFactory(CalcATMForceKernel::Name(), factory);
registerKernelFactory(CalcRMSDForceKernel::Name(), factory); registerKernelFactory(CalcRMSDForceKernel::Name(), factory);
registerKernelFactory(CalcCustomManyParticleForceKernel::Name(), factory); registerKernelFactory(CalcCustomManyParticleForceKernel::Name(), factory);
registerKernelFactory(CalcGayBerneForceKernel::Name(), factory); registerKernelFactory(CalcGayBerneForceKernel::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) 2023 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 "ReferenceTests.h"
#include "TestATMForce.h"
void runPlatformTests() {
}
#ifndef OPENMM_ATMFORCE_PROXY_H_
#define OPENMM_ATMFORCE_PROXY_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) 2023 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/internal/windowsExport.h"
#include "openmm/serialization/SerializationProxy.h"
namespace OpenMM {
/**
* This is a proxy for serializing ATMForce objects.
*/
class OPENMM_EXPORT ATMForceProxy : public SerializationProxy {
public:
ATMForceProxy();
void serialize(const void* object, SerializationNode& node) const;
void* deserialize(const SerializationNode& node) const;
};
} // namespace OpenMM
#endif /*OPENMM_ATMFORCE_PROXY_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) 2010-2023 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/serialization/ATMForceProxy.h"
#include "openmm/serialization/SerializationNode.h"
#include "openmm/Force.h"
#include "openmm/ATMForce.h"
#include <sstream>
using namespace OpenMM;
using namespace std;
ATMForceProxy::ATMForceProxy() : SerializationProxy("ATMForce") {
}
void ATMForceProxy::serialize(const void* object, SerializationNode& node) const {
node.setIntProperty("version", 0);
const ATMForce& force = *reinterpret_cast<const ATMForce*> (object);
node.setIntProperty("forceGroup", force.getForceGroup());
node.setStringProperty("name", force.getName());
node.setStringProperty("energy", force.getEnergyFunction());
SerializationNode& globalParams = node.createChildNode("GlobalParameters");
for (int i = 0; i < force.getNumGlobalParameters(); i++) {
globalParams.createChildNode("Parameter").setStringProperty("name", force.getGlobalParameterName(i)).setDoubleProperty("default", force.getGlobalParameterDefaultValue(i));
}
SerializationNode& energyDerivs = node.createChildNode("EnergyParameterDerivatives");
for (int i = 0; i < force.getNumEnergyParameterDerivatives(); i++) {
energyDerivs.createChildNode("Parameter").setStringProperty("name", force.getEnergyParameterDerivativeName(i));
}
SerializationNode& forces = node.createChildNode("Forces");
for (int i = 0; i < force.getNumForces(); i++) {
SerializationNode& f = forces.createChildNode("Force");
f.createChildNode("Force", &force.getForce(i));
}
}
void* ATMForceProxy::deserialize(const SerializationNode& node) const {
int version = node.getIntProperty("version");
if (version != 0)
throw OpenMMException("Unsupported version number");
ATMForce* force = NULL;
try {
ATMForce* force = new ATMForce(node.getStringProperty("energy"));
force->setForceGroup(node.getIntProperty("forceGroup", 0));
force->setName(node.getStringProperty("name", force->getName()));
const SerializationNode& globalParams = node.getChildNode("GlobalParameters");
for (auto& parameter : globalParams.getChildren())
force->addGlobalParameter(parameter.getStringProperty("name"), parameter.getDoubleProperty("default"));
const SerializationNode& energyDerivs = node.getChildNode("EnergyParameterDerivatives");
for (auto& parameter : energyDerivs.getChildren())
force->addEnergyParameterDerivative(parameter.getStringProperty("name"));
const SerializationNode& forces = node.getChildNode("Forces");
for (auto& f : forces.getChildren())
force->addForce(f.getChildren()[0].decodeObject<Force>());
return force;
}
catch (...) {
if (force != NULL)
delete force;
throw;
}
}
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
#include "openmm/AndersenThermostat.h" #include "openmm/AndersenThermostat.h"
#include "openmm/ATMForce.h"
#include "openmm/BrownianIntegrator.h" #include "openmm/BrownianIntegrator.h"
#include "openmm/CMAPTorsionForce.h" #include "openmm/CMAPTorsionForce.h"
#include "openmm/CMMotionRemover.h" #include "openmm/CMMotionRemover.h"
...@@ -70,6 +71,7 @@ ...@@ -70,6 +71,7 @@
#include "openmm/serialization/SerializationProxy.h" #include "openmm/serialization/SerializationProxy.h"
#include "openmm/serialization/BrownianIntegratorProxy.h" #include "openmm/serialization/BrownianIntegratorProxy.h"
#include "openmm/serialization/AndersenThermostatProxy.h" #include "openmm/serialization/AndersenThermostatProxy.h"
#include "openmm/serialization/ATMForceProxy.h"
#include "openmm/serialization/CMAPTorsionForceProxy.h" #include "openmm/serialization/CMAPTorsionForceProxy.h"
#include "openmm/serialization/CMMotionRemoverProxy.h" #include "openmm/serialization/CMMotionRemoverProxy.h"
#include "openmm/serialization/CompoundIntegratorProxy.h" #include "openmm/serialization/CompoundIntegratorProxy.h"
...@@ -123,6 +125,7 @@ using namespace OpenMM; ...@@ -123,6 +125,7 @@ using namespace OpenMM;
extern "C" void registerSerializationProxies() { extern "C" void registerSerializationProxies() {
SerializationProxy::registerProxy(typeid(AndersenThermostat), new AndersenThermostatProxy()); SerializationProxy::registerProxy(typeid(AndersenThermostat), new AndersenThermostatProxy());
SerializationProxy::registerProxy(typeid(ATMForce), new ATMForceProxy());
SerializationProxy::registerProxy(typeid(BrownianIntegrator), new BrownianIntegratorProxy()); SerializationProxy::registerProxy(typeid(BrownianIntegrator), new BrownianIntegratorProxy());
SerializationProxy::registerProxy(typeid(CMAPTorsionForce), new CMAPTorsionForceProxy()); SerializationProxy::registerProxy(typeid(CMAPTorsionForce), new CMAPTorsionForceProxy());
SerializationProxy::registerProxy(typeid(CMMotionRemover), new CMMotionRemoverProxy()); SerializationProxy::registerProxy(typeid(CMMotionRemover), new CMMotionRemoverProxy());
......
/* -------------------------------------------------------------------------- *
* 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) 2010-2023 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/internal/AssertionUtilities.h"
#include "openmm/ATMForce.h"
#include "openmm/HarmonicAngleForce.h"
#include "openmm/HarmonicBondForce.h"
#include "openmm/serialization/XmlSerializer.h"
#include <iostream>
#include <sstream>
using namespace OpenMM;
using namespace std;
void testSerialization() {
// Create a Force.
ATMForce force("2*x*(u0+u1+y)");
force.setForceGroup(3);
force.setName("custom name");
force.addGlobalParameter("x", 1.3);
force.addGlobalParameter("y", 2.221);
force.addEnergyParameterDerivative("y");
HarmonicBondForce* v1 = new HarmonicBondForce();
v1->addBond(2, 3, 5.2, 1.1);
force.addForce(v1);
HarmonicAngleForce* v2 = new HarmonicAngleForce();
v2->addAngle(3, 11, 15, 0.4, 0.2);
force.addForce(v2);
// Serialize and then deserialize it.
stringstream buffer;
XmlSerializer::serialize<ATMForce>(&force, "Force", buffer);
ATMForce* copy = XmlSerializer::deserialize<ATMForce>(buffer);
// Compare the two forces to see if they are identical.
ATMForce& force2 = *copy;
ASSERT_EQUAL(force.getForceGroup(), force2.getForceGroup());
ASSERT_EQUAL(force.getName(), force2.getName());
ASSERT_EQUAL(force.getEnergyFunction(), force2.getEnergyFunction());
ASSERT_EQUAL(force.getNumGlobalParameters(), force2.getNumGlobalParameters());
for (int i = 0; i < force.getNumGlobalParameters(); i++) {
ASSERT_EQUAL(force.getGlobalParameterName(i), force2.getGlobalParameterName(i));
ASSERT_EQUAL(force.getGlobalParameterDefaultValue(i), force2.getGlobalParameterDefaultValue(i));
}
ASSERT_EQUAL(force.getNumEnergyParameterDerivatives(), force2.getNumEnergyParameterDerivatives());
for (int i = 0; i < force.getNumEnergyParameterDerivatives(); i++)
ASSERT_EQUAL(force.getEnergyParameterDerivativeName(i), force2.getEnergyParameterDerivativeName(i));
ASSERT_EQUAL(force.getNumForces(), force2.getNumForces());
for (int i = 0; i < force.getNumForces(); i++) {
stringstream buffer1, buffer2;
XmlSerializer::serialize<Force>(&force.getForce(i), "Force", buffer1);
XmlSerializer::serialize<Force>(&force2.getForce(i), "Force", buffer2);
ASSERT_EQUAL(buffer1.str(), buffer2.str());
}
}
int main() {
try {
testSerialization();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* 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) 2023 Stanford University and the Authors. *
* Authors: Peter Eastman, Emilio Gallicchio *
* 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. *
* -------------------------------------------------------------------------- */
#ifdef WIN32
#define _USE_MATH_DEFINES // Needed to get M_PI
#endif
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/ATMForce.h"
#include "openmm/Context.h"
#include "openmm/CustomBondForce.h"
#include "openmm/CustomExternalForce.h"
#include "openmm/CustomNonbondedForce.h"
#include "openmm/HarmonicBondForce.h"
#include "openmm/LangevinMiddleIntegrator.h"
#include "openmm/LocalEnergyMinimizer.h"
#include "openmm/NonbondedForce.h"
#include "openmm/System.h"
#include "openmm/VerletIntegrator.h"
#include "openmm/serialization/XmlSerializer.h"
#include "sfmt/SFMT.h"
#include <algorithm>
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
void test2Particles() {
// A pair of particles tethered by an harmonic bond.
// Displace the second one to test energy and forces at different lambda values
System system;
system.addParticle(1.0);
system.addParticle(1.0);
double lmbd = 0.5;
double umax = 0.;
double ubcore= 0.;
double acore = 0.;
double direction = 1.0;
vector<Vec3> positions(2);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(0, 0, 0);
CustomBondForce* bond = new CustomBondForce("0.5*r^2");
bond->addBond(0, 1);
ATMForce* atm = new ATMForce(lmbd, lmbd, 0., 0, 0, umax, ubcore, acore, direction);
Vec3 nodispl = Vec3(0., 0., 0.);
Vec3 displ = Vec3(1., 0., 0.);
atm->addParticle( nodispl );
atm->addParticle( displ );
atm->addForce(bond);
atm->addEnergyParameterDerivative(ATMForce::Lambda1());
atm->addEnergyParameterDerivative(ATMForce::Lambda2());
system.addForce(atm);
VerletIntegrator integrator(1.0);
Context context(system, integrator, platform);
context.setPositions(positions);
for (double lm : {0.0, 0.5, 1.0}) {
context.setParameter(ATMForce::Lambda1(), lm);
context.setParameter(ATMForce::Lambda2(), lm);
State state = context.getState(State::Energy | State::Forces | State::ParameterDerivatives);
double epot = state.getPotentialEnergy();
double u0, u1, energy;
atm->getPerturbationEnergy(context, u1, u0, energy);
double epert = u1 - u0;
ASSERT_EQUAL_TOL(lm, context.getParameter(atm->Lambda1()), 1e-6);
ASSERT_EQUAL_TOL(lm, context.getParameter(atm->Lambda2()), 1e-6);
ASSERT_EQUAL_TOL(energy, epot, 1e-6);
ASSERT_EQUAL_TOL(lm*0.5*displ[0]*displ[0], epot, 1e-6);
ASSERT_EQUAL_TOL(0.0, u0, 1e-6);
ASSERT_EQUAL_TOL(0.5*displ[0]*displ[0], u1, 1e-6);
ASSERT_EQUAL_TOL(0.5*displ[0]*displ[0], epert, 1e-6);
ASSERT_EQUAL_VEC(Vec3(-lm*displ[0], 0.0, 0.0), state.getForces()[1], 1e-6);
ASSERT_EQUAL_TOL(0.0, state.getEnergyParameterDerivatives().at(ATMForce::Lambda1()), 1e-6);
ASSERT_EQUAL_TOL(0.5*displ[0]*displ[0], state.getEnergyParameterDerivatives().at(ATMForce::Lambda2()), 1e-6);
}
}
void test2Particles2Displacement0() {
// A pair of particles tethered by an harmonic bond.
// Displace the second one to test energy and forces at different lambda values
// In this version the second particle is displaced in both the initial and final states
// by different amounts.
System system;
system.addParticle(1.0);
system.addParticle(1.0);
double lmbd = 0.5;
double umax = 0.;
double ubcore= 0.;
double acore = 0.;
double direction = 1.0;
vector<Vec3> positions(2);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(0, 0, 0);
CustomBondForce* bond = new CustomBondForce("0.5*r^2");
bond->addBond(0, 1);
ATMForce* atm = new ATMForce(lmbd, lmbd, 0., 0., 0., umax, ubcore, acore, direction);
//first particle is not displaced at either state
Vec3 nodispl = Vec3(0., 0., 0.);
atm->addParticle( nodispl );
//second particle is displaced at both states but by the same amount (1,0,0)
Vec3 displ0 = Vec3(1., 0., 0.);
atm->addParticle( displ0, displ0 );
atm->addForce(bond);
system.addForce(atm);
VerletIntegrator integrator(1.0);
Context context(system, integrator, platform);
context.setPositions(positions);
State state;
double epot, epert;
double u0, u1, energy;
// U = U0 + lambda*epert; epert = U1 - U0
// When the second particle is displaced by the same amount at each state,
// the perturbation energy should be zero since the second particle
// is at the same position in the target and initial states,
// and the potential energy should be U0, the energy of the bond with the
// second particle displaced
state = context.getState(State::Energy | State::Forces);
epot = state.getPotentialEnergy();
atm->getPerturbationEnergy(context, u1, u0, energy);
epert = u1 - u0;
ASSERT_EQUAL_TOL(0.5*displ0[0]*displ0[0], epot, 1e-6);
ASSERT_EQUAL_TOL(0.0, epert, 1e-6);
//Displace the second particle further in the target state
Vec3 displ1 = Vec3(2., 0., 0.);
atm->setParticleParameters(1, displ1, displ0 );
atm->updateParametersInContext(context);
state = context.getState(State::Energy | State::Forces);
epot = state.getPotentialEnergy();
atm->getPerturbationEnergy(context, u1, u0, energy);
epert = u1 - u0;
ASSERT_EQUAL_TOL(0.5*displ1[0]*displ1[0] - 0.5*displ0[0]*displ0[0], epert, 1e-6);
ASSERT_EQUAL_TOL(0.5*displ0[0]*displ0[0] + lmbd*epert, epot, 1e-6);
}
double softCoreFunc(double u, double umax, double ub, double a, double& df) {
double usc = u;
df = 1.;
if(u > ub) {
double gu = (u-ub)/(a*(umax-ub)); //this is y/alpha
double zeta = 1. + 2.*gu*(gu + 1.) ;
double zetap = pow( zeta , a);
double s = 4.*(2.*gu + 1.)/zeta;
df = s*zetap/pow(1.+zetap,2);
usc = (umax-ub)*(zetap - 1.)/(zetap + 1.) + ub;
}
return usc;
}
void test2ParticlesSoftCore() {
// Similar to test2Particles() but employing a soft-core function
System system;
system.addParticle(1.0);
system.addParticle(1.0);
double lmbd = 0.5;
double umax = 10.;
double ubcore= 3.;
double acore = 0.125;
double direction = 1.0;
vector<Vec3> positions(2);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(0, 0, 0);
CustomBondForce* bond = new CustomBondForce("0.5*r^2");
bond->addBond(0, 1);
ATMForce* atm = new ATMForce(lmbd, lmbd, 0., 0, 0, umax, ubcore, acore, direction);
Vec3 nodispl = Vec3(0., 0., 0.);
Vec3 displ = Vec3(5., 0., 0.);
atm->addParticle( nodispl );
atm->addParticle( displ );
atm->addForce(bond);
system.addForce(atm);
VerletIntegrator integrator(1.0);
Context context(system, integrator, platform);
context.setPositions(positions);
State state = context.getState(State::Energy | State::Forces);
double epot = state.getPotentialEnergy();
double u0, u1, energy;
atm->getPerturbationEnergy(context, u1, u0, energy);
double epert = u1 - u0;
double ee = 0.5*displ[0]*displ[0];
double df;
ASSERT_EQUAL_TOL(energy, epot, 1e-6);
ASSERT_EQUAL_TOL(0.0, u0, 1e-6);
ASSERT_EQUAL_TOL(ee, u1, 1e-6);
ASSERT_EQUAL_TOL(ee, epert, 1e-6);
ASSERT_EQUAL_TOL(u0 + lmbd*softCoreFunc(epert, umax, ubcore, acore, df), epot, 1e-6);
ASSERT_EQUAL_VEC(Vec3(-lmbd*df*displ[0], 0.0, 0.0), state.getForces()[1], 1e-6);
}
void test2ParticlesNonbonded() {
System system;
system.addParticle(1.0);
system.addParticle(1.0);
NonbondedForce* nbforce = new NonbondedForce();
nbforce->addParticle( 1.0, 1.0, 1.0);
nbforce->addParticle(-1.0, 1.0, 1.0);
system.addForce(nbforce);
ATMForce* atm = new ATMForce(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
Vec3 nodispl = Vec3(0., 0., 0.);
Vec3 displ = Vec3(1., 0., 0.);
atm->addParticle( nodispl );
atm->addParticle( displ );
atm->addForce(XmlSerializer::clone<Force>(*nbforce));
system.removeForce(0);
system.addForce(atm);
vector<Vec3> positions;
positions.push_back(Vec3(0., 0., 0.));
positions.push_back(Vec3(1., 0., 0.));
VerletIntegrator integrator(1.0);
Context context(system, integrator, platform);
context.setPositions(positions);
double lambda = 0.5;
context.setParameter(ATMForce::Lambda1(), lambda);
context.setParameter(ATMForce::Lambda2(), lambda);
State state = context.getState( State::Energy );
double epot = state.getPotentialEnergy();
double u0, u1, energy;
atm->getPerturbationEnergy(context, u1, u0, energy);
double epert = u1 - u0;
ASSERT_EQUAL_TOL(-104.2320, epot, 1e-3);
ASSERT_EQUAL_TOL( 69.4062, epert, 1e-3);
// std::cout << "Nonbonded: epot = " << epot << std::endl;
// std::cout << "Nonbonded: epert = " << epert << std::endl;
}
void testParticlesCustomExpressionLinear() {
// Similar to test2Particles() but employing a custom alchemical energy expression
System system;
system.addParticle(1.0);
system.addParticle(1.0);
vector<Vec3> positions(2);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(0, 0, 0);
CustomBondForce* bond = new CustomBondForce("0.5*r^2");
bond->addBond(0, 1);
double lmbd = 0.5;
ATMForce* atm = new ATMForce("u0 + Lambda*(u1 - u0)");
atm->addGlobalParameter("Lambda", lmbd);
Vec3 nodispl = Vec3(0., 0., 0.);
Vec3 displ = Vec3(5., 0., 0.);
atm->addParticle( nodispl );
atm->addParticle( displ );
atm->addForce(bond);
system.addForce(atm);
VerletIntegrator integrator(1.0);
Context context(system, integrator, platform);
context.setPositions(positions);
State state = context.getState(State::Energy | State::Forces);
double epot = state.getPotentialEnergy();
double u0, u1, energy;
atm->getPerturbationEnergy(context, u1, u0, energy);
double epert = u1 - u0;
double ee = 0.5*displ[0]*displ[0];
ASSERT_EQUAL_TOL(energy, epot, 1e-6);
ASSERT_EQUAL_TOL(0.0, u0, 1e-6);
ASSERT_EQUAL_TOL(ee, u1, 1e-6);
ASSERT_EQUAL_TOL(ee, epert, 1e-6);
ASSERT_EQUAL_TOL(u0 + lmbd*epert, epot, 1e-6);
ASSERT_EQUAL_VEC(Vec3(-lmbd*displ[0], 0.0, 0.0), state.getForces()[1], 1e-6);
}
void testParticlesCustomExpressionSoftplus() {
// Similar to test2Particles() but employing a custom alchemical energy expression
System system;
system.addParticle(1.0);
system.addParticle(1.0);
vector<Vec3> positions(2);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(0, 0, 0);
Vec3 nodispl = Vec3(0., 0., 0.);
Vec3 displ = Vec3(2., 0., 0.);
CustomBondForce* bond = new CustomBondForce("0.5*r^2");
bond->addBond(0, 1);
ATMForce* atm = new ATMForce("u0 + ((Lambda2-Lambda1)/Alpha)*log(1. + exp(-Alpha*((u1-u0) - Uh))) + Lambda2*(u1-u0) + W0");
double lambda1 = 0.2;
double lambda2 = 0.5;
double alpha = 0.1;
double uh = 0;
double w0 = 0;
atm->addGlobalParameter("Lambda1", lambda1);
atm->addGlobalParameter("Lambda2", lambda2);
atm->addGlobalParameter("Alpha", alpha);
atm->addGlobalParameter("Uh", uh);
atm->addGlobalParameter("W0", w0);
atm->addParticle( nodispl );
atm->addParticle( displ );
atm->addForce(bond);
system.addForce(atm);
VerletIntegrator integrator(1.0);
Context context(system, integrator, platform);
context.setPositions(positions);
State state = context.getState(State::Energy | State::Forces);
double epot = state.getPotentialEnergy();
double u0, u1, energy;
atm->getPerturbationEnergy(context, u1, u0, energy);
double epert = u1 - u0;
double ebias = 0.0;
double ee = 1.0 + exp(-alpha*(epert - uh));
if(alpha > 0){
ebias = ((lambda2 - lambda1)/alpha) * log(ee);
}
ebias += lambda2 * epert + w0;
double bfp = (lambda2 - lambda1)/ee + lambda1;
double ep = 0.5*displ[0]*displ[0];
ASSERT_EQUAL_TOL(energy, epot, 1e-6);
ASSERT_EQUAL_TOL(0.0, u0, 1e-6);
ASSERT_EQUAL_TOL(ep, u1, 1e-6);
ASSERT_EQUAL_TOL(ep, epert, 1e-6);
ASSERT_EQUAL_TOL(u0 + ebias, epot, 1e-6);
ASSERT_EQUAL_VEC(Vec3(-bfp*displ[0], 0.0, 0.0), state.getForces()[1], 1e-6);
}
void testLargeSystem() {
// Create a system with lots of particles, each displaced differently.
int numParticles = 1000;
System system;
CustomExternalForce* external = new CustomExternalForce("x^2 + 2*y^2 + 3*z^2");
ATMForce* atm = new ATMForce(0.0, 0.0, 0.1, 0.0, 0.0, 1e6, 5e5, 1.0/16, 1.0);
atm->addForce(external);
system.addForce(atm);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
vector<Vec3> positions, displacements;
for (int i = 0; i < numParticles; i++) {
system.addParticle(1.0);
positions.push_back(3*Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt)));
Vec3 d(genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5);
displacements.push_back(d);
external->addParticle(i);
atm->addParticle(d);
}
// Also add a nonbonded force to trigger atom reordering on the GPU.
CustomNonbondedForce* nb = new CustomNonbondedForce("a*r^2");
nb->addGlobalParameter("a", 0.0);
for (int i = 0; i < numParticles; i++)
nb->addParticle();
system.addForce(nb);
VerletIntegrator integrator(1.0);
Context context(system, integrator, platform);
context.setPositions(positions);
// Evaluate the forces to see if the particles are at the correct positions.
for (double lambda : {0.0, 1.0}) {
context.setParameter(ATMForce::Lambda1(), lambda);
context.setParameter(ATMForce::Lambda2(), lambda);
State state = context.getState(State::Forces);
for (int i = 0; i < numParticles; i++) {
Vec3 expectedPos = positions[i] + lambda*displacements[i];
Vec3 expectedForce(-2*expectedPos[0], -4*expectedPos[1], -6*expectedPos[2]);
ASSERT_EQUAL_VEC(expectedForce, state.getForces()[i], 1e-6);
}
}
}
void testMolecules() {
// Verify that ATMForce correctly propagates information about molecules
// from the forces it contains.
System system;
for (int i = 0; i < 5; i++)
system.addParticle(1.0);
ATMForce* atm = new ATMForce(0.0, 0.0, 0.1, 0.0, 0.0, 1e6, 5e5, 1.0/16, 1.0);
system.addForce(atm);
HarmonicBondForce* bonds1 = new HarmonicBondForce();
bonds1->addBond(0, 1, 1.0, 1.0);
bonds1->addBond(2, 3, 1.0, 1.0);
atm->addForce(bonds1);
HarmonicBondForce* bonds2 = new HarmonicBondForce();
bonds2->addBond(1, 2, 1.0, 1.0);
atm->addForce(bonds2);
VerletIntegrator integrator(0.01);
Context context(system, integrator, platform);
vector<vector<int> > molecules = context.getMolecules();
ASSERT_EQUAL(2, molecules.size());
for (auto& mol : molecules) {
if (mol.size() == 1) {
ASSERT_EQUAL(4, mol[0]);
}
else {
ASSERT_EQUAL(4, mol.size());
for (int i = 0; i < 4; i++)
ASSERT(find(mol.begin(), mol.end(), i) != mol.end());
}
}
}
void testSimulation() {
// Create a box of Lennard-Jones spheres, including an ATMForce that displaces
// one particle to two different locations.
int numParticles = 27;
double width = 2.0;
System system;
system.setDefaultPeriodicBoxVectors(Vec3(width, 0, 0), Vec3(0, width, 0), Vec3(0, 0, width));
ATMForce* atm = new ATMForce("(u0+u1)/2");
system.addForce(atm);
NonbondedForce* nb = new NonbondedForce();
nb->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
nb->setCutoffDistance(1.0);
atm->addForce(nb);
vector<Vec3> positions;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
for (int k = 0; k < 3; k++) {
system.addParticle(10.0);
positions.push_back(Vec3(0.6*i, 0.6*j, 0.6*k));
nb->addParticle(0, 0.3, 1.0);
atm->addParticle(Vec3());
}
atm->setParticleParameters(0, Vec3(0.3, 0, 0), Vec3(-0.3, 0, 0));
// Simulate it and make sure that the other particles avoid the displaced positions.
LangevinMiddleIntegrator integrator(300, 1.0, 0.004);
Context context(system, integrator, platform);
context.setPositions(positions);
context.setVelocitiesToTemperature(300);
for (int i = 0; i < 100; i++) {
integrator.step(10);
vector<Vec3> pos = context.getState(State::Positions).getPositions();
for (int j = 1; j < numParticles; j++) {
for (double displacement : {-0.3, 0.3}) {
Vec3 d = pos[0]-pos[j];
d[0] += displacement;
for (int k = 0; k < 3; k++)
d[k] -= round(d[k]/width)*width;
assert(sqrt(d.dot(d)) > 0.2);
}
}
}
}
void runPlatformTests();
int main(int argc, char* argv[]) {
try {
initializeTests(argc, argv);
test2Particles();
test2Particles2Displacement0();
test2ParticlesSoftCore();
test2ParticlesNonbonded();
testParticlesCustomExpressionLinear();
testParticlesCustomExpressionSoftplus();
testLargeSystem();
testMolecules();
testSimulation();
runPlatformTests();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
...@@ -109,6 +109,9 @@ SKIP_METHODS = [('State', 'getPositions'), ...@@ -109,6 +109,9 @@ SKIP_METHODS = [('State', 'getPositions'),
("NoseHooverIntegrator", "getAllThermostatedPairs"), ("NoseHooverIntegrator", "getAllThermostatedPairs"),
] ]
# The build script assumes method args that are non-const references are # The build script assumes method args that are non-const references are
# used to output values. This list gives excpetions to this rule. # used to output values. This list gives excpetions to this rule.
NO_OUTPUT_ARGS = [('LocalEnergyMinimizer', 'minimize', 'context'), NO_OUTPUT_ARGS = [('LocalEnergyMinimizer', 'minimize', 'context'),
...@@ -137,6 +140,7 @@ NO_OUTPUT_ARGS = [('LocalEnergyMinimizer', 'minimize', 'context'), ...@@ -137,6 +140,7 @@ NO_OUTPUT_ARGS = [('LocalEnergyMinimizer', 'minimize', 'context'),
STEAL_OWNERSHIP = {("Platform", "registerPlatform") : [0], STEAL_OWNERSHIP = {("Platform", "registerPlatform") : [0],
("System", "addForce") : [0], ("System", "addForce") : [0],
("System", "setVirtualSite") : [1], ("System", "setVirtualSite") : [1],
("ATMForce", "addForce") : [0],
("CustomNonbondedForce", "addTabulatedFunction") : [1], ("CustomNonbondedForce", "addTabulatedFunction") : [1],
("CustomGBForce", "addTabulatedFunction") : [1], ("CustomGBForce", "addTabulatedFunction") : [1],
("CustomHbondForce", "addTabulatedFunction") : [1], ("CustomHbondForce", "addTabulatedFunction") : [1],
...@@ -319,8 +323,7 @@ UNITS = { ...@@ -319,8 +323,7 @@ UNITS = {
None, None, None, None, None, None, None, None, None, None, None, None)), None, None, None, None, None, None, None, None, None, None, None, None)),
("HippoNonbondedForce", "getInducedDipoles") : ( None, ()), ("HippoNonbondedForce", "getInducedDipoles") : ( None, ()),
("HippoNonbondedForce", "getLabFramePermanentDipoles") : ( None, ()), ("HippoNonbondedForce", "getLabFramePermanentDipoles") : ( None, ()),
("Context", "getParameter") : (None, ()), ("Context", "getParameter") : (None, ()),
("Context", "getParameters") : (None, ()), ("Context", "getParameters") : (None, ()),
("Context", "getMolecules") : (None, ()), ("Context", "getMolecules") : (None, ()),
...@@ -507,4 +510,15 @@ UNITS = { ...@@ -507,4 +510,15 @@ UNITS = {
("DrudeNoseHooverIntegrator", "getMaxDrudeDistance") : ("unit.nanometer", ()), ("DrudeNoseHooverIntegrator", "getMaxDrudeDistance") : ("unit.nanometer", ()),
("DrudeNoseHooverIntegrator", "setMaxDrudeDistance") : (None, ("unit.nanometer",)), ("DrudeNoseHooverIntegrator", "setMaxDrudeDistance") : (None, ("unit.nanometer",)),
("LocalEnergyMinimizer", "minimize") : (None, (None, "unit.kilojoules_per_mole/unit.nanometer", None)), ("LocalEnergyMinimizer", "minimize") : (None, (None, "unit.kilojoules_per_mole/unit.nanometer", None)),
("ATMForce", "getForce") : (None, ()),
("ATMForce", "getPerturbationEnergy") : ('unit.kilojoule_per_mole', ()),
("ATMForce", "getDefaultLambda1") : (None, ()),
("ATMForce", "getDefaultLambda2") : (None, ()),
("ATMForce", "getDefaultAlpha") : ('unit.kilojoule_per_mole**-1', ()),
("ATMForce", "getDefaultU0") : ('unit.kilojoule_per_mole', ()),
("ATMForce", "getDefaultW0") : ('unit.kilojoule_per_mole', ()),
("ATMForce", "getDefaultDirection") : (None, ()),
("ATMForce", "getDefaultUmax") : ('unit.kilojoule_per_mole', ()),
("ATMForce", "getDefaultUbcore") : ('unit.kilojoule_per_mole', ()),
("ATMForce", "getDefaultAcore") : (None, ()),
} }
import unittest
from openmm import *
from openmm.app import *
from openmm.unit import *
class TestATMForce(unittest.TestCase):
"""Tests the ATMForce"""
def test2ParticlesNonbonded(self):
"""Test for a Nonbonded force previously added to the System"""
system = System()
system.addParticle(1.0)
system.addParticle(1.0)
nbforce = NonbondedForce();
nbforce.addParticle( 1.0, 1.0, 1.0)
nbforce.addParticle(-1.0, 1.0, 1.0)
system.addForce(nbforce)
atmforce = ATMForce(0.5, 0.5, 0, 0, 0, 0, 0, 0, 1.0)
atmforce.addParticle(Vec3(0., 0., 0.))
atmforce.addParticle(Vec3(1., 0., 0.))
atmforce.addForce(copy.copy(nbforce))
system.removeForce(0)
system.addForce(atmforce)
integrator = VerletIntegrator(1.0)
platform = Platform.getPlatformByName('Reference')
context = Context(system, integrator, platform)
positions = []
positions.append(Vec3(0., 0., 0.))
positions.append(Vec3(1., 0., 0.))
context.setPositions(positions)
state = context.getState(getEnergy = True, getForces = True)
epot = state.getPotentialEnergy()
(u1, u0, energy) = atmforce.getPerturbationEnergy(context)
epert = u1 - u0
#print("Potential energy = ", epot)
#print("ATM perturbation energy = ", epert)
epot_expected = -104.2320*kilojoules_per_mole
epert_expected = 69.4062*kilojoules_per_mole
assert( abs(epot-epot_expected) < 1.e-3*kilojoules_per_mole )
assert( abs(epert-epert_expected) < 1.e-3*kilojoules_per_mole )
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