Unverified Commit f6431a42 authored by peastman's avatar peastman Committed by GitHub
Browse files

Merge pull request #2351 from andysim/nhc

WIP: Nosé-Hoover Thermostat
parents 2fc77d89 44dca26d
/* -------------------------------------------------------------------------- *
* 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) 2019 Stanford University and the Authors. *
* Authors: Andreas Krämer and Andrew C. Simmonett *
* 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 "TestNoseHooverThermostat.h"
void runPlatformTests() {
}
......@@ -35,5 +35,6 @@
#include "openmm/DrudeForce.h"
#include "openmm/DrudeLangevinIntegrator.h"
#include "openmm/DrudeSCFIntegrator.h"
#include "openmm/DrudeNoseHooverIntegrator.h"
#endif /*OPENMM_DRUDE_H_*/
#ifndef OPENMM_DRUDENOSEHOOVERINTEGRATOR_H_
#define OPENMM_DRUDENOSEHOOVERINTEGRATOR_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) 2019 Stanford University and the Authors. *
* Authors: Andreas Krämer and Andrew C. Simmonett *
* 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/NoseHooverIntegrator.h"
#include "openmm/Kernel.h"
#include "openmm/internal/windowsExportDrude.h"
namespace OpenMM {
/**
* This Integrator simulates systems that include Drude particles. It applies two different Nose-Hoover
* chain thermostats to the different parts of the system. The first is applied to ordinary particles (ones
* that are not part of a Drude particle pair), as well as to the center of mass of each Drude particle pair.
* A second thermostat, typically with a much lower temperature, is applied to the relative internal
* displacement of each pair.
*
* This Integrator requires the System to include a DrudeForce, which it uses to identify the Drude
* particles.
*/
class OPENMM_EXPORT_DRUDE DrudeNoseHooverIntegrator : public NoseHooverIntegrator {
public:
/**
* Create a DrudeNoseHooverIntegrator.
*
* @param temperature the target temperature for the system (in Kelvin).
* @param collisionFrequency the frequency of the system's interaction with the heat bath (in inverse picoseconds).
* @param drudeTemperature the target temperature for the Drude particles, relative to their parent atom (in Kelvin).
* @param drudeCollisionFrequency the frequency of the drude particles' interaction with the heat bath (in inverse picoseconds).
* @param stepSize the step size with which to integrator the system (in picoseconds)
* @param chainLength the number of beads in the Nose-Hoover chain.
* @param numMTS the number of step in the multiple time step chain propagation algorithm.
* @param numYoshidaSuzuki the number of terms in the Yoshida-Suzuki multi time step decomposition
* used in the chain propagation algorithm (must be 1, 3, or 5).
*/
DrudeNoseHooverIntegrator(double temperature, double collisionFrequency,
double drudeTemperature, double drudeCollisionFrequency, double stepSize,
int chainLength = 3, int numMTS = 3, int numYoshidaSuzuki = 3);
virtual ~DrudeNoseHooverIntegrator();
/**
* This will be called by the Context when it is created. It informs the Integrator
* of what context it will be integrating, and gives it a chance to do any necessary initialization.
* It will also get called again if the application calls reinitialize() on the Context.
*/
void initialize(ContextImpl& context);
/**
* Get the maximum distance a Drude particle can ever move from its parent particle, measured in nm. This is implemented
* with a hard wall constraint. If this distance is set to 0 (the default), the hard wall constraint is omitted.
*/
double getMaxDrudeDistance() const;
/**
* Set the maximum distance a Drude particle can ever move from its parent particle, measured in nm. This is implemented
* with a hard wall constraint. If this distance is set to 0 (the default), the hard wall constraint is omitted.
*/
void setMaxDrudeDistance(double distance);
/**
* Compute the kinetic energy of the drude particles at the current time.
*/
double computeDrudeKineticEnergy();
/**
* Compute the kinetic energy of all (real and drude) particles at the current time.
*/
double computeTotalKineticEnergy();
};
} // namespace OpenMM
#endif /*OPENMM_DRUDENOSEHOOVERINTEGRATOR_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) 2019 Stanford University and the Authors. *
* Authors: Andreas Krämer and Andrew C. Simmonett *
* 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/DrudeNoseHooverIntegrator.h"
#include "openmm/Context.h"
#include "openmm/OpenMMException.h"
#include "openmm/internal/ContextImpl.h"
#include "openmm/DrudeKernels.h"
#include "openmm/DrudeForce.h"
#include "openmm/CMMotionRemover.h"
#include "openmm/kernels.h"
#include <ctime>
#include <iostream>
#include <string>
#include <set>
using namespace OpenMM;
using std::string;
using std::vector;
DrudeNoseHooverIntegrator::DrudeNoseHooverIntegrator(double temperature, double collisionFrequency,
double drudeTemperature, double drudeCollisionFrequency,
double stepSize, int chainLength, int numMTS, int numYoshidaSuzuki) :
NoseHooverIntegrator(stepSize) {
setMaxDrudeDistance(0);
hasSubsystemThermostats_ = false;
addSubsystemThermostat(std::vector<int>(), std::vector<std::pair<int, int>>(), temperature,
collisionFrequency, drudeTemperature, drudeCollisionFrequency,
chainLength, numMTS, numYoshidaSuzuki);
}
DrudeNoseHooverIntegrator::~DrudeNoseHooverIntegrator() { }
double DrudeNoseHooverIntegrator::getMaxDrudeDistance() const {
return maxPairDistance_;
}
void DrudeNoseHooverIntegrator::setMaxDrudeDistance(double distance) {
if (distance < 0)
throw OpenMMException("setMaxDrudeDistance: Distance cannot be negative");
maxPairDistance_ = distance;
}
void DrudeNoseHooverIntegrator::initialize(ContextImpl& contextRef) {
if (owner != NULL && &contextRef.getOwner() != owner)
throw OpenMMException("This Integrator is already bound to a context");
context = &contextRef;
owner = &contextRef.getOwner();
vvKernel = context->getPlatform().createKernel(IntegrateVelocityVerletStepKernel::Name(), contextRef);
vvKernel.getAs<IntegrateVelocityVerletStepKernel>().initialize(contextRef.getSystem(), *this);
nhcKernel = context->getPlatform().createKernel(NoseHooverChainKernel::Name(), contextRef);
nhcKernel.getAs<NoseHooverChainKernel>().initialize();
forcesAreValid = false;
// check for drude particles and build the Nose-Hoover Chains
const System& system = context->getSystem();
const DrudeForce* drudeForce = NULL;
bool hasCMMotionRemover = false;
for (int i = 0; i < system.getNumForces(); i++){
if (dynamic_cast<const DrudeForce*>(&system.getForce(i)) != NULL) {
if (drudeForce == NULL)
drudeForce = dynamic_cast<const DrudeForce*>(&system.getForce(i));
else
throw OpenMMException("The System contains multiple DrudeForces");
}
if (dynamic_cast<const CMMotionRemover*>(&system.getForce(i))) {
hasCMMotionRemover = true;
}
}
if (drudeForce == NULL)
throw OpenMMException("The System does not contain a DrudeForce");
if (!hasCMMotionRemover) {
std::cout << "Warning: Did not find a center-of-mass motion remover in the system. "
"This is problematic when using Drude." << std::endl;
}
for (auto& thermostat: noseHooverChains){
if ( (thermostat.getThermostatedAtoms().size() == 0) && (thermostat.getThermostatedPairs().size() == 0) ){
std::set<int> realParticlesSet;
vector<int> realParticles, drudeParticles, drudeParents;
vector<std::pair<int, int>> drudePairs;
for (int i = 0; i < system.getNumParticles(); i++) {
if (system.getParticleMass(i) > 0.0) realParticlesSet.insert(i);
}
for (int i = 0; i < drudeForce->getNumParticles(); i++) {
int p, p1, p2, p3, p4;
double charge, polarizability, aniso12, aniso34;
drudeForce->getParticleParameters(i, p, p1, p2, p3, p4, charge, polarizability, aniso12, aniso34);
realParticlesSet.erase(p);
realParticlesSet.erase(p1);
drudePairs.push_back({p,p1});
}
thermostat.setThermostatedPairs(drudePairs);
thermostat.setThermostatedAtoms(std::vector<int>(realParticlesSet.begin(), realParticlesSet.end()));
}
}
initializeThermostats(system);
}
double DrudeNoseHooverIntegrator::computeDrudeKineticEnergy() {
double kE = 0.0;
for (const auto &nhc: noseHooverChains){
if (nhc.getThermostatedPairs().size() != 0) {
kE += nhcKernel.getAs<NoseHooverChainKernel>().computeMaskedKineticEnergy(*context, nhc, true).second;
}
}
return kE;
}
double DrudeNoseHooverIntegrator::computeTotalKineticEnergy() {
return vvKernel.getAs<IntegrateVelocityVerletStepKernel>().computeKineticEnergy(*context, *this);
}
......@@ -5,6 +5,7 @@
ENABLE_TESTING()
INCLUDE_DIRECTORIES(${CUDA_INCLUDE_DIR})
INCLUDE_DIRECTORIES(${OPENMM_DIR}/plugins/drude/tests)
# Automatically create tests using files named "Test*.cpp"
FILE(GLOB TEST_PROGS "*Test*.cpp")
......
/* -------------------------------------------------------------------------- *
* 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) 2013 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 "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "openmm/NonbondedForce.h"
#include "openmm/Platform.h"
#include "openmm/System.h"
#include "openmm/VerletIntegrator.h"
#include "openmm/DrudeForce.h"
#include "CudaPlatform.h"
#include "SimTKOpenMMUtilities.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
extern "C" OPENMM_EXPORT void registerDrudeCudaKernelFactories();
void runPlatformTests() { }
#include "TestDrudeNoseHoover.h"
Platform& initializePlatform(int argc, char* argv[]) {
registerDrudeCudaKernelFactories();
if (argc > 1) Platform::getPlatformByName("CUDA").setPropertyDefaultValue("Precision", std::string(argv[1]));
return Platform::getPlatformByName("CUDA");
}
......@@ -5,6 +5,7 @@
ENABLE_TESTING()
INCLUDE_DIRECTORIES(${OPENCL_INCLUDE_DIR})
INCLUDE_DIRECTORIES(${OPENMM_DIR}/plugins/drude/tests)
# Automatically create tests using files named "Test*.cpp"
FILE(GLOB TEST_PROGS "*Test*.cpp")
......
/* -------------------------------------------------------------------------- *
* 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) 2013 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 "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "openmm/NonbondedForce.h"
#include "openmm/Platform.h"
#include "openmm/System.h"
#include "openmm/VerletIntegrator.h"
#include "openmm/DrudeForce.h"
#include "OpenCLPlatform.h"
#include "SimTKOpenMMUtilities.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
extern "C" OPENMM_EXPORT void registerDrudeOpenCLKernelFactories();
void runPlatformTests() { }
#include "TestDrudeNoseHoover.h"
Platform& initializePlatform(int argc, char* argv[]) {
registerDrudeOpenCLKernelFactories();
if (argc > 1) Platform::getPlatformByName("OpenCL").setPropertyDefaultValue("Precision", std::string(argv[1]));
return Platform::getPlatformByName("OpenCL");
}
......@@ -5,6 +5,7 @@ ENABLE_TESTING()
INCLUDE_DIRECTORIES(${OPENMM_DIR}/platforms/reference/include)
INCLUDE_DIRECTORIES(${OPENMM_DIR}/openmmapi/include/openmm)
INCLUDE_DIRECTORIES(${OPENMM_DIR}/platforms/reference/src)
INCLUDE_DIRECTORIES(${OPENMM_DIR}/plugins/drude/tests)
SET(SHARED_OPENMM_DRUDE_TARGET OpenMMDrude)
......
/* -------------------------------------------------------------------------- *
* 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) 2013 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 "openmm/Platform.h"
using namespace OpenMM;
using namespace std;
//extern "C" OPENMM_EXPORT void registerDrudeReferenceKernelFactories();
Platform& initializePlatform(int argc, char* argv[]) {
/* registerDrudeReferenceKernelFactories();
*/
return Platform::getPlatformByName("Reference");
}
#include "TestDrudeNoseHoover.h"
void runPlatformTests() { }
#ifndef OPENMM_DRUDE_NOSE_HOOVER_INTEGRATOR_PROXY_H_
#define OPENMM_DRUDE_NOSE_HOOVER_INTEGRATOR_PROXY_H_
#include "openmm/serialization/SerializationProxy.h"
#include "openmm/internal/windowsExportDrude.h"
namespace OpenMM {
class OPENMM_EXPORT_DRUDE DrudeNoseHooverIntegratorProxy : public SerializationProxy {
public:
DrudeNoseHooverIntegratorProxy();
void serialize(const void* object, SerializationNode& node) const;
void* deserialize(const SerializationNode& node) const;
};
}
#endif /*OPENMM_DRUDE_NOSE_HOOVER_INTEGRATOR_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 Stanford University and the Authors. *
* Authors: Andrew C. Simmonett, Andreas Krämer *
* 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/DrudeNoseHooverIntegratorProxy.h"
#include "openmm/serialization/SerializationNode.h"
#include "openmm/DrudeNoseHooverIntegrator.h"
#include <vector>
#include <assert.h>
#include <OpenMM.h>
using namespace std;
using namespace OpenMM;
DrudeNoseHooverIntegratorProxy::DrudeNoseHooverIntegratorProxy() : SerializationProxy("DrudeNoseHooverIntegrator") {
}
void DrudeNoseHooverIntegratorProxy::serialize(const void* object, SerializationNode& node) const {
node.setIntProperty("version", 1);
const DrudeNoseHooverIntegrator& integrator = *reinterpret_cast<const DrudeNoseHooverIntegrator*>(object);
node.setDoubleProperty("stepSize", integrator.getStepSize());
node.setDoubleProperty("constraintTolerance", integrator.getConstraintTolerance());
node.setDoubleProperty("maximumPairDistance", integrator.getMaximumPairDistance());
assert(not integrator.hasSubsystemThermostats());
node.setDoubleProperty("temperature", integrator.getTemperature());
node.setDoubleProperty("relativeTemperature", integrator.getRelativeTemperature());
node.setDoubleProperty("collisionFrequency", integrator.getCollisionFrequency());
node.setDoubleProperty("relativeCollisionFrequency", integrator.getRelativeCollisionFrequency());
node.setIntProperty("chainLength", integrator.getThermostat().getChainLength());
node.setIntProperty("numMTS", integrator.getThermostat().getNumMultiTimeSteps());
node.setIntProperty("numYS", integrator.getThermostat().getNumYoshidaSuzukiTimeSteps());
}
void* DrudeNoseHooverIntegratorProxy::deserialize(const SerializationNode& node) const {
if (node.getIntProperty("version") != 1)
throw OpenMMException("Unsupported version number");
DrudeNoseHooverIntegrator* integrator;
integrator = new DrudeNoseHooverIntegrator(
node.getDoubleProperty("temperature"),
node.getDoubleProperty("collisionFrequency"),
node.getDoubleProperty("relativeTemperature"),
node.getDoubleProperty("relativeCollisionFrequency"),
node.getDoubleProperty("stepSize"),
node.getIntProperty("chainLength"),
node.getIntProperty("numMTS"),
node.getIntProperty("numYS")
);
integrator->setConstraintTolerance(node.getDoubleProperty("constraintTolerance"));
integrator->setMaximumPairDistance(node.getDoubleProperty("maximumPairDistance"));
return integrator;
}
......@@ -42,11 +42,13 @@
#include "openmm/DrudeForce.h"
#include "openmm/DrudeLangevinIntegrator.h"
#include "openmm/DrudeNoseHooverIntegrator.h"
#include "openmm/serialization/SerializationProxy.h"
#include "openmm/serialization/DrudeForceProxy.h"
#include "openmm/serialization/DrudeLangevinIntegratorProxy.h"
#include "openmm/serialization/DrudeNoseHooverIntegratorProxy.h"
#if defined(WIN32)
#include <windows.h>
......@@ -65,4 +67,5 @@ using namespace OpenMM;
extern "C" OPENMM_EXPORT_DRUDE void registerDrudeSerializationProxies() {
SerializationProxy::registerProxy(typeid(DrudeForce), new DrudeForceProxy());
SerializationProxy::registerProxy(typeid(DrudeLangevinIntegrator), new DrudeLangevinIntegratorProxy());
SerializationProxy::registerProxy(typeid(DrudeNoseHooverIntegrator), new DrudeNoseHooverIntegratorProxy());
}
/* -------------------------------------------------------------------------- *
* 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: Andrew C. Simmonett and Andreas Kraemer
* 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/DrudeNoseHooverIntegrator.h"
#include "ReferencePlatform.h"
#include "openmm/serialization/XmlSerializer.h"
#include "openmm/System.h"
#include "openmm/DrudeForce.h"
#include "openmm/Context.h"
#include <iostream>
#include <sstream>
using namespace OpenMM;
using namespace std;
extern "C" void registerDrudeSerializationProxies();
//extern "C" OPENMM_EXPORT void registerDrudeReferenceKernelFactories();
//extern "C" OPENMM_EXPORT void registerKernelFactories();
void assertIntegratorsEqual(const DrudeNoseHooverIntegrator& integrator1, const DrudeNoseHooverIntegrator& integrator2){
ASSERT_EQUAL(integrator1.getStepSize(), integrator2.getStepSize());
ASSERT_EQUAL(integrator1.getConstraintTolerance(), integrator2.getConstraintTolerance());
ASSERT_EQUAL(integrator1.getMaximumPairDistance(), integrator2.getMaximumPairDistance());
ASSERT_EQUAL(integrator1.getNumThermostats(), integrator2.getNumThermostats());
for (int i = 0; i < integrator1.getNumThermostats(); i++) {
const auto &thermostat1 = integrator1.getThermostat(i);
const auto &thermostat2 = integrator2.getThermostat(i);
ASSERT_EQUAL(thermostat1.getTemperature(), thermostat2.getTemperature());
ASSERT_EQUAL(thermostat1.getCollisionFrequency(), thermostat2.getCollisionFrequency());
ASSERT_EQUAL(thermostat1.getRelativeTemperature(), thermostat2.getRelativeTemperature());
ASSERT_EQUAL(thermostat1.getRelativeCollisionFrequency(), thermostat2.getRelativeCollisionFrequency());
ASSERT_EQUAL(thermostat1.getChainLength(), thermostat2.getChainLength());
ASSERT_EQUAL(thermostat1.getNumMultiTimeSteps(), thermostat2.getNumMultiTimeSteps());
ASSERT_EQUAL(thermostat1.getNumYoshidaSuzukiTimeSteps(), thermostat2.getNumYoshidaSuzukiTimeSteps());
ASSERT_EQUAL(thermostat1.getChainID(), thermostat2.getChainID());
const auto &thermostat1Atoms = thermostat1.getThermostatedAtoms();
const auto &thermostat2Atoms = thermostat2.getThermostatedAtoms();
ASSERT_EQUAL(thermostat1Atoms.size(), thermostat2Atoms.size());
for (int j = 0; j < thermostat1Atoms.size(); ++j) {
ASSERT_EQUAL(thermostat1Atoms[j], thermostat2Atoms[j]);
}
const auto &thermostat1Pairs = thermostat1.getThermostatedPairs();
const auto &thermostat2Pairs = thermostat2.getThermostatedPairs();
ASSERT_EQUAL(thermostat1Pairs.size(), thermostat2Pairs.size());
for (int j = 0; j < thermostat1Pairs.size(); ++j) {
ASSERT_EQUAL(thermostat1Pairs[j].first, thermostat2Pairs[j].first);
ASSERT_EQUAL(thermostat1Pairs[j].second, thermostat2Pairs[j].second);
}
}
}
void testSerialization() {
// Check with default constructor
System system;
system.addForce(new DrudeForce());
for (int i=0; i<10; i++) system.addParticle(1.0);
DrudeNoseHooverIntegrator integrator(331, 0.21, 1.1, 0.1, 0.004, 5, 5, 5);
// Serialize and then deserialize it.
stringstream buffer2;
XmlSerializer::serialize<DrudeNoseHooverIntegrator>(&integrator, "Integrator", buffer2);
DrudeNoseHooverIntegrator* copy = XmlSerializer::deserialize<DrudeNoseHooverIntegrator>(buffer2);
ASSERT_EQUAL(copy->getThermostat(0).getThermostatedAtoms().size(), 0);
assertIntegratorsEqual(integrator, *copy);
}
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) 2019 Stanford University and the Authors. *
* Authors: Andreas Krämer and Andrew C. Simmonett *
* 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/NoseHooverChain.h"
#include "openmm/CMMotionRemover.h"
#include "openmm/DrudeNoseHooverIntegrator.h"
#include "openmm/Context.h"
#include "openmm/State.h"
#include "openmm/HarmonicBondForce.h"
#include "openmm/VirtualSite.h"
#include "openmm/NonbondedForce.h"
#include "openmm/CustomExternalForce.h"
#include "openmm/System.h"
#include "openmm/DrudeForce.h"
#include "SimTKOpenMMRealType.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <sstream>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <numeric>
using namespace OpenMM;
using namespace std;
extern "C" OPENMM_EXPORT void registerDrudeReferenceKernelFactories();
extern "C" OPENMM_EXPORT void registerKernelFactories();
Platform& initializePlatform(int argc, char* argv[]);
void build_waterbox(System &system, int gridSize, double polarizability, vector<Vec3> & positions) {
// Create a box of SWM4-NDP water molecules. This involves constraints, virtual sites,
// and Drude particles.
const int numMolecules = gridSize*gridSize*gridSize;
const double spacing = 0.8;
const double boxSize = spacing*(gridSize+1);
NonbondedForce* nonbonded = new NonbondedForce();
DrudeForce* drude = new DrudeForce();
CMMotionRemover* cmm = new CMMotionRemover(1);
system.addForce(cmm);
system.addForce(nonbonded);
system.addForce(drude);
system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
nonbonded->setCutoffDistance(1.2);
nonbonded->setSwitchingDistance(0.8);
for (int i = 0; i < numMolecules; i++) {
int startIndex = system.getNumParticles();
system.addParticle(15.6); // O
system.addParticle(0.4); // D
system.addParticle(1.0); // H1
system.addParticle(1.0); // H2
system.addParticle(0.0); // M
nonbonded->addParticle(1.71636, 0.318395, 0.21094*4.184);
nonbonded->addParticle(-1.71636, 1, 0);
nonbonded->addParticle(0.55733, 1, 0);
nonbonded->addParticle(0.55733, 1, 0);
nonbonded->addParticle(-1.11466, 1, 0);
for (int j = 0; j < 5; j++)
for (int k = 0; k < j; k++)
nonbonded->addException(startIndex+j, startIndex+k, 0, 1, 0);
system.addConstraint(startIndex, startIndex+2, 0.09572);
system.addConstraint(startIndex, startIndex+3, 0.09572);
system.addConstraint(startIndex+2, startIndex+3, 0.15139);
system.setVirtualSite(startIndex+4, new ThreeParticleAverageSite(startIndex, startIndex+2, startIndex+3, 0.786646558, 0.106676721, 0.106676721));
drude->addParticle(startIndex+1, startIndex, -1, -1, -1, -1.71636, polarizability, 1, 1);
}
for (int i = 0; i < gridSize; i++) {
for (int j = 0; j < gridSize; j++) {
for (int k = 0; k < gridSize; k++) {
Vec3 pos(i*spacing, j*spacing, k*spacing);
positions.push_back(pos);
positions.push_back(pos);
positions.push_back(pos+Vec3(0.09572, 0, 0));
positions.push_back(pos+Vec3(-0.023999, 0.092663, 0));
positions.push_back(pos);
}
}
}
}
void testWaterBox(Platform& platform) {
// Create a box of SWM4-NDP water molecules. This involves constraints, virtual sites,
// and Drude particles.
System system;
const int gridSize = 3;
vector<Vec3> positions;
double polarizability = ONE_4PI_EPS0*1.71636*1.71636/(100000*4.184);
build_waterbox(system, gridSize, polarizability, positions);
const int numMolecules = gridSize*gridSize*gridSize;
int numStandardDof = 3*3*numMolecules - system.getNumConstraints();
int numDrudeDof = 3*numMolecules;
int numDof = numStandardDof+numDrudeDof;
const double temperature = 300.0;
const double temperatureDrude = 10.0;
// Simulate it and check the temperature.
int chainLength = 4;
int numMTS = 4;
int numYS = 5;
double frequency = 800.0;
double frequencyDrude = 2000.0;
int randomSeed = 100;
DrudeNoseHooverIntegrator integ(temperature, frequency,
temperatureDrude, frequencyDrude, 0.0005,
chainLength, numMTS, numYS);
Context context(system, integ, platform);
context.setPositions(positions);
context.setVelocitiesToTemperature(temperature, randomSeed);
std::vector<Vec3> velocities = context.getState(State::Velocities).getVelocities();
for (int i = 0; i < numMolecules; i++){
Vec3 noize;
for (int j = 0; j < 3; j++){
noize[j] = float(((i+18311)*(j+18253) * 313419097822414) % 18313) / float(18313);
noize[j] *= sqrt(3 * BOLTZ * temperatureDrude / 0.4);
}
velocities[5*i+1] = velocities[5*i] + noize;
}
context.setVelocities(velocities);
context.applyConstraints(1e-6);
// Equilibrate.
integ.step(500);
// Compute the internal and center of mass temperatures.
double totalKE = 0;
const int numSteps = 4000;
double meanTemp = 0.0;
double meanDrudeTemp = 0.0;
double meanConserved = 0.0;
for (int i = 0; i < numSteps; i++) {
integ.step(1);
State state = context.getState(State::Energy);
double KE = state.getKineticEnergy();
double PE = state.getPotentialEnergy();
double fullKE = integ.computeTotalKineticEnergy();
double drudeKE = integ.computeDrudeKineticEnergy();
double temp = KE/(0.5*numStandardDof*BOLTZ);
double drudeTemp = drudeKE/(0.5*numDrudeDof*BOLTZ);
meanTemp = (i*meanTemp + temp)/(i+1);
meanDrudeTemp = (i*meanDrudeTemp + drudeTemp)/(i+1);
double heatBathEnergy = integ.computeHeatBathEnergy();
double conserved = PE + fullKE + heatBathEnergy;
meanConserved = (i*meanConserved + conserved)/(i+1);
totalKE += KE;
ASSERT(fabs(meanConserved - conserved) < 0.6);
}
totalKE /= numSteps;
ASSERT_USUALLY_EQUAL_TOL(temperature, meanTemp, 0.004);
ASSERT_USUALLY_EQUAL_TOL(temperatureDrude, meanDrudeTemp, 0.004);
}
double testWaterBoxWithHardWallConstraint(Platform& platform, double hardWallConstraint){
// Create a box of SWM4-NDP water molecules. This involves constraints, virtual sites,
// and Drude particles.
System system;
const int gridSize = 3;
vector<Vec3> positions;
double polarizability = 1e-2;
build_waterbox(system, gridSize, polarizability, positions);
const int numMolecules = gridSize*gridSize*gridSize;
int numStandardDof = 3*3*numMolecules - system.getNumConstraints();
int numDrudeDof = 3*numMolecules;
int numDof = numStandardDof+numDrudeDof;
const double temperature = 300.0;
const double temperatureDrude = 10.0;
// Simulate it and check the temperature.
int chainLength = 4;
int numMTS = 3;
int numYS = 3;
double frequency = 25.0;
double frequencyDrude = 25.0;
int randomSeed = 100;
DrudeNoseHooverIntegrator integ(temperature, frequency,
temperatureDrude, frequencyDrude, 0.0005,
chainLength, numMTS, numYS);
integ.setMaxDrudeDistance(hardWallConstraint);
Context context(system, integ, platform);
context.setPositions(positions);
context.setVelocitiesToTemperature(temperature, randomSeed);
std::vector<Vec3> velocities = context.getState(State::Velocities).getVelocities();
for (int i = 0; i < numMolecules; i++){
Vec3 noize;
for (int j = 0; j < 3; j++){
noize[j] = float(((i+18311)*(j+18253) * 313419097822414) % 18313) / float(18313);
noize[j] *= sqrt(3 * BOLTZ * temperatureDrude / 0.4);
}
velocities[5*i+1] = velocities[5*i] + noize;
}
context.setVelocities(velocities);
context.applyConstraints(1e-6);
// Equilibrate.
integ.step(10);
// Compute the internal and center of mass temperatures.
double totalKE = 0;
const int numSteps = 10;
double meanTemp = 0.0;
double meanDrudeTemp = 0.0;
double meanConserved = 0.0;
double maxR = 0.0;
for (int i = 0; i < numSteps; i++) {
integ.step(1);
State state = context.getState(State::Energy | State::Positions);
double KE = state.getKineticEnergy();
double PE = state.getPotentialEnergy();
double fullKE = integ.computeTotalKineticEnergy();
double drudeKE = integ.computeDrudeKineticEnergy();
double temp = KE/(0.5*numStandardDof*BOLTZ);
double drudeTemp = drudeKE/(0.5*numDrudeDof*BOLTZ);
meanTemp = (i*meanTemp + temp)/(i+1);
meanDrudeTemp = (i*meanDrudeTemp + drudeTemp)/(i+1);
double heatBathEnergy = integ.computeHeatBathEnergy();
double conserved = PE + fullKE + heatBathEnergy;
meanConserved = (i*meanConserved + conserved)/(i+1);
const auto & positions = state.getPositions();
for(int mol = 0; mol < gridSize*gridSize*gridSize; ++mol) {
auto dR = positions[5*mol+1] - positions[5*mol];
maxR = std::max(maxR, std::sqrt(dR.dot(dR)));
}
totalKE += KE;
}
totalKE /= numSteps;
return maxR;
}
int main(int argc, char* argv[]) {
try {
registerKernelFactories();
Platform& platform = initializePlatform(argc, argv);
testWaterBox(platform);
double maxDrudeDistance = 0.005;
double observedDrudeDistance = testWaterBoxWithHardWallConstraint(platform, 0.0);
ASSERT(observedDrudeDistance > maxDrudeDistance);
observedDrudeDistance = testWaterBoxWithHardWallConstraint(platform, maxDrudeDistance);
ASSERT(observedDrudeDistance < maxDrudeDistance);
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
#ifndef OPENMM_NOSE_HOOVER_INTEGRATOR_PROXY_H_
#define OPENMM_NOSE_HOOVER_INTEGRATOR_PROXY_H_
#include "openmm/serialization/XmlSerializer.h"
namespace OpenMM {
class NoseHooverIntegratorProxy : public SerializationProxy {
public:
NoseHooverIntegratorProxy();
void serialize(const void* object, SerializationNode& node) const;
void* deserialize(const SerializationNode& node) const;
};
}
#endif /*OPENMM_NOSE_HOOVER_INTEGRATOR_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 Stanford University and the Authors. *
* Authors: Andrew C. Simmonett, Andreas Krämer *
* 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/NoseHooverIntegratorProxy.h"
#include <vector>
#include <OpenMM.h>
using namespace std;
using namespace OpenMM;
NoseHooverIntegratorProxy::NoseHooverIntegratorProxy() : SerializationProxy("NoseHooverIntegrator") {
}
void NoseHooverIntegratorProxy::serialize(const void* object, SerializationNode& node) const {
node.setIntProperty("version", 1);
const NoseHooverIntegrator& integrator = *reinterpret_cast<const NoseHooverIntegrator*>(object);
node.setDoubleProperty("stepSize", integrator.getStepSize());
node.setDoubleProperty("constraintTolerance", integrator.getConstraintTolerance());
node.setDoubleProperty("maximumPairDistance", integrator.getMaximumPairDistance());
node.setBoolProperty("hasSubsystemThermostats", integrator.hasSubsystemThermostats());
if (integrator.hasSubsystemThermostats()) {
// Serialize all thermostats separately
for (int i = 0; i < integrator.getNumThermostats(); i++){
const auto& chain = integrator.getThermostat(i);
auto& chainNode = node.createChildNode("Thermostat");
chainNode.setDoubleProperty("temperature", chain.getTemperature());
chainNode.setDoubleProperty("collisionFrequency", chain.getCollisionFrequency());
chainNode.setDoubleProperty("relativeTemperature", chain.getRelativeTemperature());
chainNode.setDoubleProperty("relativeCollisionFrequency", chain.getRelativeCollisionFrequency());
chainNode.setIntProperty("chainLength", chain.getChainLength());
chainNode.setIntProperty("numMTS", chain.getNumMultiTimeSteps());
chainNode.setIntProperty("numYS", chain.getNumYoshidaSuzukiTimeSteps());
auto& particlesNode = chainNode.createChildNode("ThermostatedAtoms");
for (int particle: chain.getThermostatedAtoms()){
particlesNode.createChildNode("Particle").setIntProperty("index", particle);
}
auto& pairsNode = chainNode.createChildNode("ThermostatedPairs");
for (auto& pair: chain.getThermostatedPairs()){
auto& pairNode = pairsNode.createChildNode("Pair");
pairNode.setIntProperty("index1", pair.first);
pairNode.setIntProperty("index2", pair.second);
}
}
} else { // Serialize standard thermostat
node.setDoubleProperty("temperature", integrator.getTemperature());
node.setDoubleProperty("collisionFrequency", integrator.getCollisionFrequency());
node.setIntProperty("chainLength", integrator.getThermostat().getChainLength());
node.setIntProperty("numMTS", integrator.getThermostat().getNumMultiTimeSteps());
node.setIntProperty("numYS", integrator.getThermostat().getNumYoshidaSuzukiTimeSteps());
}
}
void* NoseHooverIntegratorProxy::deserialize(const SerializationNode& node) const {
if (node.getIntProperty("version") != 1)
throw OpenMMException("Unsupported version number");
NoseHooverIntegrator* integrator;
if (node.getBoolProperty("hasSubsystemThermostats")){
// deserialize all chains
integrator = new NoseHooverIntegrator(node.getDoubleProperty("stepSize"));
for (auto& chainNode : node.getChildren()) {
// particles
const auto& particlesNode = chainNode.getChildNode("ThermostatedAtoms");
vector<int> particles;
for (auto& particleNode: particlesNode.getChildren()){
particles.push_back(particleNode.getIntProperty("index"));
}
// pairs
const auto& pairsNode = chainNode.getChildNode("ThermostatedPairs");
vector<pair<int, int>> pairs;
for (auto& pairNode: pairsNode.getChildren()){
pairs.emplace_back(pairNode.getIntProperty("index1"), pairNode.getIntProperty("index2"));
}
integrator->addSubsystemThermostat(
particles, pairs,
chainNode.getDoubleProperty("temperature"),
chainNode.getDoubleProperty("collisionFrequency"),
chainNode.getDoubleProperty("relativeTemperature"),
chainNode.getDoubleProperty("relativeCollisionFrequency"),
chainNode.getIntProperty("chainLength"),
chainNode.getIntProperty("numMTS"),
chainNode.getIntProperty("numYS")
);
}
} else {
integrator = new NoseHooverIntegrator(
node.getDoubleProperty("temperature"),
node.getDoubleProperty("collisionFrequency"),
node.getDoubleProperty("stepSize"),
node.getIntProperty("chainLength"),
node.getIntProperty("numMTS"),
node.getIntProperty("numYS")
);
}
integrator->setConstraintTolerance(node.getDoubleProperty("constraintTolerance"));
integrator->setMaximumPairDistance(node.getDoubleProperty("maximumPairDistance"));
return integrator;
}
......@@ -56,6 +56,7 @@
#include "openmm/MonteCarloBarostat.h"
#include "openmm/MonteCarloMembraneBarostat.h"
#include "openmm/NonbondedForce.h"
#include "openmm/NoseHooverIntegrator.h"
#include "openmm/PeriodicTorsionForce.h"
#include "openmm/RBTorsionForce.h"
#include "openmm/RMSDForce.h"
......@@ -93,6 +94,7 @@
#include "openmm/serialization/MonteCarloBarostatProxy.h"
#include "openmm/serialization/MonteCarloMembraneBarostatProxy.h"
#include "openmm/serialization/NonbondedForceProxy.h"
#include "openmm/serialization/NoseHooverIntegratorProxy.h"
#include "openmm/serialization/PeriodicTorsionForceProxy.h"
#include "openmm/serialization/RBTorsionForceProxy.h"
#include "openmm/serialization/RMSDForceProxy.h"
......@@ -151,6 +153,7 @@ extern "C" void registerSerializationProxies() {
SerializationProxy::registerProxy(typeid(MonteCarloBarostat), new MonteCarloBarostatProxy());
SerializationProxy::registerProxy(typeid(MonteCarloMembraneBarostat), new MonteCarloMembraneBarostatProxy());
SerializationProxy::registerProxy(typeid(NonbondedForce), new NonbondedForceProxy());
SerializationProxy::registerProxy(typeid(NoseHooverIntegrator), new NoseHooverIntegratorProxy());
SerializationProxy::registerProxy(typeid(PeriodicTorsionForce), new PeriodicTorsionForceProxy());
SerializationProxy::registerProxy(typeid(RBTorsionForce), new RBTorsionForceProxy());
SerializationProxy::registerProxy(typeid(RMSDForce), new RMSDForceProxy());
......@@ -159,4 +162,4 @@ extern "C" void registerSerializationProxies() {
SerializationProxy::registerProxy(typeid(VariableLangevinIntegrator), new VariableLangevinIntegratorProxy());
SerializationProxy::registerProxy(typeid(VariableVerletIntegrator), new VariableVerletIntegratorProxy());
SerializationProxy::registerProxy(typeid(VerletIntegrator), new VerletIntegratorProxy());
}
\ 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: Andrew C. Simmonett and Andreas Kraemer
* 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/NoseHooverIntegrator.h"
#include "openmm/serialization/XmlSerializer.h"
#include "openmm/System.h"
#include "openmm/Context.h"
#include <iostream>
#include <sstream>
using namespace OpenMM;
using namespace std;
void assertIntegratorsEqual(const NoseHooverIntegrator& integrator1, const NoseHooverIntegrator& integrator2){
ASSERT_EQUAL(integrator1.getStepSize(), integrator2.getStepSize());
ASSERT_EQUAL(integrator1.getConstraintTolerance(), integrator2.getConstraintTolerance());
ASSERT_EQUAL(integrator1.getMaximumPairDistance(), integrator2.getMaximumPairDistance());
ASSERT_EQUAL(integrator1.getNumThermostats(), integrator2.getNumThermostats());
for (int i = 0; i < integrator1.getNumThermostats(); i++) {
const auto &thermostat1 = integrator1.getThermostat(i);
const auto &thermostat2 = integrator2.getThermostat(i);
ASSERT_EQUAL(thermostat1.getTemperature(), thermostat2.getTemperature());
ASSERT_EQUAL(thermostat1.getCollisionFrequency(), thermostat2.getCollisionFrequency());
ASSERT_EQUAL(thermostat1.getRelativeTemperature(), thermostat2.getRelativeTemperature());
ASSERT_EQUAL(thermostat1.getRelativeCollisionFrequency(), thermostat2.getRelativeCollisionFrequency());
ASSERT_EQUAL(thermostat1.getChainLength(), thermostat2.getChainLength());
ASSERT_EQUAL(thermostat1.getNumMultiTimeSteps(), thermostat2.getNumMultiTimeSteps());
ASSERT_EQUAL(thermostat1.getNumYoshidaSuzukiTimeSteps(), thermostat2.getNumYoshidaSuzukiTimeSteps());
ASSERT_EQUAL(thermostat1.getChainID(), thermostat2.getChainID());
const auto &thermostat1Atoms = thermostat1.getThermostatedAtoms();
const auto &thermostat2Atoms = thermostat2.getThermostatedAtoms();
ASSERT_EQUAL(thermostat1Atoms.size(), thermostat2Atoms.size());
for (int j = 0; j < thermostat1Atoms.size(); ++j) {
ASSERT_EQUAL(thermostat1Atoms[j], thermostat2Atoms[j]);
}
const auto &thermostat1Pairs = thermostat1.getThermostatedPairs();
const auto &thermostat2Pairs = thermostat2.getThermostatedPairs();
ASSERT_EQUAL(thermostat1Pairs.size(), thermostat2Pairs.size());
for (int j = 0; j < thermostat1Pairs.size(); ++j) {
ASSERT_EQUAL(thermostat1Pairs[j].first, thermostat2Pairs[j].first);
ASSERT_EQUAL(thermostat1Pairs[j].second, thermostat2Pairs[j].second);
}
}
}
void testSerialization() {
// Check with custom subsystem thermostats
NoseHooverIntegrator integrator_sub (0.0006);
integrator_sub.setConstraintTolerance(0.0404);
integrator_sub.setMaximumPairDistance(0.0051);
integrator_sub.addSubsystemThermostat(
{0,1,2,3,4,7}, {{0,7}}, 301.1, 1.1, 1.2, 1.3, 9, 2, 5
);
// Serialize and then deserialize it.
stringstream buffer;
XmlSerializer::serialize<NoseHooverIntegrator>(&integrator_sub, "Integrator", buffer);
NoseHooverIntegrator* copy = XmlSerializer::deserialize<NoseHooverIntegrator>(buffer);
assertIntegratorsEqual(integrator_sub, *copy);
// Check with default constructor
System system;
for (int i=0; i<10; i++) system.addParticle(1.0);
NoseHooverIntegrator integrator(331, 1.1, 0.004, 5, 5, 5);
Context context(system, integrator);
// Serialize and then deserialize it.
stringstream buffer2;
XmlSerializer::serialize<NoseHooverIntegrator>(&integrator, "Integrator", buffer2);
copy = XmlSerializer::deserialize<NoseHooverIntegrator>(buffer2);
// for thermostats that apply to the whole system, the particles are not serialized ...
ASSERT_EQUAL(copy->getThermostat(0).getThermostatedAtoms().size(), 0);
// ... but assigned when creating a context.
Context context2(system, *copy);
assertIntegratorsEqual(integrator, *copy);
}
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) 2019 Stanford University and the Authors. *
* Authors: Andreas Krämer and Andrew C. Simmonett *
* 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/Context.h"
#include "openmm/CustomExternalForce.h"
#include "openmm/HarmonicBondForce.h"
#include "openmm/NonbondedForce.h"
#include "openmm/System.h"
#include "openmm/NoseHooverIntegrator.h"
#include "openmm/VirtualSite.h"
#include "SimTKOpenMMRealType.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
const double TOL = 1e-5;
void testVVSingleBond() {
System system;
system.addParticle(2.0);
system.addParticle(2.0);
NoseHooverIntegrator integrator(0.01);
HarmonicBondForce* forceField = new HarmonicBondForce();
forceField->addBond(0, 1, 1.5, 1);
system.addForce(forceField);
Context context(system, integrator, platform);
vector<Vec3> positions(2);
positions[0] = Vec3(-1, 0, 0);
positions[1] = Vec3(1, 0, 0);
context.setPositions(positions);
// This is simply a harmonic oscillator, so 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 < 1000; ++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(10.0, context.getState(0).getTime(), 1e-5);
}
void testVVConstraints() {
const int numParticles = 8;
const int numConstraints = 5;
System system;
NoseHooverIntegrator integrator(0.001);
integrator.setConstraintTolerance(1e-5);
NonbondedForce* forceField = new NonbondedForce();
for (int i = 0; i < numParticles; ++i) {
system.addParticle(i%2 == 0 ? 5.0 : 10.0);
forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0);
}
system.addConstraint(0, 1, 1.0);
system.addConstraint(1, 2, 1.0);
system.addConstraint(2, 3, 1.0);
system.addConstraint(4, 5, 1.0);
system.addConstraint(6, 7, 1.0);
system.addForce(forceField);
Context context(system, integrator, platform);
vector<Vec3> positions(numParticles);
vector<Vec3> velocities(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numParticles; ++i) {
positions[i] = Vec3(i/2, (i+1)/2, 0);
velocities[i] = Vec3(genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5);
}
context.setPositions(positions);
context.setVelocities(velocities);
// Simulate it and see whether the constraints remain satisfied.
double initialEnergy = 0.0;
for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces);
for (int j = 0; j < numConstraints; ++j) {
int particle1, particle2;
double distance;
system.getConstraintParameters(j, particle1, particle2, distance);
Vec3 p1 = state.getPositions()[particle1];
Vec3 p2 = state.getPositions()[particle2];
double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2]));
ASSERT_EQUAL_TOL(distance, dist, 1e-4);
}
double energy = state.getPotentialEnergy()+state.getKineticEnergy();
if (i == 1)
initialEnergy = energy;
else if (i > 1)
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01);
integrator.step(1);
}
}
void testVVConstrainedClusters() {
const int numParticles = 7;
System system;
NoseHooverIntegrator integrator(0.001);
integrator.setConstraintTolerance(1e-5);
NonbondedForce* forceField = new NonbondedForce();
for (int i = 0; i < numParticles; ++i) {
system.addParticle(i > 1 ? 1.0 : 10.0);
forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0);
}
system.addConstraint(0, 1, 1.0);
system.addConstraint(0, 2, 1.0);
system.addConstraint(0, 3, 1.0);
system.addConstraint(0, 4, 1.0);
system.addConstraint(1, 5, 1.0);
system.addConstraint(1, 6, 1.0);
system.addConstraint(2, 3, sqrt(2.0));
system.addConstraint(2, 4, sqrt(2.0));
system.addConstraint(3, 4, sqrt(2.0));
system.addConstraint(5, 6, sqrt(2.0));
system.addForce(forceField);
Context context(system, integrator, platform);
vector<Vec3> positions(numParticles);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(1, 0, 0);
positions[2] = Vec3(-1, 0, 0);
positions[3] = Vec3(0, 1, 0);
positions[4] = Vec3(0, 0, 1);
positions[5] = Vec3(2, 0, 0);
positions[6] = Vec3(1, 1, 0);
vector<Vec3> velocities(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numParticles; ++i)
velocities[i] = Vec3(genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5);
context.setPositions(positions);
context.setVelocities(velocities);
// Simulate it and see whether the constraints remain satisfied.
double initialEnergy = 0.0;
for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces);
for (int j = 0; j < system.getNumConstraints(); ++j) {
int particle1, particle2;
double distance;
system.getConstraintParameters(j, particle1, particle2, distance);
Vec3 p1 = state.getPositions()[particle1];
Vec3 p2 = state.getPositions()[particle2];
double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2]));
ASSERT_EQUAL_TOL(distance, dist, 2e-5);
}
double energy = state.getPotentialEnergy()+state.getKineticEnergy();
if (i == 1)
initialEnergy = energy;
else if (i > 1)
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01);
integrator.step(1);
}
}
void testVVConstrainedMasslessParticles() {
System system;
system.addParticle(0.0);
system.addParticle(1.0);
system.addConstraint(0, 1, 1.5);
vector<Vec3> positions(2);
positions[0] = Vec3(-1, 0, 0);
positions[1] = Vec3(1, 0, 0);
NoseHooverIntegrator integrator(0.01);
bool failed = false;
try {
// This should throw an exception.
Context context(system, integrator, platform);
}
catch (exception& ex) {
failed = true;
}
ASSERT(failed);
// Now make both particles massless, which should work.
system.setParticleMass(1, 0.0);
Context context(system, integrator, platform);
context.setPositions(positions);
context.setVelocitiesToTemperature(300.0);
integrator.step(1);
State state = context.getState(State::Velocities);
ASSERT_EQUAL(0.0, state.getVelocities()[0][0]);
}
/**
* Make sure that virtual sites are updated correctly
*/
void testThreeParticleVirtualSite() {
System system;
system.addParticle(1.0);
system.addParticle(1.0);
system.addParticle(1.0);
system.addParticle(0.0);
system.setVirtualSite(3, new ThreeParticleAverageSite(0, 1, 2, 0.2, 0.3, 0.5));
CustomExternalForce* forceField = new CustomExternalForce("-a*x");
system.addForce(forceField);
forceField->addPerParticleParameter("a");
vector<double> params(1);
params[0] = 0.1;
forceField->addParticle(0, params);
params[0] = 0.2;
forceField->addParticle(1, params);
params[0] = 0.3;
forceField->addParticle(2, params);
params[0] = 0.4;
forceField->addParticle(3, params);
NoseHooverIntegrator integrator(0.002);
Context context(system, integrator, platform);
vector<Vec3> positions(4);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(1, 0, 0);
positions[2] = Vec3(0, 1, 0);
context.setPositions(positions);
context.applyConstraints(0.0001);
for (int i = 0; i < 1000; i++) {
State state = context.getState(State::Positions | State::Forces);
const vector<Vec3>& pos = state.getPositions();
ASSERT_EQUAL_VEC(pos[0]*0.2+pos[1]*0.3+pos[2]*0.5, pos[3], 1e-5);
ASSERT_EQUAL_VEC(Vec3(0.1+0.4*0.2, 0, 0), state.getForces()[0], 1e-5);
ASSERT_EQUAL_VEC(Vec3(0.2+0.4*0.3, 0, 0), state.getForces()[1], 1e-5);
ASSERT_EQUAL_VEC(Vec3(0.3+0.4*0.5, 0, 0), state.getForces()[2], 1e-5);
integrator.step(1);
}
}
void runPlatformTests();
int main(int argc, char* argv[]) {
try {
initializeTests(argc, argv);
testVVSingleBond();
testVVConstraints();
testVVConstrainedClusters();
testVVConstrainedMasslessParticles();
testThreeParticleVirtualSite();
runPlatformTests();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
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