diff --git a/docs-source/api-c++/forces.rst b/docs-source/api-c++/forces.rst index 62b072955..9c25206a8 100644 --- a/docs-source/api-c++/forces.rst +++ b/docs-source/api-c++/forces.rst @@ -99,3 +99,4 @@ expression. generated/CustomManyParticleForce generated/CustomNonbondedForce generated/CustomTorsionForce + generated/CustomVolumeForce diff --git a/docs-source/usersguide/theory/03_custom_forces.rst b/docs-source/usersguide/theory/03_custom_forces.rst index 2374c3338..19ac182c4 100644 --- a/docs-source/usersguide/theory/03_custom_forces.rst +++ b/docs-source/usersguide/theory/03_custom_forces.rst @@ -413,6 +413,21 @@ be used as a collective variable. The energy is then computed as where *f*\ (...) is a user supplied mathematical expression of the collective variables. It also may depend on user defined global parameters. +CustomVolumeForce +***************** + +CustomVolumeForce computes an energy that depends only on the box vectors +defining the periodic box (see Section :numref:`periodic-boundary-conditions`). + +.. math:: + E = f(\mathbf{a}, \mathbf{b}, \mathbf{c}) + +Because the energy does not depend on particle positions, it does not apply any +forces to particles. It is primarily useful for constant pressure simulations, +where the volume-dependent energy can influence the behavior of the barostat. +Energy terms of this sort are often used for pressure matching in coarse grained +force fields. + ATMForce ******** diff --git a/openmmapi/include/OpenMM.h b/openmmapi/include/OpenMM.h index fce5d6175..1c4f7db99 100644 --- a/openmmapi/include/OpenMM.h +++ b/openmmapi/include/OpenMM.h @@ -49,6 +49,7 @@ #include "openmm/CustomIntegrator.h" #include "openmm/CustomManyParticleForce.h" #include "openmm/CustomNonbondedForce.h" +#include "openmm/CustomVolumeForce.h" #include "openmm/DPDIntegrator.h" #include "openmm/Force.h" #include "openmm/GayBerneForce.h" diff --git a/openmmapi/include/openmm/CustomVolumeForce.h b/openmmapi/include/openmm/CustomVolumeForce.h new file mode 100644 index 000000000..771275cab --- /dev/null +++ b/openmmapi/include/openmm/CustomVolumeForce.h @@ -0,0 +1,160 @@ +#ifndef OPENMM_CUSTOMVOLUMEFORCE_H_ +#define OPENMM_CUSTOMVOLUMEFORCE_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) 2025 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 "Force.h" +#include "internal/windowsExport.h" +#include + +namespace OpenMM { + +/** + * This class computes an energy that depends only on the volume of the periodic box, or more generally + * on the box shape as specified by the elements of the box vectors. Because the energy does not + * depend on particle positions, it does not apply any forces to particles. It is primarily useful + * for constant pressure simulations, where the volume-dependent energy can influence the behavior + * of the barostat. Energy terms of this sort are often used for pressure matching in coarse grained + * force fields. + * + * To use this class, create a CustomVolumeForce object, passing an algebraic expression to the constructor + * that defines the energy. The expression may depend on the following variables. + * + * + * + * The initial value of a global parameter is specified in the call to addGlobalParameter(). Theire values + * can be modified during a simulation by calling Context::setParameter(). + * + * Expressions may involve the operators + (add), - (subtract), * (multiply), / (divide), and ^ (power), and the following + * functions: sqrt, exp, log, sin, cos, sec, csc, tan, cot, asin, acos, atan, atan2, sinh, cosh, tanh, erf, erfc, min, max, abs, floor, ceil, step, delta, select. All trigonometric functions + * are defined in radians, and log is the natural logarithm. step(x) = 0 if x is less than 0, 1 otherwise. delta(x) = 1 if x is 0, 0 otherwise. + * select(x,y,z) = z if x = 0, y otherwise. + */ + +class OPENMM_EXPORT CustomVolumeForce : public Force { +public: + /** + * Create a CustomVolumeForce. + * + * @param energy an algebraic expression giving the energy as a function of the box shape + */ + explicit CustomVolumeForce(const std::string& energy); + /** + * Get the number of global parameters that the energy depends on. + */ + int getNumGlobalParameters() const { + return globalParameters.size(); + } + /** + * Get the algebraic expression that defines the energy. + */ + const std::string& getEnergyFunction() const; + /** + * Set the algebraic expression that defines the energy. + */ + void setEnergyFunction(const std::string& energy); + /** + * Add a new global parameter that the interaction may depend on. The default value provided to + * this method is the initial value of the parameter in newly created Contexts. You can change + * the value at any time by calling setParameter() on the Context. + * + * @param name the name of the parameter + * @param defaultValue the default value of the parameter + * @return the index of the parameter that was added + */ + int addGlobalParameter(const std::string& name, double defaultValue); + /** + * Get the name of a global parameter. + * + * @param index the index of the parameter for which to get the name + * @return the parameter name + */ + const std::string& getGlobalParameterName(int index) const; + /** + * Set the name of a global parameter. + * + * @param index the index of the parameter for which to set the name + * @param name the name of the parameter + */ + void setGlobalParameterName(int index, const std::string& name); + /** + * Get the default value of a global parameter. + * + * @param index the index of the parameter for which to get the default value + * @return the parameter default value + */ + double getGlobalParameterDefaultValue(int index) const; + /** + * Set the default value of a global parameter. + * + * @param index the index of the parameter for which to set the default value + * @param defaultValue the default value of the parameter + */ + void setGlobalParameterDefaultValue(int index, double defaultValue); + /** + * Returns whether or not this force makes use of periodic boundary conditions. Because this + * class is only applicable to periodic systems, this always returns true. + */ + bool usesPeriodicBoundaryConditions() const { + return true; + } +protected: + ForceImpl* createImpl() const; +private: + class GlobalParameterInfo; + std::string energyExpression; + std::vector globalParameters; +}; + +/** + * This is an internal class used to record information about a global parameter. + * @private + */ +class CustomVolumeForce::GlobalParameterInfo { +public: + std::string name; + double defaultValue; + GlobalParameterInfo() { + } + GlobalParameterInfo(const std::string& name, double defaultValue) : name(name), defaultValue(defaultValue) { + } +}; + +} // namespace OpenMM + +#endif /*OPENMM_CUSTOMVOLUMEFORCE_H_*/ diff --git a/openmmapi/include/openmm/internal/CustomVolumeForceImpl.h b/openmmapi/include/openmm/internal/CustomVolumeForceImpl.h new file mode 100644 index 000000000..9022af555 --- /dev/null +++ b/openmmapi/include/openmm/internal/CustomVolumeForceImpl.h @@ -0,0 +1,67 @@ +#ifndef OPENMM_CUSTOMVOLUMEFORCEIMPL_H_ +#define OPENMM_CUSTOMVOLUMEFORCEIMPL_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) 2025 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 "CustomCPPForceImpl.h" +#include "openmm/CustomVolumeForce.h" +#include "lepton/CompiledExpression.h" +#include + +namespace OpenMM { + +/** + * This is the internal implementation of CustomVolumeForce. + */ + +class CustomVolumeForceImpl : public CustomCPPForceImpl { +public: + CustomVolumeForceImpl(const CustomVolumeForce& owner); + void initialize(ContextImpl& context); + const CustomVolumeForce& getOwner() const { + return owner; + } + double computeForce(ContextImpl& context, const std::vector& positions, std::vector& forces); + std::map getDefaultParameters(); +private: + const CustomVolumeForce& owner; + std::map defaultParameters; + Lepton::CompiledExpression energyExpression; + std::vector globalParameterNames; + std::vector globalValues; + Vec3 a, b, c; + double volume; +}; + +} // namespace OpenMM + +#endif /*OPENMM_CUSTOMVOLUMEFORCEIMPL_H_*/ diff --git a/openmmapi/src/CustomVolumeForce.cpp b/openmmapi/src/CustomVolumeForce.cpp new file mode 100644 index 000000000..1fdac8f90 --- /dev/null +++ b/openmmapi/src/CustomVolumeForce.cpp @@ -0,0 +1,77 @@ +/* -------------------------------------------------------------------------- * + * 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) 2025 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/CustomVolumeForce.h" +#include "openmm/internal/AssertionUtilities.h" +#include "openmm/internal/CustomVolumeForceImpl.h" + +using namespace OpenMM; +using namespace std; + +CustomVolumeForce::CustomVolumeForce(const string& energy) : energyExpression(energy) { +} + +const string& CustomVolumeForce::getEnergyFunction() const { + return energyExpression; +} + +void CustomVolumeForce::setEnergyFunction(const std::string& energy) { + energyExpression = energy; +} + +int CustomVolumeForce::addGlobalParameter(const string& name, double defaultValue) { + globalParameters.push_back(GlobalParameterInfo(name, defaultValue)); + return globalParameters.size()-1; +} + +const string& CustomVolumeForce::getGlobalParameterName(int index) const { + ASSERT_VALID_INDEX(index, globalParameters); + return globalParameters[index].name; +} + +void CustomVolumeForce::setGlobalParameterName(int index, const string& name) { + ASSERT_VALID_INDEX(index, globalParameters); + globalParameters[index].name = name; +} + +double CustomVolumeForce::getGlobalParameterDefaultValue(int index) const { + ASSERT_VALID_INDEX(index, globalParameters); + return globalParameters[index].defaultValue; +} + +void CustomVolumeForce::setGlobalParameterDefaultValue(int index, double defaultValue) { + ASSERT_VALID_INDEX(index, globalParameters); + globalParameters[index].defaultValue = defaultValue; +} + +ForceImpl* CustomVolumeForce::createImpl() const { + return new CustomVolumeForceImpl(*this); +} diff --git a/openmmapi/src/CustomVolumeForceImpl.cpp b/openmmapi/src/CustomVolumeForceImpl.cpp new file mode 100644 index 000000000..6b0d0b26b --- /dev/null +++ b/openmmapi/src/CustomVolumeForceImpl.cpp @@ -0,0 +1,76 @@ +/* -------------------------------------------------------------------------- * + * 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) 2025 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#include "openmm/internal/CustomVolumeForceImpl.h" +#include "openmm/internal/ContextImpl.h" +#include "lepton/ParsedExpression.h" +#include "lepton/Parser.h" + +using namespace OpenMM; +using namespace std; + +CustomVolumeForceImpl::CustomVolumeForceImpl(const CustomVolumeForce& owner) : CustomCPPForceImpl(owner), owner(owner) { + Lepton::ParsedExpression expression = Lepton::Parser::parse(owner.getEnergyFunction()); + energyExpression = expression.createCompiledExpression(); + map variableLocations; + globalParameterNames.resize(owner.getNumGlobalParameters()); + globalValues.resize(owner.getNumGlobalParameters()); + for (int i = 0; i < owner.getNumGlobalParameters(); i++) { + string name = owner.getGlobalParameterName(i); + defaultParameters[name] = owner.getGlobalParameterDefaultValue(i); + globalParameterNames[i] = name; + variableLocations[name] = &globalValues[i]; + } + variableLocations["v"] = &volume; + variableLocations["ax"] = &a[0]; + variableLocations["bx"] = &b[0]; + variableLocations["by"] = &b[1]; + variableLocations["cx"] = &c[0]; + variableLocations["cy"] = &c[1]; + variableLocations["cz"] = &c[2]; + energyExpression.setVariableLocations(variableLocations); +} + +void CustomVolumeForceImpl::initialize(ContextImpl& context) { + CustomCPPForceImpl::initialize(context); +} + +double CustomVolumeForceImpl::computeForce(ContextImpl& context, const vector& positions, vector& forces) { + for (int i = 0; i < globalParameterNames.size(); i++) + globalValues[i] = context.getParameter(globalParameterNames[i]); + context.getPeriodicBoxVectors(a, b, c); + volume = a[0]*b[1]*c[2]; + return energyExpression.evaluate(); +} + +map CustomVolumeForceImpl::getDefaultParameters() { + return defaultParameters; +} diff --git a/serialization/include/openmm/serialization/CustomVolumeForceProxy.h b/serialization/include/openmm/serialization/CustomVolumeForceProxy.h new file mode 100644 index 000000000..70b993e95 --- /dev/null +++ b/serialization/include/openmm/serialization/CustomVolumeForceProxy.h @@ -0,0 +1,53 @@ +#ifndef OPENMM_CUSTOMVOLUMEFORCE_PROXY_H_ +#define OPENMM_CUSTOMVOLUMEFORCE_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) 2025 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#include "openmm/internal/windowsExport.h" +#include "openmm/serialization/SerializationProxy.h" + +namespace OpenMM { + +/** + * This is a proxy for serializing CustomVolumeForce objects. + */ + +class OPENMM_EXPORT CustomVolumeForceProxy : public SerializationProxy { +public: + CustomVolumeForceProxy(); + void serialize(const void* object, SerializationNode& node) const; + void* deserialize(const SerializationNode& node) const; +}; + +} // namespace OpenMM + +#endif /*OPENMM_CUSTOMVOLUMEFORCE_PROXY_H_*/ diff --git a/serialization/src/CustomVolumeForceProxy.cpp b/serialization/src/CustomVolumeForceProxy.cpp new file mode 100644 index 000000000..ea80e2771 --- /dev/null +++ b/serialization/src/CustomVolumeForceProxy.cpp @@ -0,0 +1,75 @@ +/* -------------------------------------------------------------------------- * + * 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) 2025 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/CustomVolumeForceProxy.h" +#include "openmm/serialization/SerializationNode.h" +#include "openmm/Force.h" +#include "openmm/CustomVolumeForce.h" +#include + +using namespace OpenMM; +using namespace std; + +CustomVolumeForceProxy::CustomVolumeForceProxy() : SerializationProxy("CustomVolumeForce") { +} + +void CustomVolumeForceProxy::serialize(const void* object, SerializationNode& node) const { + node.setIntProperty("version", 0); + const CustomVolumeForce& force = *reinterpret_cast(object); + node.setIntProperty("forceGroup", force.getForceGroup()); + node.setStringProperty("name", force.getName()); + node.setStringProperty("energy", force.getEnergyFunction()); + SerializationNode& globalParams = node.createChildNode("GlobalParameters"); + for (int i = 0; i < force.getNumGlobalParameters(); i++) { + globalParams.createChildNode("Parameter").setStringProperty("name", force.getGlobalParameterName(i)).setDoubleProperty("default", force.getGlobalParameterDefaultValue(i)); + } +} + +void* CustomVolumeForceProxy::deserialize(const SerializationNode& node) const { + int version = node.getIntProperty("version"); + if (version != 0) + throw OpenMMException("Unsupported version number"); + CustomVolumeForce* force = NULL; + try { + CustomVolumeForce* force = new CustomVolumeForce(node.getStringProperty("energy")); + force->setForceGroup(node.getIntProperty("forceGroup", 0)); + force->setName(node.getStringProperty("name", force->getName())); + const SerializationNode& globalParams = node.getChildNode("GlobalParameters"); + for (auto& parameter : globalParams.getChildren()) + force->addGlobalParameter(parameter.getStringProperty("name"), parameter.getDoubleProperty("default")); + return force; + } + catch (...) { + if (force != NULL) + delete force; + throw; + } +} diff --git a/serialization/src/SerializationProxyRegistration.cpp b/serialization/src/SerializationProxyRegistration.cpp index 27d82ea56..ad734c1d7 100644 --- a/serialization/src/SerializationProxyRegistration.cpp +++ b/serialization/src/SerializationProxyRegistration.cpp @@ -47,6 +47,7 @@ #include "openmm/CustomManyParticleForce.h" #include "openmm/CustomNonbondedForce.h" #include "openmm/CustomTorsionForce.h" +#include "openmm/CustomVolumeForce.h" #include "openmm/DPDIntegrator.h" #include "openmm/GayBerneForce.h" #include "openmm/GBSAOBCForce.h" @@ -88,6 +89,7 @@ #include "openmm/serialization/CustomManyParticleForceProxy.h" #include "openmm/serialization/CustomNonbondedForceProxy.h" #include "openmm/serialization/CustomTorsionForceProxy.h" +#include "openmm/serialization/CustomVolumeForceProxy.h" #include "openmm/serialization/DPDIntegratorProxy.h" #include "openmm/serialization/GayBerneForceProxy.h" #include "openmm/serialization/GBSAOBCForceProxy.h" @@ -147,6 +149,7 @@ extern "C" void registerSerializationProxies() { SerializationProxy::registerProxy(typeid(CustomManyParticleForce), new CustomManyParticleForceProxy()); SerializationProxy::registerProxy(typeid(CustomNonbondedForce), new CustomNonbondedForceProxy()); SerializationProxy::registerProxy(typeid(CustomTorsionForce), new CustomTorsionForceProxy()); + SerializationProxy::registerProxy(typeid(CustomVolumeForce), new CustomVolumeForceProxy()); SerializationProxy::registerProxy(typeid(Discrete1DFunction), new Discrete1DFunctionProxy()); SerializationProxy::registerProxy(typeid(Discrete2DFunction), new Discrete2DFunctionProxy()); SerializationProxy::registerProxy(typeid(Discrete3DFunction), new Discrete3DFunctionProxy()); diff --git a/serialization/tests/TestSerializeCustomVolumeForce.cpp b/serialization/tests/TestSerializeCustomVolumeForce.cpp new file mode 100644 index 000000000..45a0ed3c9 --- /dev/null +++ b/serialization/tests/TestSerializeCustomVolumeForce.cpp @@ -0,0 +1,79 @@ +/* -------------------------------------------------------------------------- * + * 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) 2025 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#include "openmm/internal/AssertionUtilities.h" +#include "openmm/CustomVolumeForce.h" +#include "openmm/serialization/XmlSerializer.h" +#include +#include + +using namespace OpenMM; +using namespace std; + +void testSerialization() { + // Create a Force. + + CustomVolumeForce force("2*v-by"); + force.setForceGroup(3); + force.setName("custom name"); + force.addGlobalParameter("x", 1.3); + force.addGlobalParameter("y", 2.221); + + // Serialize and then deserialize it. + + stringstream buffer; + XmlSerializer::serialize(&force, "Force", buffer); + CustomVolumeForce* copy = XmlSerializer::deserialize(buffer); + + // Compare the two forces to see if they are identical. + + CustomVolumeForce& force2 = *copy; + ASSERT_EQUAL(force.getForceGroup(), force2.getForceGroup()); + ASSERT_EQUAL(force.getName(), force2.getName()); + ASSERT_EQUAL(force.getEnergyFunction(), force2.getEnergyFunction()); + ASSERT_EQUAL(force.getNumGlobalParameters(), force2.getNumGlobalParameters()); + for (int i = 0; i < force.getNumGlobalParameters(); i++) { + ASSERT_EQUAL(force.getGlobalParameterName(i), force2.getGlobalParameterName(i)); + ASSERT_EQUAL(force.getGlobalParameterDefaultValue(i), force2.getGlobalParameterDefaultValue(i)); + } +} + +int main() { + try { + testSerialization(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +} diff --git a/tests/TestCustomVolumeForce.cpp b/tests/TestCustomVolumeForce.cpp new file mode 100644 index 000000000..a93b39f8f --- /dev/null +++ b/tests/TestCustomVolumeForce.cpp @@ -0,0 +1,135 @@ +/* -------------------------------------------------------------------------- * + * 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) 2025 Stanford University and the Authors. * + * Authors: Peter Eastman * + * Contributors: * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * + * USE OR OTHER DEALINGS IN THE SOFTWARE. * + * -------------------------------------------------------------------------- */ + +#include "openmm/internal/AssertionUtilities.h" +#include "openmm/Context.h" +#include "openmm/CustomVolumeForce.h" +#include "openmm/Platform.h" +#include "openmm/VerletIntegrator.h" +#include "sfmt/SFMT.h" +#include + +using namespace OpenMM; +using namespace std; + +void testVolume() { + System system; + Vec3 a(2, 0, 0); + Vec3 b(0.1, 2, 0); + Vec3 c(0.1, 0.1, 2); + system.setDefaultPeriodicBoxVectors(a, b, c); + system.addParticle(1.0); + CustomVolumeForce* force = new CustomVolumeForce("2*v"); + system.addForce(force); + VerletIntegrator integrator(0.01); + Context context(system, integrator, Platform::getPlatform("Reference")); + context.setPositions({Vec3()}); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + for (int i = 0; i < 10; i++) { + a[0] = 2.0 + 0.1*genrand_real2(sfmt); + b[1] = 2.0 + 0.1*genrand_real2(sfmt); + c[2] = 2.0 + 0.1*genrand_real2(sfmt); + b[0] = 0.1*genrand_real2(sfmt); + c[0] = 0.1*genrand_real2(sfmt); + c[1] = 0.1*genrand_real2(sfmt); + context.setPeriodicBoxVectors(a, b, c); + double energy = context.getState(State::Energy).getPotentialEnergy(); + ASSERT_EQUAL_TOL(2*a[0]*b[1]*c[2], energy, 1e-6); + } +} + +void testBoxVectors() { + System system; + Vec3 a(2, 0, 0); + Vec3 b(0.1, 2, 0); + Vec3 c(0.1, 0.1, 2); + system.setDefaultPeriodicBoxVectors(a, b, c); + system.addParticle(1.0); + CustomVolumeForce* force = new CustomVolumeForce("1 + ax + 2*bx + 3*by + 4*cx + 5*cy + 6*cz"); + system.addForce(force); + VerletIntegrator integrator(0.01); + Context context(system, integrator, Platform::getPlatform("Reference")); + context.setPositions({Vec3()}); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + for (int i = 0; i < 10; i++) { + a[0] = 2.0 + 0.1*genrand_real2(sfmt); + b[1] = 2.0 + 0.1*genrand_real2(sfmt); + c[2] = 2.0 + 0.1*genrand_real2(sfmt); + b[0] = 0.1*genrand_real2(sfmt); + c[0] = 0.1*genrand_real2(sfmt); + c[1] = 0.1*genrand_real2(sfmt); + context.setPeriodicBoxVectors(a, b, c); + double energy = context.getState(State::Energy).getPotentialEnergy(); + ASSERT_EQUAL_TOL(1+a[0]+2*b[0]+3*b[1]+4*c[0]+5*c[1]+6*c[2], energy, 1e-6); + } +} + +void testGlobalParameters() { + System system; + Vec3 a(2, 0, 0); + Vec3 b(0, 2, 0); + Vec3 c(0, 0, 3); + system.setDefaultPeriodicBoxVectors(a, b, c); + system.addParticle(1.0); + CustomVolumeForce* force = new CustomVolumeForce("p1*ax + p2*cz"); + force->addGlobalParameter("p1", 1.0); + force->addGlobalParameter("p2", 1.0); + system.addForce(force); + VerletIntegrator integrator(0.01); + Context context(system, integrator, Platform::getPlatform("Reference")); + context.setPositions({Vec3()}); + OpenMM_SFMT::SFMT sfmt; + init_gen_rand(0, sfmt); + for (int i = 0; i < 10; i++) { + double p1 = genrand_real2(sfmt); + double p2 = genrand_real2(sfmt); + context.setParameter("p1", p1); + context.setParameter("p2", p2); + double energy = context.getState(State::Energy).getPotentialEnergy(); + ASSERT_EQUAL_TOL(2*p1+3*p2, energy, 1e-6); + } +} + +int main(int argc, char* argv[]) { + try { + testVolume(); + testBoxVectors(); + testGlobalParameters(); + } + catch(const exception& e) { + cout << "exception: " << e.what() << endl; + return 1; + } + cout << "Done" << endl; + return 0; +}