Commit 1c938ceb authored by Jason Swails's avatar Jason Swails
Browse files

Merge branch 'master' into amber-switching

 Conflicts:
	wrappers/python/simtk/openmm/app/amberprmtopfile.py

In fixing the merge conflict, I went ahead and fixed up the switchDistance logic
to match what I did in CharmmPsfFile.
parents a1113e7b 167ae8a0
......@@ -6,6 +6,8 @@ INSTALL_FILES(/include/openmm/serialization FILES ${CMAKE_CURRENT_SOURCE_DIR}/in
INSTALL_FILES(/include/openmm/serialization FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/openmm/serialization/SerializationProxy.h)
INSTALL_FILES(/include/openmm/serialization FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/openmm/serialization/XmlSerializer.h)
IF(BUILD_TESTING)
SET(OPENMM_BUILD_SERIALIZATION_TESTS TRUE CACHE BOOL "Whether to build serialization test cases")
MARK_AS_ADVANCED(OPENMM_BUILD_SERIALIZATION_TESTS)
IF(BUILD_TESTING AND OPENMM_BUILD_SERIALIZATION_TESTS)
ADD_SUBDIRECTORY(tests)
ENDIF(BUILD_TESTING)
ENDIF(BUILD_TESTING AND OPENMM_BUILD_SERIALIZATION_TESTS)
#ifndef OPENMM_COMPOUND_INTEGRATOR_PROXY_H_
#define OPENMM_COMPOUND_INTEGRATOR_PROXY_H_
#include "openmm/serialization/XmlSerializer.h"
namespace OpenMM {
class CompoundIntegratorProxy : public SerializationProxy {
public:
CompoundIntegratorProxy();
void serialize(const void* object, SerializationNode& node) const;
void* deserialize(const SerializationNode& node) const;
};
}
#endif /*OPENMM_COMPOUND_INTEGRATOR_PROXY_H_*/
\ No newline at end of file
......@@ -105,7 +105,7 @@ public:
/**
* Determine whether this node has a property with a particular node.
*
* @param the name of the property to check for
* @param name the name of the property to check for
*/
bool hasProperty(const std::string& name) const;
/**
......
#ifndef OPENMM_GBVIFORCEFIELDIMPL_H_
#define OPENMM_GBVIFORCEFIELDIMPL_H_
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
......@@ -9,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2008 Stanford University and the Authors. *
* Portions copyright (c) 2015 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
......@@ -32,46 +29,29 @@
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "ForceImpl.h"
#include "openmm/GBVIForce.h"
#include "openmm/Kernel.h"
#include <string>
namespace OpenMM {
/**
* This is the internal implementation of GBVIForce.
*/
class GBVIForceImpl : public ForceImpl {
public:
GBVIForceImpl(const GBVIForce& owner);
void initialize(ContextImpl& context);
const GBVIForce& getOwner() const {
return owner;
}
// calculate scaled radii (Eq. 5 of Labute paper [JCC 29 1693-1698 2008])
void findScaledRadii( int numberOfParticles, const std::vector<std::vector<int> >& bondIndices,
const std::vector<double> & bondLengths, std::vector<double> & scaledRadii) const;
// if bond info not set, then use bond forces/constraints
int getBondsFromForces(ContextImpl& context);
void updateContextState(ContextImpl& context) {
// This force field doesn't update the state directly.
}
double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups);
std::map<std::string, double> getDefaultParameters() {
return std::map<std::string, double>(); // This force field doesn't define any parameters.
}
std::vector<std::string> getKernelNames();
private:
const GBVIForce& owner;
Kernel kernel;
};
} // namespace OpenMM
#endif /*OPENMM_GBVIFORCEFIELDIMPL_H_*/
#include "openmm/serialization/CompoundIntegratorProxy.h"
#include <OpenMM.h>
using namespace std;
using namespace OpenMM;
CompoundIntegratorProxy::CompoundIntegratorProxy() : SerializationProxy("CompoundIntegrator") {
}
void CompoundIntegratorProxy::serialize(const void* object, SerializationNode& node) const {
node.setIntProperty("version", 1);
const CompoundIntegrator& integrator = *reinterpret_cast<const CompoundIntegrator*>(object);
node.setIntProperty("currentIntegrator", integrator.getCurrentIntegrator());
for (int i = 0; i < integrator.getNumIntegrators(); i++)
node.createChildNode("Integrator", &integrator.getIntegrator(i));
}
void* CompoundIntegratorProxy::deserialize(const SerializationNode& node) const {
if (node.getIntProperty("version") != 1)
throw OpenMMException("Unsupported version number");
CompoundIntegrator *integrator = new CompoundIntegrator();
for (int i = 0; i < node.getChildren().size(); i++)
integrator->addIntegrator(node.getChildren()[i].decodeObject<Integrator>());
integrator->setCurrentIntegrator(node.getIntProperty("currentIntegrator"));
return integrator;
}
\ No newline at end of file
/* -------------------------------------------------------------------------- *
* 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-2014 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/GBVIForceProxy.h"
#include "openmm/serialization/SerializationNode.h"
#include "openmm/Force.h"
#include "openmm/GBVIForce.h"
#include <sstream>
using namespace OpenMM;
using namespace std;
GBVIForceProxy::GBVIForceProxy() : SerializationProxy("GBVIForce") {
}
void GBVIForceProxy::serialize(const void* object, SerializationNode& node) const {
node.setIntProperty("version", 2);
const GBVIForce& force = *reinterpret_cast<const GBVIForce*>(object);
node.setIntProperty("forceGroup", force.getForceGroup());
node.setIntProperty("method", (int) force.getNonbondedMethod());
node.setIntProperty("scalingMethod", (int) force.getBornRadiusScalingMethod());
node.setDoubleProperty("quinticLowerLimitFactor", force.getQuinticLowerLimitFactor());
node.setDoubleProperty("quinticUpperBornRadiusLimit", force.getQuinticUpperBornRadiusLimit());
node.setDoubleProperty("cutoff", force.getCutoffDistance());
node.setDoubleProperty("soluteDielectric", force.getSoluteDielectric());
node.setDoubleProperty("solventDielectric", force.getSolventDielectric());
SerializationNode& particles = node.createChildNode("Particles");
for (int i = 0; i < force.getNumParticles(); i++) {
double charge, radius, gamma;
force.getParticleParameters(i, charge, radius, gamma);
particles.createChildNode("Particle").setDoubleProperty("q", charge).setDoubleProperty("r", radius).setDoubleProperty("gamma", gamma);
}
SerializationNode& bonds = node.createChildNode("Bonds");
for (int i = 0; i < force.getNumBonds(); i++) {
int particle1, particle2;
double distance;
force.getBondParameters(i, particle1, particle2, distance);
bonds.createChildNode("Bond").setIntProperty("p1", particle1).setIntProperty("p2", particle2).setDoubleProperty("d", distance);
}
}
void* GBVIForceProxy::deserialize(const SerializationNode& node) const {
if (node.getIntProperty("version") != 1 && node.getIntProperty("version") != 2)
throw OpenMMException("Unsupported version number");
GBVIForce* force = new GBVIForce();
try {
force->setForceGroup(node.getIntProperty("forceGroup", 0));
force->setNonbondedMethod((GBVIForce::NonbondedMethod) node.getIntProperty("method"));
force->setCutoffDistance(node.getDoubleProperty("cutoff"));
force->setSoluteDielectric(node.getDoubleProperty("soluteDielectric"));
force->setSolventDielectric(node.getDoubleProperty("solventDielectric"));
if( node.getIntProperty("version") >= 2 ){
force->setBornRadiusScalingMethod( (GBVIForce::BornRadiusScalingMethod) node.getIntProperty( "scalingMethod"));
force->setQuinticLowerLimitFactor(node.getDoubleProperty("quinticLowerLimitFactor"));
force->setQuinticUpperBornRadiusLimit(node.getDoubleProperty("quinticUpperBornRadiusLimit"));
}
const SerializationNode& particles = node.getChildNode("Particles");
for (int i = 0; i < (int) particles.getChildren().size(); i++) {
const SerializationNode& particle = particles.getChildren()[i];
force->addParticle(particle.getDoubleProperty("q"), particle.getDoubleProperty("r"), particle.getDoubleProperty("gamma"));
}
const SerializationNode& bonds = node.getChildNode("Bonds");
for (int i = 0; i < (int) bonds.getChildren().size(); i++) {
const SerializationNode& bond = bonds.getChildren()[i];
force->addBond(bond.getIntProperty("p1"), bond.getIntProperty("p2"), bond.getDoubleProperty("d"));
}
}
catch (...) {
delete force;
throw;
}
return force;
}
......@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2010-2014 Stanford University and the Authors. *
* Portions copyright (c) 2010-2015 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
......@@ -33,6 +33,7 @@
#include "openmm/BrownianIntegrator.h"
#include "openmm/CMAPTorsionForce.h"
#include "openmm/CMMotionRemover.h"
#include "openmm/CompoundIntegrator.h"
#include "openmm/CustomAngleForce.h"
#include "openmm/CustomBondForce.h"
#include "openmm/CustomCompoundBondForce.h"
......@@ -44,7 +45,6 @@
#include "openmm/CustomNonbondedForce.h"
#include "openmm/CustomTorsionForce.h"
#include "openmm/GBSAOBCForce.h"
#include "openmm/GBVIForce.h"
#include "openmm/HarmonicAngleForce.h"
#include "openmm/HarmonicBondForce.h"
#include "openmm/LangevinIntegrator.h"
......@@ -65,6 +65,7 @@
#include "openmm/serialization/AndersenThermostatProxy.h"
#include "openmm/serialization/CMAPTorsionForceProxy.h"
#include "openmm/serialization/CMMotionRemoverProxy.h"
#include "openmm/serialization/CompoundIntegratorProxy.h"
#include "openmm/serialization/CustomAngleForceProxy.h"
#include "openmm/serialization/CustomBondForceProxy.h"
#include "openmm/serialization/CustomCompoundBondForceProxy.h"
......@@ -76,7 +77,6 @@
#include "openmm/serialization/CustomNonbondedForceProxy.h"
#include "openmm/serialization/CustomTorsionForceProxy.h"
#include "openmm/serialization/GBSAOBCForceProxy.h"
#include "openmm/serialization/GBVIForceProxy.h"
#include "openmm/serialization/HarmonicAngleForceProxy.h"
#include "openmm/serialization/HarmonicBondForceProxy.h"
#include "openmm/serialization/LangevinIntegratorProxy.h"
......@@ -112,6 +112,7 @@ extern "C" void registerSerializationProxies() {
SerializationProxy::registerProxy(typeid(BrownianIntegrator), new BrownianIntegratorProxy());
SerializationProxy::registerProxy(typeid(CMAPTorsionForce), new CMAPTorsionForceProxy());
SerializationProxy::registerProxy(typeid(CMMotionRemover), new CMMotionRemoverProxy());
SerializationProxy::registerProxy(typeid(CompoundIntegrator), new CompoundIntegratorProxy());
SerializationProxy::registerProxy(typeid(Continuous1DFunction), new Continuous1DFunctionProxy());
SerializationProxy::registerProxy(typeid(Continuous2DFunction), new Continuous2DFunctionProxy());
SerializationProxy::registerProxy(typeid(Continuous3DFunction), new Continuous3DFunctionProxy());
......@@ -129,7 +130,6 @@ extern "C" void registerSerializationProxies() {
SerializationProxy::registerProxy(typeid(Discrete2DFunction), new Discrete2DFunctionProxy());
SerializationProxy::registerProxy(typeid(Discrete3DFunction), new Discrete3DFunctionProxy());
SerializationProxy::registerProxy(typeid(GBSAOBCForce), new GBSAOBCForceProxy());
SerializationProxy::registerProxy(typeid(GBVIForce), new GBVIForceProxy());
SerializationProxy::registerProxy(typeid(HarmonicAngleForce), new HarmonicAngleForceProxy());
SerializationProxy::registerProxy(typeid(HarmonicBondForce), new HarmonicBondForceProxy());
SerializationProxy::registerProxy(typeid(LangevinIntegrator), new LangevinIntegratorProxy());
......
......@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2010 Stanford University and the Authors. *
* Portions copyright (c) 2010-2015 Stanford University and the Authors. *
* Authors: Peter Eastman, Yutong Zhao *
* Contributors: *
* *
......@@ -32,6 +32,7 @@
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/BrownianIntegrator.h"
#include "openmm/CompoundIntegrator.h"
#include "openmm/CustomIntegrator.h"
#include "openmm/LangevinIntegrator.h"
#include "openmm/VariableLangevinIntegrator.h"
......@@ -185,6 +186,29 @@ void testSerializeCustomIntegrator() {
delete intg2;
}
void testSerializeCompoundIntegrator() {
CompoundIntegrator integ;
integ.addIntegrator(new LangevinIntegrator(372.4, 1.234, 0.0018));
integ.addIntegrator(new VerletIntegrator(0.002));
integ.setCurrentIntegrator(1);
stringstream ss;
XmlSerializer::serialize<Integrator>(&integ, "CompoundIntegrator", ss);
CompoundIntegrator *integ2 = dynamic_cast<CompoundIntegrator*>(XmlSerializer::deserialize<Integrator>(ss));
ASSERT_EQUAL(integ.getCurrentIntegrator(), integ2->getCurrentIntegrator());
LangevinIntegrator& langevin1 = dynamic_cast<LangevinIntegrator&>(integ.getIntegrator(0));
LangevinIntegrator& langevin2 = dynamic_cast<LangevinIntegrator&>(integ2->getIntegrator(0));
ASSERT_EQUAL(langevin1.getConstraintTolerance(), langevin2.getConstraintTolerance());
ASSERT_EQUAL(langevin1.getStepSize(), langevin2.getStepSize());
ASSERT_EQUAL(langevin1.getTemperature(), langevin2.getTemperature());
ASSERT_EQUAL(langevin1.getFriction(), langevin2.getFriction());
ASSERT_EQUAL(langevin1.getRandomNumberSeed(), langevin2.getRandomNumberSeed());
VerletIntegrator& verlet1 = dynamic_cast<VerletIntegrator&>(integ.getIntegrator(1));
VerletIntegrator& verlet2 = dynamic_cast<VerletIntegrator&>(integ2->getIntegrator(1));
ASSERT_EQUAL(verlet1.getConstraintTolerance(), verlet2.getConstraintTolerance());
ASSERT_EQUAL(verlet1.getStepSize(), verlet2.getStepSize());
delete integ2;
}
int main() {
try {
testSerializeBrownianIntegrator();
......@@ -193,6 +217,7 @@ int main() {
testSerializeVariableLangevinIntegrator();
testSerializeVariableVerletIntegrator();
testSerializeLangevinIntegrator();
testSerializeCompoundIntegrator();
}
catch(const exception& e) {
return 1;
......
......@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2008-2009 Stanford University and the Authors. *
* Portions copyright (c) 2015 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
......@@ -29,214 +29,194 @@
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
/**
* This tests the reference implementation of GBVIForce.
*/
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/BrownianIntegrator.h"
#include "openmm/CompoundIntegrator.h"
#include "openmm/Context.h"
#include "ReferencePlatform.h"
#include "openmm/HarmonicBondForce.h"
#include "openmm/GBVIForce.h"
#include "openmm/GBSAOBCForce.h"
#include "openmm/System.h"
#include "openmm/LangevinIntegrator.h"
#include "openmm/NonbondedForce.h"
#include "openmm/System.h"
#include "openmm/VerletIntegrator.h"
#include "SimTKOpenMMRealType.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
ReferencePlatform platform;
const double TOL = 1e-5;
void testSingleParticle() {
void testChangingIntegrator() {
System system;
system.addParticle(2.0);
LangevinIntegrator integrator(0, 0.1, 0.01);
GBVIForce* forceField = new GBVIForce();
double charge = -1.0;
double radius = 0.15;
double gamma = 1.0;
forceField->addParticle(charge, radius, gamma);
system.addForce(forceField);
ASSERT(!forceField->usesPeriodicBoundaryConditions());
ASSERT(!system.usesPeriodicBoundaryConditions());
Context context(system, integrator, platform);
vector<Vec3> positions(1);
positions[0] = Vec3(0, 0, 0);
context.setPositions(positions);
State state = context.getState(State::Energy);
double bornRadius = radius;
double eps0 = EPSILON0;
double tau = (1.0/forceField->getSoluteDielectric()-1.0/forceField->getSolventDielectric());
double bornEnergy = (-charge*charge/(8*PI_M*eps0))*tau/bornRadius;
double nonpolarEnergy = -gamma*tau*std::pow(radius/bornRadius, 3.0);
double expectedE = (bornEnergy+nonpolarEnergy);
double obtainedE = state.getPotentialEnergy();
double diff = fabs((obtainedE - expectedE)/expectedE);
ASSERT_EQUAL_TOL((bornEnergy+nonpolarEnergy), state.getPotentialEnergy(), 0.01);
}
void testEnergyEthane(int applyBornRadiiScaling) {
const int numParticles = 8;
System system;
LangevinIntegrator integrator(0, 0.1, 0.01);
// harmonic bond
double C_HBondDistance = 0.1097;
double C_CBondDistance = 0.1504;
system.addParticle(2.0);
HarmonicBondForce* bonds = new HarmonicBondForce();
bonds->addBond(0, 1, C_HBondDistance, 0.0);
bonds->addBond(2, 1, C_HBondDistance, 0.0);
bonds->addBond(3, 1, C_HBondDistance, 0.0);
bonds->addBond(1, 4, C_CBondDistance, 0.0);
bonds->addBond(5, 4, C_HBondDistance, 0.0);
bonds->addBond(6, 4, C_HBondDistance, 0.0);
bonds->addBond(7, 4, C_HBondDistance, 0.0);
bonds->addBond(0, 1, 1.5, 1);
system.addForce(bonds);
double C_radius, C_gamma, C_charge, H_radius, H_gamma, H_charge;
int AM1_BCC = 1;
H_charge = -0.053;
C_charge = -3.0*H_charge;
if (AM1_BCC) {
C_radius = 0.180;
C_gamma = -0.2863;
H_radius = 0.125;
H_gamma = 0.2437;
}
else {
C_radius = 0.215;
C_gamma = -1.1087;
H_radius = 0.150;
H_gamma = 0.1237;
CompoundIntegrator integrator;
integrator.addIntegrator(new VerletIntegrator(0.01));
integrator.addIntegrator(new LangevinIntegrator(300.0, 10.0, 0.011));
integrator.addIntegrator(new BrownianIntegrator(300.0, 10.0, 0.012));
Context context(system, integrator, platform);
ASSERT_EQUAL(0, integrator.getCurrentIntegrator());
vector<Vec3> positions(2);
positions[0] = Vec3(-1, 0, 0);
positions[1] = Vec3(1, 0, 0);
for (int iteration = 0; iteration < 2; ++iteration) {
context.setPositions(positions);
// First integrate with the Verlet integrator and compare it to the analytical solution.
const double freq = 1.0;
State state = context.getState(State::Energy);
const double initialEnergy = state.getKineticEnergy()+state.getPotentialEnergy();
for (int i = 0; i < 100; ++i) {
state = context.getState(State::Positions | State::Velocities | State::Energy);
double time = state.getTime();
double expectedDist = 1.5+0.5*std::cos(freq*time);
ASSERT_EQUAL_VEC(Vec3(-0.5*expectedDist, 0, 0), state.getPositions()[0], 0.02);
ASSERT_EQUAL_VEC(Vec3(0.5*expectedDist, 0, 0), state.getPositions()[1], 0.02);
double expectedSpeed = -0.5*freq*std::sin(freq*time);
ASSERT_EQUAL_VEC(Vec3(-0.5*expectedSpeed, 0, 0), state.getVelocities()[0], 0.02);
ASSERT_EQUAL_VEC(Vec3(0.5*expectedSpeed, 0, 0), state.getVelocities()[1], 0.02);
double energy = state.getKineticEnergy()+state.getPotentialEnergy();
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01);
integrator.step(1);
}
ASSERT_EQUAL_TOL(100*0.01, context.getState(0).getTime(), 1e-5);
// Switch to the Langevin integrator and make sure that it heats up.
integrator.setCurrentIntegrator(1);
integrator.step(100);
double ke = 0.0;
for (int i = 0; i < 1000; ++i) {
integrator.step(10);
state = context.getState(State::Energy);
ke += state.getKineticEnergy();
}
double expectedKE = 0.5*2*3*BOLTZ*300.0;
ASSERT_USUALLY_EQUAL_TOL(expectedKE, ke/1000, 0.1);
ASSERT_EQUAL_TOL(100*0.01+10100*0.011, context.getState(0).getTime(), 1e-5);
// Now reinitialize the context and repeat all of these tests to make sure that works correctly.
context.reinitialize();
integrator.setCurrentIntegrator(0);
}
}
NonbondedForce* nonbonded = new NonbondedForce();
nonbonded->setNonbondedMethod(NonbondedForce::NoCutoff);
GBVIForce* forceField = new GBVIForce();
if (applyBornRadiiScaling) {
forceField->setBornRadiusScalingMethod(GBVIForce::QuinticSpline);
void testChangingParameters() {
System system;
system.addParticle(1.0);
CompoundIntegrator integrator;
integrator.addIntegrator(new VerletIntegrator(0.01));
integrator.addIntegrator(new LangevinIntegrator(300.0, 10.0, 0.02));
integrator.addIntegrator(new BrownianIntegrator(300.0, 10.0, 0.03));
// Try getting and setting the step size for different component integrators.
for (int i = 0; i < 3; i++) {
integrator.setCurrentIntegrator(i);
ASSERT_EQUAL_TOL(0.01*(i+1), integrator.getStepSize(), 1e-7);
}
else {
forceField->setBornRadiusScalingMethod(GBVIForce::NoScaling);
for (int i = 0; i < 3; i++) {
integrator.setCurrentIntegrator(i);
integrator.setStepSize(0.02*(i+1));
ASSERT_EQUAL_TOL(0.02*(i+1), integrator.getStepSize(), 1e-7);
}
for (int i = 0; i < numParticles; i++) {
system.addParticle(1.0);
forceField->addParticle(H_charge, H_radius, H_gamma);
nonbonded->addParticle( H_charge, H_radius, 0.0);
for (int i = 0; i < 3; i++) {
integrator.setCurrentIntegrator(i);
ASSERT_EQUAL_TOL(0.02*(i+1), integrator.getStepSize(), 1e-7);
}
forceField->setParticleParameters(1, C_charge, C_radius, C_gamma);
forceField->setParticleParameters(4, C_charge, C_radius, C_gamma);
nonbonded->setParticleParameters( 1, C_charge, C_radius, 0.0);
nonbonded->setParticleParameters( 4, C_charge, C_radius, 0.0);
forceField->addBond(0, 1, C_HBondDistance);
forceField->addBond(2, 1, C_HBondDistance);
forceField->addBond(3, 1, C_HBondDistance);
forceField->addBond(1, 4, C_CBondDistance);
forceField->addBond(5, 4, C_HBondDistance);
forceField->addBond(6, 4, C_HBondDistance);
forceField->addBond(7, 4, C_HBondDistance);
std::vector<pair<int, int> > bondExceptions;
std::vector<double> bondDistances;
bondExceptions.push_back(pair<int, int>(0, 1));
bondDistances.push_back(C_HBondDistance);
bondExceptions.push_back(pair<int, int>(2, 1));
bondDistances.push_back(C_HBondDistance);
bondExceptions.push_back(pair<int, int>(3, 1));
bondDistances.push_back(C_HBondDistance);
// Try getting and setting the constraint tolerance for different component integrators.
bondExceptions.push_back(pair<int, int>(1, 4));
bondDistances.push_back(C_CBondDistance);
bondExceptions.push_back(pair<int, int>(5, 4));
bondDistances.push_back(C_HBondDistance);
bondExceptions.push_back(pair<int, int>(6, 4));
bondDistances.push_back(C_HBondDistance);
bondExceptions.push_back(pair<int, int>(7, 4));
bondDistances.push_back(C_HBondDistance);
nonbonded->createExceptionsFromBonds(bondExceptions, 0.0, 0.0);
system.addForce(forceField);
system.addForce(nonbonded);
for (int i = 0; i < 3; i++) {
integrator.setCurrentIntegrator(i);
ASSERT_EQUAL_TOL(1e-5, integrator.getConstraintTolerance(), 1e-7);
}
for (int i = 0; i < 3; i++) {
integrator.setCurrentIntegrator(i);
integrator.setConstraintTolerance(1e-4*(i+1));
ASSERT_EQUAL_TOL(1e-4*(i+1), integrator.getConstraintTolerance(), 1e-7);
}
for (int i = 0; i < 3; i++) {
integrator.setCurrentIntegrator(i);
ASSERT_EQUAL_TOL(1e-4*(i+1), integrator.getConstraintTolerance(), 1e-7);
}
}
void testDifferentStepSizes() {
System system;
system.addParticle(2.0);
system.addParticle(2.0);
HarmonicBondForce* bonds = new HarmonicBondForce();
bonds->addBond(0, 1, 1.5, 1);
system.addForce(bonds);
CompoundIntegrator integrator;
integrator.addIntegrator(new VerletIntegrator(0.005));
integrator.addIntegrator(new VerletIntegrator(0.01));
Context context(system, integrator, platform);
vector<Vec3> positions(numParticles);
positions[0] = Vec3(0.5480, 1.7661, 0.0000);
positions[1] = Vec3(0.7286, 0.8978, 0.6468);
positions[2] = Vec3(0.4974, 0.0000, 0.0588);
positions[3] = Vec3(0.0000, 0.9459, 1.4666);
positions[4] = Vec3(2.1421, 0.8746, 1.1615);
positions[5] = Vec3(2.3239, 0.0050, 1.8065);
positions[6] = Vec3(2.8705, 0.8295, 0.3416);
positions[7] = Vec3(2.3722, 1.7711, 1.7518);
ASSERT_EQUAL(0, integrator.getCurrentIntegrator());
vector<Vec3> positions(2);
positions[0] = Vec3(-1, 0, 0);
positions[1] = Vec3(1, 0, 0);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
// Take a small step in the direction of the energy gradient.
double norm = 0.0;
double forceSum[3] = { 0.0, 0.0, 0.0 };
for (int i = 0; i < numParticles; ++i) {
Vec3 f = state.getForces()[i];
norm += f[0]*f[0] + f[1]*f[1] + f[2]*f[2];
forceSum[0] += f[0];
forceSum[1] += f[1];
forceSum[2] += f[2];
// Integrate with the first Verlet integrator and compare it to the analytical solution.
const double freq = 1.0;
double expectedTime = 0;
for (int i = 0; i < 100; ++i) {
State state = context.getState(State::Positions);
double time = state.getTime();
ASSERT_EQUAL_TOL(expectedTime, time, 1e-5);
double expectedDist = 1.5+0.5*std::cos(freq*time);
ASSERT_EQUAL_VEC(Vec3(-0.5*expectedDist, 0, 0), state.getPositions()[0], 0.02);
ASSERT_EQUAL_VEC(Vec3(0.5*expectedDist, 0, 0), state.getPositions()[1], 0.02);
integrator.step(1);
expectedTime += 0.005;
}
norm = std::sqrt(norm);
const double delta = 1e-4;
double step = delta/norm;
for (int i = 0; i < numParticles; ++i) {
Vec3 p = positions[i];
Vec3 f = state.getForces()[i];
positions[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step);
}
context.setPositions(positions);
State state2 = context.getState(State::Energy);
// See whether the potential energy changed by the expected amount.
// Now switch to the second Verlet integrator which has a different step size.
integrator.setCurrentIntegrator(1);
for (int i = 0; i < 100; ++i) {
State state = context.getState(State::Positions);
double time = state.getTime();
ASSERT_EQUAL_TOL(expectedTime, time, 1e-5);
double expectedDist = 1.5+0.5*std::cos(freq*time);
ASSERT_EQUAL_VEC(Vec3(-0.5*expectedDist, 0, 0), state.getPositions()[0], 0.02);
ASSERT_EQUAL_VEC(Vec3(0.5*expectedDist, 0, 0), state.getPositions()[1], 0.02);
integrator.step(1);
expectedTime += 0.01;
}
ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state.getPotentialEnergy())/delta, 0.01)
// Finally, switch back to the first one again.
integrator.setCurrentIntegrator(0);
for (int i = 0; i < 100; ++i) {
State state = context.getState(State::Positions);
double time = state.getTime();
ASSERT_EQUAL_TOL(expectedTime, time, 1e-5);
double expectedDist = 1.5+0.5*std::cos(freq*time);
ASSERT_EQUAL_VEC(Vec3(-0.5*expectedDist, 0, 0), state.getPositions()[0], 0.02);
ASSERT_EQUAL_VEC(Vec3(0.5*expectedDist, 0, 0), state.getPositions()[1], 0.02);
integrator.step(1);
expectedTime += 0.005;
}
}
int main() {
void runPlatformTests();
int main(int argc, char* argv[]) {
try {
testSingleParticle();
testEnergyEthane(0);
testEnergyEthane(1);
initializeTests(argc, argv);
testChangingIntegrator();
testChangingParameters();
testDifferentStepSizes();
runPlatformTests();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
......
......@@ -167,6 +167,38 @@ void testPeriodic() {
}
}
void testZeroPeriodicDistance() {
Vec3 vx(5, 0, 0);
Vec3 vy(0, 6, 0);
Vec3 vz(1, 2, 7);
double x0 = 51, y0 = -17, z0 = 11.2;
System system;
system.setDefaultPeriodicBoxVectors(vx, vy, vz);
system.addParticle(1.0);
CustomExternalForce* force = new CustomExternalForce("periodicdistance(x, y, z, x0, y0, z0)^2");
force->addPerParticleParameter("x0");
force->addPerParticleParameter("y0");
force->addPerParticleParameter("z0");
vector<double> params(3);
params[0] = x0;
params[1] = y0;
params[2] = z0;
force->addParticle(0, params);
system.addForce(force);
ASSERT(force->usesPeriodicBoundaryConditions());
ASSERT(system.usesPeriodicBoundaryConditions());
VerletIntegrator integrator(0.01);
Context context(system, integrator, platform);
vector<Vec3> positions(1);
positions[0] = Vec3(x0, y0, z0);
context.setPositions(positions);
State state = context.getState(State::Positions | State::Forces | State::Energy);
vector<Vec3> forces = state.getForces();
for (int i = 0; i < 3; i++)
ASSERT_EQUAL(forces[0][i], forces[0][i]);
}
void testIllegalVariable() {
System system;
system.addParticle(1.0);
......@@ -192,6 +224,7 @@ int main(int argc, char* argv[]) {
testForce();
testManyParameters();
testPeriodic();
testZeroPeriodicDistance();
testIllegalVariable();
runPlatformTests();
}
......
......@@ -6,8 +6,8 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2010-2014 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Portions copyright (c) 2010-2015 Stanford University and the Authors. *
* Authors: Robert McGibbon *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
......@@ -30,74 +30,61 @@
* -------------------------------------------------------------------------- */
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/GBVIForce.h"
#include "openmm/serialization/XmlSerializer.h"
#include "openmm/Context.h"
#include "openmm/NonbondedForce.h"
#include "openmm/Platform.h"
#include "openmm/VerletIntegrator.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <sstream>
using namespace OpenMM;
using namespace std;
void testSerialization() {
// Create a Force.
GBVIForce force;
force.setForceGroup(3);
force.setNonbondedMethod(GBVIForce::CutoffPeriodic);
force.setBornRadiusScalingMethod(GBVIForce::QuinticSpline);
force.setQuinticLowerLimitFactor(0.123);
force.setQuinticUpperBornRadiusLimit(5.123);
force.setCutoffDistance(2.0);
force.setSoluteDielectric(5.1);
force.setSolventDielectric(50.0);
force.addParticle(1, 0.1, 0.01);
force.addParticle(0.5, 0.2, 0.02);
force.addParticle(-0.5, 0.3, 0.03);
force.addBond(0, 1, 2.0);
force.addBond(3, 5, 1.2);
// Serialize and then deserialize it.
stringstream buffer;
XmlSerializer::serialize<GBVIForce>(&force, "Force", buffer);
GBVIForce* copy = XmlSerializer::deserialize<GBVIForce>(buffer);
void testTruncatedOctahedron() {
const int numMolecules = 5;
const int numParticles = numMolecules*2;
const float cutoff = 2.0;
Vec3 a(6.7929, 0, 0);
Vec3 b(-2.264163559406279, 6.404455775962287, 0);
Vec3 c(-2.264163559406279, -3.2019384603140684, 5.54658849047036);
System system;
system.setDefaultPeriodicBoxVectors(a, b, c);
NonbondedForce* force = new NonbondedForce();
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
vector<Vec3> positions(numParticles);
force->setCutoffDistance(cutoff);
force->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
for (int i = 0; i < numMolecules; i++) {
system.addParticle(1.0);
system.addParticle(1.0);
force->addParticle(-1, 0.2, 0.2);
force->addParticle(1, 0.2, 0.2);
positions[2*i] = a*genrand_real2(sfmt) + b*genrand_real2(sfmt) + c*genrand_real2(sfmt);
positions[2*i+1] = positions[2*i] + Vec3(1.0, 0.0, 0.0);
system.addConstraint(2*i, 2*i+1, 1.0);
}
system.addForce(force);
VerletIntegrator integrator(0.01);
Context context(system, integrator, Platform::getPlatformByName("Reference"));
context.setPositions(positions);
State initialState = context.getState(State::Positions | State::Energy, true);
double initialEnergy = initialState.getPotentialEnergy();
// Compare the two forces to see if they are identical.
context.setState(initialState);
State finalState = context.getState(State::Positions | State::Energy, true);
double finalEnergy = finalState.getPotentialEnergy();
GBVIForce& force2 = *copy;
ASSERT_EQUAL(force.getForceGroup(), force2.getForceGroup());
ASSERT_EQUAL(force.getNonbondedMethod(), force2.getNonbondedMethod());
ASSERT_EQUAL(force.getCutoffDistance(), force2.getCutoffDistance());
ASSERT_EQUAL(force.getSoluteDielectric(), force2.getSoluteDielectric());
ASSERT_EQUAL(force.getSolventDielectric(), force2.getSolventDielectric());
ASSERT_EQUAL(force.getNumParticles(), force2.getNumParticles());
ASSERT_EQUAL(force.getQuinticUpperBornRadiusLimit(), force2.getQuinticUpperBornRadiusLimit());
ASSERT_EQUAL(force.getQuinticLowerLimitFactor(), force2.getQuinticLowerLimitFactor());
ASSERT_EQUAL(force.getBornRadiusScalingMethod(), force2.getBornRadiusScalingMethod());
for (int i = 0; i < force.getNumParticles(); i++) {
double charge1, radius1, scale1;
double charge2, radius2, scale2;
force.getParticleParameters(i, charge1, radius1, scale1);
force2.getParticleParameters(i, charge2, radius2, scale2);
ASSERT_EQUAL(charge1, charge2);
ASSERT_EQUAL(radius1, radius2);
ASSERT_EQUAL(scale1, scale2);
}
ASSERT_EQUAL(force.getNumBonds(), force2.getNumBonds());
for (int i = 0; i < force.getNumBonds(); i++) {
int a1, a2, b1, b2;
double da, db;
force.getBondParameters(i, a1, a2, da);
force2.getBondParameters(i, b1, b2, db);
ASSERT_EQUAL(a1, b1);
ASSERT_EQUAL(a2, b2);
ASSERT_EQUAL(da, db);
}
ASSERT_EQUAL_TOL(initialEnergy, finalEnergy, 1e-4);
}
int main() {
int main(int argc, char* argv[]) {
try {
testSerialization();
testTruncatedOctahedron();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
......
......@@ -255,7 +255,7 @@ void testForce(int numParticles, NonbondedForce::NonbondedMethod method, GBSAOBC
State state2 = context.getState(State::Energy);
context.setPositions(positions3);
State state3 = context.getState(State::Energy);
ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/delta, 1e-2)
ASSERT_EQUAL_TOL(state2.getPotentialEnergy(), state3.getPotentialEnergy()+norm*delta, 1e-5)
}
}
......
......@@ -78,7 +78,7 @@ void testLargeSystem() {
const int numParticles = numMolecules*2;
const double cutoff = 2.0;
const double boxSize = 4.0;
const double tolerance = 10;
const double tolerance = 15;
System system;
system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
NonbondedForce* nonbonded = new NonbondedForce();
......
from __future__ import print_function
import re
import sys
import textwrap
from inspect import cleandoc
from numpydoc.docscrape import NumpyDocString
# Doxygen does a bad job of generating documentation based on docstrings. This script is run as a filter
# on each file, and converts the docstrings into Doxygen style comments so we get better documentation.
# Doxygen does a bad job of generating documentation based on docstrings.
# This script is run as a filter
# on each file, and converts the docstrings into Doxygen style comments
# so we get better documentation.
input = open(sys.argv[1])
while True:
line = input.readline()
if len(line) == 0:
......@@ -15,46 +24,57 @@ while True:
split = stripped.split()
if split[0] == 'class' and split[1][0].islower():
# Classes that start with a lowercase letter were defined by SWIG. We want to hide them.
print("%s## @private" % prefix)
print("%s## @private" % prefix, end='')
if split[1][0] == '_' and split[1][1] != '_':
# Names starting with a single _ are assumed to be private.
print("%s## @private" % prefix)
print("%s## @private" % prefix, end='')
# We're at the start of a class or function definition. Find all lines that contain the declaration.
declaration = line
while len(line) > 0 and line.find(':') == -1:
line = input.readline()
declaration += line
# Now look for a docstring.
docstrings = []
docstringlines = []
line = input.readline()
stripped = line.lstrip()
if stripped.startswith('"""'):
line = stripped[3:]
readingParameters = False
while line.find('"""') == -1:
docstrings.append(line)
l = line.strip()
if l.startswith('"""') or l.startswith("'''"):
if l.count('"""') == 2 or l.count("'''") == 2:
docstringlines.append(l[3:-3])
else:
docstringlines.append(l[3:])
line = input.readline()
if line.strip() == 'Parameters:':
readingParameters = True
l = line.strip()
while l.find('"""') == -1 and l.find("'''") == -1:
docstringlines.append(line.rstrip())
line = input.readline()
stripped = line.lstrip()
if readingParameters and stripped.startswith('- '):
line = "@param %s" % stripped[2:]
elif stripped.startswith('Returns:'):
line = "@return %s" % stripped[8:]
line = line[:line.find('"""')]
docstrings.append(line)
l = line.strip()
if line.rstrip().endswith('"""') or line.rstrip().endswith("'''"):
# last line
docstringlines.append(line.rstrip()[:-3])
docstring = NumpyDocString(cleandoc('\n'.join(docstringlines)))
# print(docstringlines)
# Print out the docstring in Doxygen syntax, followed by the declaration.
for s in docstrings:
print("%s##%s" % (prefix, s.strip()))
print(declaration)
if len(docstrings) == 0:
print(line)
for line in docstring['Summary']:
print('{prefix}## {line}'.format(prefix=prefix, line=line))
if len(docstring['Extended Summary']) > 0:
print('{prefix}##'.format(prefix=prefix))
for line in docstring['Extended Summary']:
print('{prefix}## {line}'.format(prefix=prefix, line=line.strip()))
print('{prefix}##'.format(prefix=prefix))
for name, type, descr in docstring['Parameters']:
print('{prefix}## @param {name} ({type}) {descr}'.format(prefix=prefix, type=type, name=name, descr=' '.join(descr)))
for name, type, descr in docstring['Returns']:
if type == '':
type = name
print('{prefix}## @return ({type}) {descr}'.format(prefix=prefix, type=type, name=name, descr=' '.join(descr)))
print(declaration, end='')
if len(docstringlines) == 0:
print(line, end='')
else:
print(line)
\ No newline at end of file
print(line, end='')
......@@ -10,7 +10,7 @@ Portions copyright (c) 2012 Stanford University and the Authors.
Authors: Peter Eastman, Steffen Lindert
Contributors:
Permission is hereby granted, free of charge, to any person obtaining a
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,
......@@ -37,22 +37,26 @@ from simtk.unit import kilojoules_per_mole, is_quantity
class AMDIntegrator(CustomIntegrator):
"""AMDIntegrator implements the aMD integration algorithm.
The system is integrated based on a modified potential. Whenever the energy V(r) is less than a
cutoff value E, the following effective potential is used:
V*(r) = V(r) + (E-V(r))^2 / (alpha+E-V(r))
For details, see Hamelberg et al., J. Chem. Phys. 127, 155102 (2007).
"""
def __init__(self, dt, alpha, E):
"""Create an AMDIntegrator.
Parameters:
- dt (time) The integration time step to use
- alpha (energy) The alpha parameter to use
- E (energy) The energy cutoff to use
Parameters
----------
dt : time
The integration time step to use
alpha : energy
The alpha parameter to use
E : energy
The energy cutoff to use
"""
CustomIntegrator.__init__(self, dt)
self.addGlobalVariable("alpha", alpha)
......@@ -64,23 +68,23 @@ class AMDIntegrator(CustomIntegrator):
self.addComputePerDof("x", "x+dt*v")
self.addConstrainPositions()
self.addComputePerDof("v", "(x-oldx)/dt")
def getAlpha(self):
"""Get the value of alpha for the integrator."""
return self.getGlobalVariable(0)*kilojoules_per_mole
def setAlpha(self, alpha):
"""Set the value of alpha for the integrator."""
self.setGlobalVariable(0, alpha)
def getE(self):
"""Get the energy threshold E for the integrator."""
return self.getGlobalVariable(1)*kilojoules_per_mole
def setE(self, E):
"""Set the energy threshold E for the integrator."""
self.setGlobalVariable(1, E)
def getEffectiveEnergy(self, energy):
"""Given the actual potential energy of the system, return the value of the effective potential."""
alpha = self.getAlpha()
......@@ -94,21 +98,26 @@ class AMDIntegrator(CustomIntegrator):
class AMDForceGroupIntegrator(CustomIntegrator):
"""AMDForceGroupIntegrator implements a single boost aMD integration algorithm.
This is similar to AMDIntegrator, but is applied based on the energy of a single force group
(typically representing torsions).
For details, see Hamelberg et al., J. Chem. Phys. 127, 155102 (2007).
"""
def __init__(self, dt, group, alphaGroup, EGroup):
"""Create a AMDForceGroupIntegrator.
Parameters:
- dt (time) The integration time step to use
- group (int) The force group to apply the boost to
- alphaGroup (energy) The alpha parameter to use for the boosted force group
- EGroup (energy) The energy cutoff to use for the boosted force group
Parameters
----------
dt : time
The integration time step to use
group : int
The force group to apply the boost to
alphaGroup : energy
The alpha parameter to use for the boosted force group
EGroup : energy
The energy cutoff to use for the boosted force group
"""
CustomIntegrator.__init__(self, dt)
self.addGlobalVariable("alphaGroup", alphaGroup)
......@@ -124,29 +133,35 @@ class AMDForceGroupIntegrator(CustomIntegrator):
self.addComputePerDof("x", "x+dt*v")
self.addConstrainPositions()
self.addComputePerDof("v", "(x-oldx)/dt")
def getAlphaGroup(self):
"""Get the value of alpha for the boosted force group."""
return self.getGlobalVariable(0)*kilojoules_per_mole
def setAlphaGroup(self, alpha):
"""Set the value of alpha for the boosted force group."""
self.setGlobalVariable(0, alpha)
def getEGroup(self):
"""Get the energy threshold E for the boosted force group."""
return self.getGlobalVariable(1)*kilojoules_per_mole
def setEGroup(self, E):
"""Set the energy threshold E for the boosted force group."""
self.setGlobalVariable(1, E)
def getEffectiveEnergy(self, groupEnergy):
"""Given the actual group energy of the system, return the value of the effective potential.
Parameters:
- groupEnergy (energy): the actual potential energy of the boosted force group
Returns: the value of the effective potential
Parameters
----------
groupEnergy : energy
the actual potential energy of the boosted force group
Returns
-------
energy
the value of the effective potential
"""
alphaGroup = self.getAlphaGroup()
EGroup = self.getEGroup()
......@@ -161,24 +176,31 @@ class AMDForceGroupIntegrator(CustomIntegrator):
class DualAMDIntegrator(CustomIntegrator):
"""DualAMDIntegrator implements a dual boost aMD integration algorithm.
This is similar to AMDIntegrator, but two different boosts are applied to the potential:
one based on the total energy, and one based on the energy of a single force group
(typically representing torsions).
For details, see Hamelberg et al., J. Chem. Phys. 127, 155102 (2007).
"""
def __init__(self, dt, group, alphaTotal, ETotal, alphaGroup, EGroup):
"""Create a DualAMDIntegrator.
Parameters:
- dt (time) The integration time step to use
- group (int) The force group to apply the second boost to
- alphaTotal (energy) The alpha parameter to use for the total energy
- ETotal (energy) The energy cutoff to use for the total energy
- alphaGroup (energy) The alpha parameter to use for the boosted force group
- EGroup (energy) The energy cutoff to use for the boosted force group
Parameters
----------
dt : time
The integration time step to use
group : int
The force group to apply the second boost to
alphaTotal : energy
The alpha parameter to use for the total energy
ETotal : energy
The energy cutoff to use for the total energy
alphaGroup : energy
The alpha parameter to use for the boosted force group
EGroup : energy
The energy cutoff to use for the boosted force group
"""
CustomIntegrator.__init__(self, dt)
self.addGlobalVariable("alphaTotal", alphaTotal)
......@@ -201,46 +223,53 @@ class DualAMDIntegrator(CustomIntegrator):
self.addComputePerDof("x", "x+dt*v")
self.addConstrainPositions()
self.addComputePerDof("v", "(x-oldx)/dt")
def getAlphaTotal(self):
"""Get the value of alpha for the total energy."""
return self.getGlobalVariable(0)*kilojoules_per_mole
def setAlphaTotal(self, alpha):
"""Set the value of alpha for the total energy."""
self.setGlobalVariable(0, alpha)
def getETotal(self):
"""Get the energy threshold E for the total energy."""
return self.getGlobalVariable(1)*kilojoules_per_mole
def setETotal(self, E):
"""Set the energy threshold E for the total energy."""
self.setGlobalVariable(1, E)
def getAlphaGroup(self):
"""Get the value of alpha for the boosted force group."""
return self.getGlobalVariable(2)*kilojoules_per_mole
def setAlphaGroup(self, alpha):
"""Set the value of alpha for the boosted force group."""
self.setGlobalVariable(2, alpha)
def getEGroup(self):
"""Get the energy threshold E for the boosted force group."""
return self.getGlobalVariable(3)*kilojoules_per_mole
def setEGroup(self, E):
"""Set the energy threshold E for the boosted force group."""
self.setGlobalVariable(3, E)
def getEffectiveEnergy(self, totalEnergy, groupEnergy):
"""Given the actual potential energy of the system, return the value of the effective potential.
Parameters:
- totalEnergy (energy): the actual potential energy of the whole system
- groupEnergy (energy): the actual potential energy of the boosted force group
Returns: the value of the effective potential
Parameters
----------
totalEnergy : energy
the actual potential energy of the whole system
groupEnergy : energy
the actual potential energy of the boosted force group
Returns
-------
energy
the value of the effective potential
"""
alphaTotal = self.getAlphaTotal()
ETotal = self.getETotal()
......
......@@ -60,12 +60,17 @@ class AmberInpcrdFile(object):
def __init__(self, file, loadVelocities=None, loadBoxVectors=None):
"""Load an inpcrd file.
An inpcrd file contains atom positions and, optionally, velocities and periodic box dimensions.
Parameters:
- file (string) the name of the file to load
- loadVelocities (boolean=None) deprecated. Velocities are loaded automatically if present
- loadBoxVectors (boolean=None) deprecated. Box vectors are loaded automatically if present
An inpcrd file contains atom positions and, optionally, velocities and
periodic box dimensions.
Parameters
----------
file : str
The name of the file to load
loadVelocities : bool
Deprecated. Velocities are loaded automatically if present
loadBoxVectors : bool
Deprecated. Box vectors are loaded automatically if present
"""
self.file = file
if loadVelocities is not None or loadBoxVectors is not None:
......@@ -84,8 +89,11 @@ class AmberInpcrdFile(object):
def getPositions(self, asNumpy=False):
"""Get the atomic positions.
Parameters:
- asNumpy (boolean=False) if true, the values are returned as a numpy array instead of a list of Vec3s
Parameters
----------
asNumpy : bool=False
if true, the values are returned as a numpy array instead of a list
of Vec3s
"""
if asNumpy:
if self._numpyPositions is None:
......@@ -97,8 +105,10 @@ class AmberInpcrdFile(object):
def getVelocities(self, asNumpy=False):
"""Get the atomic velocities.
Parameters:
- asNumpy (boolean=False) if true, the vectors are returned as numpy arrays instead of Vec3s
Parameters
----------
asNumpy : bool=False
if true, the vectors are returned as numpy arrays instead of Vec3s
"""
if self.velocities is None:
raise AttributeError('velocities not found in %s' % self.file)
......@@ -112,8 +122,11 @@ class AmberInpcrdFile(object):
def getBoxVectors(self, asNumpy=False):
"""Get the periodic box vectors.
Parameters:
- asNumpy (boolean=False) if true, the values are returned as a numpy array instead of a list of Vec3s
Parameters
----------
asNumpy : bool=False
if true, the values are returned as a numpy array instead of a list
of Vec3s
"""
if self.boxVectors is None:
raise AttributeError('Box information not found in %s' % self.file)
......
......@@ -69,6 +69,15 @@ class GBn2(object):
return 'GBn2'
GBn2 = GBn2()
def _strip_optunit(thing, unit):
"""
Strips optional units, converting to specified unit type. If no unit
present, it just returns the number
"""
if u.is_quantity(thing):
return thing.value_in_unit(unit)
return thing
class AmberPrmtopFile(object):
"""AmberPrmtopFile parses an AMBER prmtop file and constructs a Topology and (optionally) an OpenMM System from it."""
......@@ -150,36 +159,59 @@ class AmberPrmtopFile(object):
implicitSolventSaltConc=0.0*(unit.moles/unit.liter),
implicitSolventKappa=None, temperature=298.15*unit.kelvin,
soluteDielectric=1.0, solventDielectric=78.5,
removeCMMotion=True, hydrogenMass=None, ewaldErrorTolerance=0.0005, switchDistance=0.0*unit.nanometer):
"""Construct an OpenMM System representing the topology described by this prmtop file.
Parameters:
- nonbondedMethod (object=NoCutoff) The method to use for nonbonded interactions. Allowed values are
NoCutoff, CutoffNonPeriodic, CutoffPeriodic, Ewald, or PME.
- nonbondedCutoff (distance=1*nanometer) The cutoff distance to use for nonbonded interactions
- constraints (object=None) Specifies which bonds angles should be implemented with constraints.
Allowed values are None, HBonds, AllBonds, or HAngles.
- rigidWater (boolean=True) If true, water molecules will be fully rigid regardless of the value passed for the constraints argument
- implicitSolvent (object=None) If not None, the implicit solvent model to use. Allowed values are HCT, OBC1, OBC2, GBn, or GBn2.
- implicitSolventSaltConc (float=0.0*unit.moles/unit.liter) The salt concentration for GB
calculations (modelled as a debye screening parameter). It is converted to the debye length (kappa)
using the provided temperature and solventDielectric
- temperature (float=300*kelvin) Temperature of the system. Only used to compute the Debye length from
implicitSolventSoltConc
- implicitSolventKappa (float units of 1/length) If this value is set, implicitSolventSaltConc will be ignored.
- soluteDielectric (float=1.0) The solute dielectric constant to use in the implicit solvent model.
- solventDielectric (float=78.5) The solvent dielectric constant to use in the implicit solvent model.
- removeCMMotion (boolean=True) If true, a CMMotionRemover will be added to the System
- hydrogenMass (mass=None) The mass to use for hydrogen atoms bound to heavy atoms. Any mass added to a hydrogen is
subtracted from the heavy atom to keep their total mass the same.
- ewaldErrorTolerance (float=0.0005) The error tolerance to use if nonbondedMethod is Ewald or PME.
- switchDistance (distance=0*nanometer) The distance at which the
switching function is active for nonbonded interactions. If the
switchDistance evaluates to boolean False (if it is 0), no
switching function will be used. Illegal values will raise a
ValueError
Returns: the newly created System
removeCMMotion=True, hydrogenMass=None, ewaldErrorTolerance=0.0005,
switchDistance=0.0*unit.nanometer):
"""Construct an OpenMM System representing the topology described by this
prmtop file.
Parameters
----------
nonbondedMethod : object=NoCutoff
The method to use for nonbonded interactions. Allowed values are
NoCutoff, CutoffNonPeriodic, CutoffPeriodic, Ewald, or PME.
nonbondedCutoff : distance=1*nanometer
The cutoff distance to use for nonbonded interactions
constraints : object=None
Specifies which bonds angles should be implemented with constraints.
Allowed values are None, HBonds, AllBonds, or HAngles.
rigidWater : boolean=True
If true, water molecules will be fully rigid regardless of the value
passed for the constraints argument
implicitSolvent : object=None
If not None, the implicit solvent model to use. Allowed values are
HCT, OBC1, OBC2, GBn, or GBn2.
implicitSolventSaltConc : float=0.0*unit.moles/unit.liter
The salt concentration for GB calculations (modelled as a debye
screening parameter). It is converted to the debye length (kappa)
using the provided temperature and solventDielectric
temperature : float=300*kelvin
Temperature of the system. Only used to compute the Debye length
from implicitSolventSoltConc
implicitSolventKappa : float units of 1/length
If this value is set, implicitSolventSaltConc will be ignored.
soluteDielectric : float=1.0
The solute dielectric constant to use in the implicit solvent model.
solventDielectric : float=78.5
The solvent dielectric constant to use in the implicit solvent
model.
removeCMMotion : boolean=True
If true, a CMMotionRemover will be added to the System
hydrogenMass : mass=None
The mass to use for hydrogen atoms bound to heavy atoms. Any mass
added to a hydrogen is subtracted from the heavy atom to keep their
total mass the same.
ewaldErrorTolerance : float=0.0005
The error tolerance to use if nonbondedMethod is Ewald or PME.
switchDistance : float=0*nanometers
A positive value turns on a potential energy switching function for
Lennard-Jones interactions. If the switchDistance is 0 or evaluates
to boolean False, no switching function will be used. Illegal values
(e.g., less than 0) will raise a ValueError
Returns
-------
System
the newly created System
"""
if self._prmtop.chamber:
raise ValueError("CHAMBER-style topology file detected. CHAMBER "
......@@ -257,13 +289,14 @@ class AmberPrmtopFile(object):
if switchDistance and nonbondedMethod is not ff.NoCutoff:
# make sure it's legal
if switchDistance >= nonbondedCutoff:
if (_strip_optunit(switchDistance, u.nanometer) >=
_strip_optunit(nonbondedCutoff, u.nanometer)):
raise ValueError('switchDistance is too large compared '
'to the cutoff!')
if abs(switchDistance) != switchDistance:
# Detects negatives for both Quantity and float
raise ValueError('switchDistance must be non-negative!')
force.setUseSwitchingFunction(True)
force.setSwitchingDistance(switchDistance)
'to the cutoff!')
if _strip_optunit(switchDistance, u.nanometer) < 0:
# Detects negatives for both Quantity and float
raise ValueError('switchDistance must be non-negative!')
force.setUseSwitchingFunction(True)
force.setSwitchingDistance(switchDistance)
return sys
"""
Provides a class for parsing CHARMM-style coordinate files, namely CHARMM .crd
(coordinate) files and CHARMM .rst (restart) file. Uses CharmmFile class in
_charmmfile.py for reading files
_charmmfile.py for reading files
This file is part of the OpenMM molecular simulation toolkit originating from
Simbios, the NIH National Center for Physics-Based Simulation of Biological
......@@ -49,12 +49,17 @@ class CharmmCrdFile(object):
Reads and parses a CHARMM coordinate file (.crd) into its components,
namely the coordinates, CHARMM atom types, resid, resname, etc.
Main attributes:
- natom (int) : Number of atoms in the system
- resname (list) : Names of all residues
- positions (list) : All cartesian coordinates [x1, y1, z1, x2, ...]
Example:
Attributes
----------
natom : int
Number of atoms in the system
resname : list
Names of all residues
positions : list
All cartesian coordinates [x1, y1, z1, x2, ...]
Examples
--------
>>> chm = CharmmCrdFile('testfiles/1tnm.crd')
>>> print '%d atoms; %d coords' % (chm.natom, len(chm.positions))
1414 atoms; 1414 coords
......@@ -91,15 +96,15 @@ class CharmmCrdFile(object):
intitle = False
elif line.strip()[0] != '*':
intitle = False
else:
else:
intitle = True
while len(line.strip()) == 0: # Skip whitespace
line = crdfile.readline()
try:
self.natom = int(line.strip().split()[0])
for row in range(self.natom):
line = crdfile.readline().strip().split()
self.atomno.append(int(line[0]))
......@@ -131,14 +136,21 @@ class CharmmRstFile(object):
Reads and parses data, velocities and coordinates from a CHARMM restart
file (.rst) of file name 'fname' into class attributes
Main attributes:
- natom (int) : Number of atoms in the system
- resname (list) : Names of all residues
- positions (list) : All cartesian coordinates [x1, y1, z1, x2, ...]
- positionsold (list) : Old cartesian coordinates
- velocities (list) : List of all cartesian velocities
Example:
Attributes
----------
natom : int
Number of atoms in the system
resname : list
Names of all residues
positions : list
All cartesian coordinates [x1, y1, z1, x2, ...]
positionsold : list
Old cartesian coordinates
velocities : list
List of all cartesian velocities
Examples
--------
>>> chm = CharmmRstFile('testfiles/sample-charmm.rst')
>>> print chm.header[0]
REST 37 1
......@@ -155,7 +167,7 @@ class CharmmRstFile(object):
self.positionsold = []
self.positions = []
self.velocities = []
self.ff_version = 0
self.natom = 0
self.npriv = 0
......@@ -169,7 +181,7 @@ class CharmmRstFile(object):
def _parse(self, fname):
crdfile = open(fname, 'r')
readingHeader = True
readingHeader = True
while readingHeader:
line = crdfile.readline()
......@@ -177,7 +189,7 @@ class CharmmRstFile(object):
raise CharmmFileError('Premature end of file')
line = line.strip()
words = line.split()
if len(line) != 0:
if len(line) != 0:
if words[0] == 'ENERGIES' or words[0] == '!ENERGIES':
readingHeader = False
else:
......@@ -191,14 +203,14 @@ class CharmmRstFile(object):
if line[0][0:5] == 'NATOM' or line[0][0:6] == '!NATOM':
try:
line = self.header[row+1].strip().split()
self.natom = int(line[0])
self.natom = int(line[0])
self.npriv = int(line[1]) # num. previous steps
self.nstep = int(line[2]) # num. steps in file
self.nsavc = int(line[3]) # coord save frequency
self.nstep = int(line[2]) # num. steps in file
self.nsavc = int(line[3]) # coord save frequency
self.nsavv = int(line[4]) # velocities "
self.jhstrt = int(line[5]) # Num total steps?
break
except (ValueError, IndexError) as e:
raise CharmmFileError('Problem parsing CHARMM restart')
......@@ -244,7 +256,7 @@ class CharmmRstFile(object):
if len(line) < 3*CHARMMLEN:
raise CharmmFileError("Less than 3 coordinates present in "
"coordinate row or positions may be "
"truncated.")
"truncated.")
line = line.replace('D','E') # CHARMM uses 'D' for exponentials
......
......@@ -51,41 +51,43 @@ class CharmmParameterSet(object):
the information found in the MASS section of the CHARMM topology file
(TOP/RTF) and all of the information in the parameter files (PAR)
Parameters:
- filenames : List of topology, parameter, and stream files to load into
the parameter set. The following file type suffixes are recognized.
Unrecognized file types raise a TypeError
.rtf, .top -- Residue topology file
.par, .prm -- Parameter file
.str -- Stream file
.inp -- If "par" is in the file name, it is a parameter file. If
Parameters
----------
filenames : List of topology, parameter, and stream files to load into the parameter set.
The following file type suffixes are recognized. Unrecognized file types raise a TypeError
* .rtf, .top -- Residue topology file
* .par, .prm -- Parameter file
* .str -- Stream file
* .inp -- If "par" is in the file name, it is a parameter file. If
"top" is in the file name, it is a topology file. Otherwise,
raise TypeError
Attributes:
All type lists are dictionaries whose keys are tuples (with however
many elements are needed to define that type of parameter). The types
that can be in any order are SORTED.
- atom_types_str
- atom_types_int
- atom_types_tuple
- bond_types
- angle_types
- urey_bradley_types
- dihedral_types
- improper_types
- cmap_types
- nbfix_types
The dihedral types can be multiterm, so the values for each dict key is
actually a list of DihedralType instances. The atom_types are dicts that
match the name (str), number (int), or (name, number) tuple (tuple) to
the atom type. The tuple is guaranteed to be the most robust, although
when only the integer or string is available the other dictionaries are
helpful
Example:
Attributes
----------
All type lists are dictionaries whose keys are tuples (with however
many elements are needed to define that type of parameter). The types
that can be in any order are SORTED.
- atom_types_str
- atom_types_int
- atom_types_tuple
- bond_types
- angle_types
- urey_bradley_types
- dihedral_types
- improper_types
- cmap_types
- nbfix_types
The dihedral types can be multiterm, so the values for each dict key is
actually a list of DihedralType instances. The atom_types are dicts that
match the name (str), number (int), or (name, number) tuple (tuple) to
the atom type. The tuple is guaranteed to be the most robust, although
when only the integer or string is available the other dictionaries are
helpful
Examples
--------
>>> params = CharmmParameterSet('charmm22.top', 'charmm22.par', 'file.str')
"""
......@@ -113,7 +115,7 @@ class CharmmParameterSet(object):
self.cmap_types = dict()
self.nbfix_types = dict()
self.parametersets = []
# Load all of the files
tops, pars, strs = [], [], []
for arg in args:
......@@ -150,23 +152,30 @@ class CharmmParameterSet(object):
Instantiates a CharmmParameterSet from a Topology file and a Parameter
file (or just a Parameter file if it has all information)
Parameters:
- tfile (str) : Name of the Topology (RTF/TOP) file
- pfile (str) : Name of the Parameter (PAR) file
- sfiles (list of str) : List or tuple of stream (STR) file names.
- permissive (bool) : Accept non-bonbded parameters for undefined
atom types (default False)
Returns:
Parameters
-----------
tfile : str
Name of the Topology (RTF/TOP) file
pfile : str
Name of the Parameter (PAR) file
sfiles : list of str
List or tuple of stream (STR) file names.
permissive : bool=False
Accept non-bonbded parameters for undefined atom types
Returns
-------
CharmmParameterSet
New CharmmParameterSet populated with the parameters found in the
provided files.
Notes:
The RTF file is read first (if provided), followed by the PAR file,
followed by the list of stream files (in the order they are
provided). Parameters in each stream file will overwrite those that
came before (or simply append to the existing set if they are
different)
Notes
-----
The RTF file is read first (if provided), followed by the PAR file,
followed by the list of stream files (in the order they are
provided). Parameters in each stream file will overwrite those that
came before (or simply append to the existing set if they are
different)
"""
inst = cls()
if tfile is not None:
......@@ -183,21 +192,24 @@ class CharmmParameterSet(object):
return inst
def readParameterFile(self, pfile, permissive=False):
"""
Reads all of the parameters from a parameter file. Versions 36 and
later of the CHARMM force field files have an ATOMS section defining
all of the atom types. Older versions need to load this information
from the RTF/TOP files.
Parameters:
- pfile (str) : Name of the CHARMM PARameter file to read
- permissive (bool) : Accept non-bonbded parameters for undefined
atom types (default False)
Notes: The atom types must all be loaded by the end of this routine.
Either supply a PAR file with atom definitions in them or read in a
RTF/TOP file first. Failure to do so will result in a raised
RuntimeError.
"""Reads all of the parameters from a parameter file. Versions 36 and later
of the CHARMM force field files have an ATOMS section defining all of
the atom types. Older versions need to load this information from the
RTF/TOP files.
Parameters
----------
pfile : str
Name of the CHARMM PARameter file to read
permissive : bool
Accept non-bonbded parameters for undefined atom types (default:
False).
Notes
-----
The atom types must all be loaded by the end of this routine. Either
supply a PAR file with atom definitions in them or read in a RTF/TOP
file first. Failure to do so will result in a raised RuntimeError.
"""
conv = CharmmParameterSet._convert
if isinstance(pfile, str):
......@@ -353,7 +365,7 @@ class CharmmParameterSet(object):
if dtype.per == dihedral.per:
# Replace. Warn if they are different
if dtype != dihedral:
warnings.warn('Replacing dihedral %r with %r' %
warnings.warn('Replacing dihedral %r with %r' %
(dtype, dihedral))
self.dihedral_types[key]
replaced = True
......@@ -487,7 +499,7 @@ class CharmmParameterSet(object):
ty = CmapType(current_cmap_res, current_cmap_data)
self.cmap_types[current_cmap] = ty
# If in permissive mode create an atomtype for every type used in
# If in permissive mode create an atomtype for every type used in
# the nonbonded parameters. This is a work-around for when all that's
# available is a CHARMM22 inp file, which has no ATOM/MASS fields
......@@ -499,7 +511,7 @@ class CharmmParameterSet(object):
for key in nonbonded_types:
if not key in self.atom_types_str:
atype =AtomType(name=key, number=idx, mass= float('NaN'), atomic_number= 1 )
self.atom_types_str[key] = atype
self.atom_types_str[key] = atype
self.atom_types_int[idx] = atype
idx=idx+1
......@@ -518,14 +530,17 @@ class CharmmParameterSet(object):
if own_handle: f.close()
def readTopologyFile(self, tfile):
"""
Reads _only_ the atom type definitions from a topology file. This is
"""Reads _only_ the atom type definitions from a topology file. This is
unnecessary for versions 36 and later of the CHARMM force field.
Parameters:
- tfile (str) : Name of the CHARMM TOPology file to read
Parameters
----------
tfile : str
: Name of the CHARMM TOPology file to read
Note: The CHARMM TOPology file is also called a Residue Topology File
Notes
-----
The CHARMM TOPology file is also called a Residue Topology File
"""
conv = CharmmParameterSet._convert
if isinstance(tfile, str):
......@@ -564,12 +579,13 @@ class CharmmParameterSet(object):
if own_handle: f.close()
def readStreamFile(self, sfile):
"""
Reads RTF and PAR sections from a stream file and dispatches the
"""Reads RTF and PAR sections from a stream file and dispatches the
sections to readTopologyFile or readParameterFile
Parameters:
- sfile (str or CharmmStreamFile) : Stream file to parse
Parameters
----------
sfile : str or CharmmStreamFile
Stream file to parse
"""
if isinstance(sfile, CharmmStreamFile):
f = sfile
......@@ -594,14 +610,8 @@ class CharmmParameterSet(object):
bond, angle, dihedral, improper, or cmap type will pair with EVERY key
in the type mapping dictionaries that points to the equivalent type
Returns:
- Returns the instance that is being condensed.
Notes:
The return value allows you to condense the types at construction
time.
Example:
Example
-------
>>> params = CharmmParameterSet('charmm.prm').condense()
"""
# First scan through all of the bond types
......@@ -631,8 +641,10 @@ class CharmmParameterSet(object):
"""
Loops through the given dict and condenses all types.
Parameter:
- typedict : Type dictionary to condense
Parameters
----------
typedict
Type dictionary to condense
"""
keylist = list(typedict.keys())
for i in range(len(keylist) - 1):
......
......@@ -102,17 +102,22 @@ class _ZeroDict(dict):
return [0, 0], []
return 0, []
def _strip_optunit(thing, unit):
"""
Strips optional units, converting to specified unit type. If no unit
present, it just returns the number
"""
if u.is_quantity(thing):
return thing.value_in_unit(unit)
return thing
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
_resre = re.compile(r'(\d+)([a-zA-Z]*)')
class CharmmPsfFile(object):
"""
A chemical structure instantiated from CHARMM files.
"""A chemical structure instantiated from CHARMM files.
Example:
>>> cs = CharmmPsfFile("testfiles/test.psf")
This structure has numerous attributes that are lists of the elements of
this structure, including atoms, bonds, torsions, etc. The attributes are
- residue_list
......@@ -129,13 +134,14 @@ class CharmmPsfFile(object):
Additional attribute is available if a CharmmParameterSet is loaded into
this structure.
- urey_bradley_list
The lengths of each of these lists gives the pointers (e.g., natom, nres,
etc.)
Example:
Examples
--------
>>> cs = CharmmPsfFile("testfiles/test.psf")
>>> len(cs.atom_list)
33
......@@ -154,19 +160,21 @@ class CharmmPsfFile(object):
CMAP_FORCE_GROUP = 5
NONBONDED_FORCE_GROUP = 6
GB_FORCE_GROUP = 6
@_catchindexerror
def __init__(self, psf_name):
"""
Opens and parses a PSF file, then instantiates a CharmmPsfFile
"""Opens and parses a PSF file, then instantiates a CharmmPsfFile
instance from the data.
Parameters:
psf_name (str) : Name of the PSF file (it must exist)
Exceptions Raised:
IOError : If file "psf_name" does not exist
CharmmPSFError: If any parsing errors are encountered
Parameters
----------
psf_name : str
Name of the PSF file (it must exist)
Raises
------
IOError : If file "psf_name" does not exist
CharmmPSFError: If any parsing errors are encountered
"""
conv = CharmmPsfFile._convert
# Make sure the file exists
......@@ -379,14 +387,17 @@ class CharmmPsfFile(object):
@staticmethod
def _convert(string, type, message):
"""
Converts a string to a specific type, making sure to raise
"""Converts a string to a specific type, making sure to raise
CharmmPSFError with the given message in the event of a failure.
Parameters:
- string (str) : Input string to process
- type (type) : Type of data to convert to
- message (str) : Error message to put in exception if failed
Parameters
----------
string : str
Input string to process
type : type
Type of data to convert to
message : str
Error message to put in exception if failed
"""
try:
return type(string)
......@@ -396,23 +407,24 @@ class CharmmPsfFile(object):
@staticmethod
def _parse_psf_section(psf):
"""
This method parses a section of the PSF file
Parameters:
- psf (CharmmFile) : Open file that is pointing to the first line
of the section that is to be parsed
Returns:
(title, pointers, data)
- title (str) : The label of the PSF section we are parsing
- pointers (int/tuple of ints) : If one pointer is set, pointers is
simply the integer that is value of that pointer. Otherwise
it is a tuple with every pointer value defined in the first
line
- data (list) : A list of all data in the parsed section converted
to `dtype'
"""This method parses a section of the PSF file
Parameters
----------
psf : CharmmFile
Open file that is pointing to the first line of the section
that is to be parsed
Returns
--------
str
The label of the PSF section we are parsing
int/tuple of ints
If one pointer is set, pointers is simply the integer that is
value of that pointer. Otherwise it is a tuple with every pointer
value defined in the first line
list
A list of all data in the parsed section converted to `dtype'
"""
conv = CharmmPsfFile._convert
line = psf.readline()
......@@ -453,25 +465,25 @@ class CharmmPsfFile(object):
return title, pointers, data
def loadParameters(self, parmset):
"""
Loads parameters from a parameter set that was loaded via CHARMM RTF,
"""Loads parameters from a parameter set that was loaded via CHARMM RTF,
PAR, and STR files.
Parameters:
- parmset (CharmmParameterSet) : List of all parameters
Notes:
- If any parameters that are necessary cannot be found, a
MissingParameter exception is raised.
- If any dihedral or improper parameters cannot be found, I will try
inserting wildcards (at either end for dihedrals and as the two
central atoms in impropers) and see if that matches. Wild-cards
will apply ONLY if specific parameters cannot be found.
- This method will expand the dihedral_parameter_list attribute by
adding a separate Dihedral object for each term for types that
have a multi-term expansion
Parameters
----------
parmset : CharmmParameterSet
List of all parameters
Notes
-----
- If any parameters that are necessary cannot be found, a
MissingParameter exception is raised.
- If any dihedral or improper parameters cannot be found, I will try
inserting wildcards (at either end for dihedrals and as the two
central atoms in impropers) and see if that matches. Wild-cards
will apply ONLY if specific parameters cannot be found.
- This method will expand the dihedral_parameter_list attribute by
adding a separate Dihedral object for each term for types that
have a multi-term expansion
"""
# First load the atom types
types_are_int = False
......@@ -579,13 +591,22 @@ class CharmmPsfFile(object):
def setBox(self, a, b, c, alpha=90.0*u.degrees, beta=90.0*u.degrees,
gamma=90.0*u.degrees):
"""
Sets the periodic box boundary conditions.
Parameters:
- a, b, c (floats) : Lengths of the periodic cell
- alpha, beta, gamma (floats, optional) : Angles between the
periodic cell vectors.
"""Sets the periodic box boundary conditions.
Parameters
----------
a : length
Lengths of the periodic cell
b : length
Lengths of the periodic cell
c : length
Lengths of the periodic cell
alpha : floats, optional
Angles between the periodic cell vectors.
beta : floats, optional
Angles between the periodic cell vectors.
gamma : floats, optional
Angles between the periodic cell vectors.
"""
try:
# Since we are setting the box, delete the cached box lengths if we
......@@ -611,7 +632,7 @@ class CharmmPsfFile(object):
pass
# Cache the topology for easy returning later
self._topology = topology = Topology()
last_chain = None
last_residue = None
# Add each chain (separate 'system's) and residue
......@@ -743,52 +764,60 @@ class CharmmPsfFile(object):
ewaldErrorTolerance=0.0005,
flexibleConstraints=True,
verbose=False):
"""
Construct an OpenMM System representing the topology described by the
"""Construct an OpenMM System representing the topology described by the
prmtop file. You MUST have loaded a parameter set into this PSF before
calling createSystem. If not, AttributeError will be raised. ValueError
is raised for illegal input.
Parameters:
- params (CharmmParameterSet) The parameter set to use to parametrize
this molecule
- nonbondedMethod (object=NoCutoff) The method to use for nonbonded
interactions. Allowed values are NoCutoff, CutoffNonPeriodic,
CutoffPeriodic, Ewald, or PME.
- nonbondedCutoff (distance=1*nanometer) The cutoff distance to use
for nonbonded interactions.
- switchDistance (distance=0*nanometer) The distance at which the
switching function is active for nonbonded interactions. If the
switchDistance evaluates to boolean False (if it is 0), no
switching function will be used. Illegal values will raise a
ValueError
- constraints (object=None) Specifies which bonds or angles should be
implemented with constraints. Allowed values are None, HBonds,
AllBonds, or HAngles.
- rigidWater (boolean=True) If true, water molecules will be fully
rigid regardless of the value passed for the constraints argument
- implicitSolvent (object=None) If not None, the implicit solvent
model to use. Allowed values are HCT, OBC1, OBC2, or GBn
- implicitSolventKappa (float=None): Debye screening parameter to
model salt concentrations in GB solvent.
- implicitSolventSaltConc (float=0.0*u.moles/u.liter): Salt
concentration for GB simulations. Converted to Debye length
`kappa'
- temperature (float=298.15*u.kelvin): Temperature used in the salt
concentration-to-kappa conversion for GB salt concentration term
- soluteDielectric (float=1.0) The solute dielectric constant to use
in the implicit solvent model.
- solventDielectric (float=78.5) The solvent dielectric constant to
use in the implicit solvent model.
- removeCMMotion (boolean=True) If true, a CMMotionRemover will be
added to the System.
- hydrogenMass (mass=None) The mass to use for hydrogen atoms bound to
heavy atoms. Any mass added to a hydrogen is subtracted from the
heavy atom to keep their total mass the same.
- ewaldErrorTolerance (float=0.0005) The error tolerance to use if the
nonbonded method is Ewald or PME.
- flexibleConstraints (bool=True) Are our constraints flexible or not?
- verbose (bool=False) Optionally prints out a running progress report
Parameters
----------
params : CharmmParameterSet
The parameter set to use to parametrize this molecule
nonbondedMethod : object=NoCutoff
The method to use for nonbonded interactions. Allowed values are
NoCutoff, CutoffNonPeriodic, CutoffPeriodic, Ewald, or PME.
nonbondedCutoff : distance=1*nanometer
The cutoff distance to use for nonbonded interactions.
switchDistance : distance=0*nanometer
The distance at which the switching function is active for nonbonded
interactions. If the switchDistance evaluates to boolean False (if
it is 0), no switching function will be used. Illegal values will
raise a ValueError
constraints : object=None
Specifies which bonds or angles should be implemented with
constraints. Allowed values are None, HBonds, AllBonds, or HAngles.
rigidWater : boolean=True
If true, water molecules will be fully rigid regardless of the value
passed for the constraints argument
implicitSolvent : object=None
If not None, the implicit solvent model to use. Allowed values are
HCT, OBC1, OBC2, or GBn
implicitSolventKappa : float=None
Debye screening parameter to model salt concentrations in GB
solvent.
implicitSolventSaltConc : float=0.0*u.moles/u.liter
Salt concentration for GB simulations. Converted to Debye length
`kappa'
temperature : float=298.15*u.kelvin
Temperature used in the salt concentration-to-kappa conversion for
GB salt concentration term
soluteDielectric : float=1.0
The solute dielectric constant to use in the implicit solvent model.
solventDielectric : float=78.5
The solvent dielectric constant to use in the implicit solvent
model.
removeCMMotion : boolean=True
If true, a CMMotionRemover will be added to the System.
hydrogenMass : mass=None
The mass to use for hydrogen atoms bound to heavy atoms. Any mass
added to a hydrogen is subtracted from the heavy atom to keep their
total mass the same.
ewaldErrorTolerance : float=0.0005
The error tolerance to use if the nonbonded method is Ewald or PME.
flexibleConstraints : bool=True
Are our constraints flexible or not?
verbose : bool=False
Optionally prints out a running progress report
"""
# Load the parameter set
self.loadParameters(params.condense())
......@@ -812,7 +841,7 @@ class CharmmPsfFile(object):
raise ValueError('Illegal implicit solvent model choice.')
if not constraints in (None, ff.HAngles, ff.HBonds, ff.AllBonds):
raise ValueError('Illegal constraints choice')
# Define conversion factors
length_conv = u.angstrom.conversion_factor_to(u.nanometer)
_chmfrc = u.kilocalorie_per_mole/(u.angstrom*u.angstrom)
......@@ -824,7 +853,7 @@ class CharmmPsfFile(object):
dihe_frc_conv = u.kilocalorie_per_mole.conversion_factor_to(
u.kilojoule_per_mole)
ene_conv = dihe_frc_conv
# Create the system and determine if any of our atoms have NBFIX (and
# therefore requires a CustomNonbondedForce instead)
typenames = set()
......@@ -1026,10 +1055,11 @@ class CharmmPsfFile(object):
# See if we need to use a switching function
if switchDistance and nonbondedMethod is not ff.NoCutoff:
# make sure it's legal
if switchDistance >= nonbondedCutoff:
if (_strip_optunit(switchDistance, u.nanometer) >=
_strip_optunit(nonbondedCutoff, u.nanometer)):
raise ValueError('switchDistance is too large compared '
'to the cutoff!')
if abs(switchDistance) != switchDistance:
if _strip_optunit(switchDistance, u.nanometer) < 0:
# Detects negatives for both Quantity and float
raise ValueError('switchDistance must be non-negative!')
force.setUseSwitchingFunction(True)
......@@ -1070,10 +1100,11 @@ class CharmmPsfFile(object):
# See if we need to use a switching function
if switchDistance and nonbondedMethod is not ff.NoCutoff:
# make sure it's legal
if switchDistance >= nonbondedCutoff:
if (_strip_optunit(switchDistance, u.nanometer) >=
_strip_optunit(nonbondedCutoff, u.nanometer)):
raise ValueError('switchDistance is too large compared '
'to the cutoff!')
if abs(switchDistance) != switchDistance:
if _strip_optunit(switchDistance, u.nanometer) < 0:
# Detects negatives for both Quantity and float
raise ValueError('switchDistance must be non-negative!')
force.setUseSwitchingFunction(True)
......@@ -1156,11 +1187,15 @@ class CharmmPsfFile(object):
raise ValueError('Unrecognized nonbonded method')
if switchDistance and nonbondedMethod is not ff.NoCutoff:
# make sure it's legal
if switchDistance >= nonbondedCutoff:
if (_strip_optunit(switchDistance, u.nanometer) >=
_strip_optunit(nonbondedCutoff, u.nanometer)):
raise ValueError('switchDistance is too large compared '
'to the cutoff!')
cforce.setUseSwitchingFunction(True)
cforce.setSwitchingDistance(switchDistance)
if _strip_optunit(switchDistance, u.nanometer) < 0:
# Detects negatives for both Quantity and float
raise ValueError('switchDistance must be non-negative!')
cforce.setUseSwitchingFunction(True)
cforce.setSwitchingDistance(switchDistance)
for i in lj_idx_list:
cforce.addParticle((i - 1,)) # adjust for indexing from 0
......@@ -1343,7 +1378,7 @@ class CharmmPsfFile(object):
def boxLengths(self, stuff):
raise RuntimeError('Use setBox to set a box with lengths and angles '
'or set the boxVectors attribute with box vectors')
@property
def boxVectors(self):
""" Return the box vectors """
......@@ -1388,12 +1423,12 @@ def set_molecules(atom_list):
owner = []
# The way I do this is via a recursive algorithm, in which
# the "set_owner" method is called for each bonded partner an atom
# has, which in turn calls set_owner for each of its partners and
# has, which in turn calls set_owner for each of its partners and
# so on until everything has been assigned.
molecule_number = 1 # which molecule number we are on
for i in range(len(atom_list)):
# If this atom has not yet been "owned", make it the next molecule
# However, we only increment which molecule number we're on if
# However, we only increment which molecule number we're on if
# we actually assigned a new molecule (obviously)
if not atom_list[i].marked:
tmp = [i]
......@@ -1414,7 +1449,7 @@ def _set_owner(atom_list, owner_array, atm, mol_id):
owner_array.append(partner.idx)
_set_owner(atom_list, owner_array, partner.idx, mol_id)
elif partner.marked != mol_id:
raise MoleculeError('Atom %d in multiple molecules' %
raise MoleculeError('Atom %d in multiple molecules' %
partner.idx)
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
......
......@@ -8,7 +8,7 @@ Medical Research, grant U54 GM072970. See https://simtk.org.
Portions copyright (c) 2014 Stanford University and the Authors.
Authors: Robert McGibbon
Contributors:
Contributors:
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
......@@ -71,10 +71,12 @@ class CheckpointReporter(object):
def __init__(self, file, reportInterval):
"""Create a CheckpointReporter.
Parameters:
- file (string or open file object) The file to write to. Any current
contents will be overwritten.
- reportInterval (int) The interval (in time steps) at which to write checkpoints
Parameters
----------
file : string or open file object
The file to write to. Any current contents will be overwritten.
reportInterval : int
The interval (in time steps) at which to write checkpoints.
"""
self._reportInterval = reportInterval
......@@ -88,12 +90,18 @@ class CheckpointReporter(object):
def describeNextReport(self, simulation):
"""Get information about the next report this object will generate.
Parameters:
- simulation (Simulation) The Simulation to generate a report for
Returns: A five element tuple. The first element is the number of steps until the
next report. The remaining elements specify whether that report will require
positions, velocities, forces, and energies respectively.
Parameters
----------
simulation : Simulation
The Simulation to generate a report for
Returns
-------
tuple
A five element tuple. The first element is the number of steps
until the next report. The remaining elements specify whether
that report will require positions, velocities, forces, and
energies respectively.
"""
steps = self._reportInterval - simulation.currentStep%self._reportInterval
return (steps, False, False, False, False)
......@@ -101,9 +109,12 @@ class CheckpointReporter(object):
def report(self, simulation, state):
"""Generate a report.
Parameters:
- simulation (Simulation) The Simulation to generate a report for
- state (State) The current state of the simulation
Parameters
----------
simulation : Simulation
The Simulation to generate a report for
state : State
The current state of the simulation
"""
self._out.seek(0)
chk = simulation.context.createCheckpoint()
......
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