/* Portions copyright (c) 2009-2017 Stanford University and Simbios. * Contributors: Peter Eastman * * 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 "ReferenceCustomCVForce.h" #include "ReferencePlatform.h" #include "ReferenceTabulatedFunction.h" #include "lepton/CustomFunction.h" #include "lepton/ParsedExpression.h" #include "lepton/Parser.h" using namespace OpenMM; using namespace std; ReferenceCustomCVForce::ReferenceCustomCVForce(const CustomCVForce& force) { // Create custom functions for the tabulated functions. map functions; for (int i = 0; i < (int) force.getNumTabulatedFunctions(); i++) functions[force.getTabulatedFunctionName(i)] = createReferenceTabulatedFunction(force.getTabulatedFunction(i)); // Create the expressions. Lepton::ParsedExpression energyExpr = Lepton::Parser::parse(force.getEnergyFunction(), functions); energyExpression = energyExpr.createProgram(); for (int i = 0; i < force.getNumCollectiveVariables(); i++) { string name = force.getCollectiveVariableName(i); variableNames.push_back(name); variableDerivExpressions.push_back(energyExpr.differentiate(name).optimize().createProgram()); } for (int i = 0; i < force.getNumEnergyParameterDerivatives(); i++) { string name = force.getEnergyParameterDerivativeName(i); paramDerivNames.push_back(name); paramDerivExpressions.push_back(energyExpr.differentiate(name).optimize().createProgram()); } // Delete the custom functions. for (auto& function : functions) delete function.second; } ReferenceCustomCVForce::~ReferenceCustomCVForce() { } void ReferenceCustomCVForce::calculateIxn(ContextImpl& innerContext, vector& atomCoordinates, const map& globalParameters, vector& forces, double* totalEnergy, map& energyParamDerivs) const { // Compute the collective variables, and their derivatives with respect to particle positions. int numCVs = variableNames.size(); ReferencePlatform::PlatformData* data = reinterpret_cast(innerContext.getPlatformData()); vector& innerForces = *((vector*) data->forces); map& innerDerivs = *((map*) data->energyParameterDerivatives); vector cvValues; vector > cvForces; vector > cvDerivs; for (int i = 0; i < numCVs; i++) { cvValues.push_back(innerContext.calcForcesAndEnergy(true, true, 1< variables = globalParameters; for (int i = 0; i < numCVs; i++) variables[variableNames[i]] = cvValues[i]; if (totalEnergy != NULL) *totalEnergy += energyExpression.evaluate(variables); for (int i = 0; i < numCVs; i++) { double dEdV = variableDerivExpressions[i].evaluate(variables); for (int j = 0; j < numParticles; j++) forces[j] += cvForces[i][j]*dEdV; } // Compute the energy parameter derivatives. for (int i = 0; i < paramDerivExpressions.size(); i++) energyParamDerivs[paramDerivNames[i]] += paramDerivExpressions[i].evaluate(variables); for (int i = 0; i < numCVs; i++) { double dEdV = variableDerivExpressions[i].evaluate(variables); for (auto& deriv : cvDerivs[i]) energyParamDerivs[deriv.first] += dEdV*deriv.second; } }