/* -------------------------------------------------------------------------- * * OpenMMAmoeba * * -------------------------------------------------------------------------- * * 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) 2008-2009 Stanford University and the Authors. * * Authors: * * Contributors: * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as published * * by the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public License * * along with this program. If not, see . * * -------------------------------------------------------------------------- */ #include "AmoebaReferenceKernels.h" #include "AmoebaReferenceBondForce.h" #include "AmoebaReferenceAngleForce.h" #include "AmoebaReferenceInPlaneAngleForce.h" #include "AmoebaReferencePiTorsionForce.h" #include "AmoebaReferenceStretchBendForce.h" #include "AmoebaReferenceOutOfPlaneBendForce.h" #include "AmoebaReferenceTorsionTorsionForce.h" #include "AmoebaReferenceVdwForce.h" #include "AmoebaReferenceWcaDispersionForce.h" #include "AmoebaReferenceGeneralizedKirkwoodForce.h" #include "openmm/internal/AmoebaTorsionTorsionForceImpl.h" #include "openmm/internal/AmoebaWcaDispersionForceImpl.h" #include "ReferencePlatform.h" #include "openmm/internal/ContextImpl.h" #include "openmm/AmoebaMultipoleForce.h" #include "openmm/internal/AmoebaMultipoleForceImpl.h" #include "openmm/internal/AmoebaVdwForceImpl.h" #include "openmm/internal/AmoebaGeneralizedKirkwoodForceImpl.h" #include "openmm/NonbondedForce.h" #include "openmm/internal/NonbondedForceImpl.h" #include #ifdef _MSC_VER #include #endif using namespace OpenMM; using namespace std; static vector& extractPositions(ContextImpl& context) { ReferencePlatform::PlatformData* data = reinterpret_cast(context.getPlatformData()); return *((vector*) data->positions); } static vector& extractVelocities(ContextImpl& context) { ReferencePlatform::PlatformData* data = reinterpret_cast(context.getPlatformData()); return *((vector*) data->velocities); } static vector& extractForces(ContextImpl& context) { ReferencePlatform::PlatformData* data = reinterpret_cast(context.getPlatformData()); return *((vector*) data->forces); } static RealVec& extractBoxSize(ContextImpl& context) { ReferencePlatform::PlatformData* data = reinterpret_cast(context.getPlatformData()); return *(RealVec*) data->periodicBoxSize; } // *************************************************************************** ReferenceCalcAmoebaBondForceKernel::ReferenceCalcAmoebaBondForceKernel(std::string name, const Platform& platform, System& system) : CalcAmoebaBondForceKernel(name, platform), system(system) { } ReferenceCalcAmoebaBondForceKernel::~ReferenceCalcAmoebaBondForceKernel() { } void ReferenceCalcAmoebaBondForceKernel::initialize(const System& system, const AmoebaBondForce& force) { numBonds = force.getNumBonds(); for( int ii = 0; ii < numBonds; ii++) { int particle1Index, particle2Index; double lengthValue, kValue; force.getBondParameters(ii, particle1Index, particle2Index, lengthValue, kValue ); particle1.push_back( particle1Index ); particle2.push_back( particle2Index ); length.push_back( static_cast( lengthValue ) ); kQuadratic.push_back( static_cast( kValue ) ); } globalBondCubic = static_cast(force.getAmoebaGlobalBondCubic()); globalBondQuartic = static_cast(force.getAmoebaGlobalBondQuartic()); } double ReferenceCalcAmoebaBondForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { vector& posData = extractPositions(context); vector& forceData = extractForces(context); AmoebaReferenceBondForce amoebaReferenceBondForce; RealOpenMM energy = amoebaReferenceBondForce.calculateForceAndEnergy( numBonds, posData, particle1, particle2, length, kQuadratic, globalBondCubic, globalBondQuartic, forceData ); return static_cast(energy); } void ReferenceCalcAmoebaBondForceKernel::copyParametersToContext(ContextImpl& context, const AmoebaBondForce& force) { if (numBonds != force.getNumBonds()) throw OpenMMException("updateParametersInContext: The number of bonds has changed"); // Record the values. for (int i = 0; i < numBonds; ++i) { int particle1Index, particle2Index; double lengthValue, kValue; force.getBondParameters(i, particle1Index, particle2Index, lengthValue, kValue); if (particle1Index != particle1[i] || particle2Index != particle2[i]) throw OpenMMException("updateParametersInContext: The set of particles in a bond has changed"); length[i] = (RealOpenMM) lengthValue; kQuadratic[i] = (RealOpenMM) kValue; } } // *************************************************************************** ReferenceCalcAmoebaAngleForceKernel::ReferenceCalcAmoebaAngleForceKernel(std::string name, const Platform& platform, System& system) : CalcAmoebaAngleForceKernel(name, platform), system(system) { } ReferenceCalcAmoebaAngleForceKernel::~ReferenceCalcAmoebaAngleForceKernel() { } void ReferenceCalcAmoebaAngleForceKernel::initialize(const System& system, const AmoebaAngleForce& force) { numAngles = force.getNumAngles(); for (int ii = 0; ii < numAngles; ii++) { int particle1Index, particle2Index, particle3Index; double angleValue, k; force.getAngleParameters(ii, particle1Index, particle2Index, particle3Index, angleValue, k); particle1.push_back( particle1Index ); particle2.push_back( particle2Index ); particle3.push_back( particle3Index ); angle.push_back( static_cast( angleValue ) ); kQuadratic.push_back( static_cast( k) ); } globalAngleCubic = static_cast(force.getAmoebaGlobalAngleCubic()); globalAngleQuartic = static_cast(force.getAmoebaGlobalAngleQuartic()); globalAnglePentic = static_cast(force.getAmoebaGlobalAnglePentic()); globalAngleSextic = static_cast(force.getAmoebaGlobalAngleSextic()); } double ReferenceCalcAmoebaAngleForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { vector& posData = extractPositions(context); vector& forceData = extractForces(context); AmoebaReferenceAngleForce amoebaReferenceAngleForce; RealOpenMM energy = amoebaReferenceAngleForce.calculateForceAndEnergy( numAngles, posData, particle1, particle2, particle3, angle, kQuadratic, globalAngleCubic, globalAngleQuartic, globalAnglePentic, globalAngleSextic, forceData ); return static_cast(energy); } void ReferenceCalcAmoebaAngleForceKernel::copyParametersToContext(ContextImpl& context, const AmoebaAngleForce& force) { if (numAngles != force.getNumAngles()) throw OpenMMException("updateParametersInContext: The number of angles has changed"); // Record the values. for (int i = 0; i < numAngles; ++i) { int particle1Index, particle2Index, particle3Index; double angleValue, k; force.getAngleParameters(i, particle1Index, particle2Index, particle3Index, angleValue, k); if (particle1Index != particle1[i] || particle2Index != particle2[i] || particle3Index != particle3[i]) throw OpenMMException("updateParametersInContext: The set of particles in an angle has changed"); angle[i] = (RealOpenMM) angleValue; kQuadratic[i] = (RealOpenMM) k; } } ReferenceCalcAmoebaInPlaneAngleForceKernel::ReferenceCalcAmoebaInPlaneAngleForceKernel(std::string name, const Platform& platform, System& system) : CalcAmoebaInPlaneAngleForceKernel(name, platform), system(system) { } ReferenceCalcAmoebaInPlaneAngleForceKernel::~ReferenceCalcAmoebaInPlaneAngleForceKernel() { } void ReferenceCalcAmoebaInPlaneAngleForceKernel::initialize(const System& system, const AmoebaInPlaneAngleForce& force) { numAngles = force.getNumAngles(); for (int ii = 0; ii < numAngles; ii++) { int particle1Index, particle2Index, particle3Index, particle4Index; double angleValue, k; force.getAngleParameters(ii, particle1Index, particle2Index, particle3Index, particle4Index, angleValue, k); particle1.push_back( particle1Index ); particle2.push_back( particle2Index ); particle3.push_back( particle3Index ); particle4.push_back( particle4Index ); angle.push_back( static_cast( angleValue ) ); kQuadratic.push_back( static_cast( k ) ); } globalInPlaneAngleCubic = static_cast(force.getAmoebaGlobalInPlaneAngleCubic()); globalInPlaneAngleQuartic = static_cast(force.getAmoebaGlobalInPlaneAngleQuartic()); globalInPlaneAnglePentic = static_cast(force.getAmoebaGlobalInPlaneAnglePentic()); globalInPlaneAngleSextic = static_cast(force.getAmoebaGlobalInPlaneAngleSextic()); } double ReferenceCalcAmoebaInPlaneAngleForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { vector& posData = extractPositions(context); vector& forceData = extractForces(context); AmoebaReferenceInPlaneAngleForce amoebaReferenceInPlaneAngleForce; RealOpenMM energy = amoebaReferenceInPlaneAngleForce.calculateForceAndEnergy( numAngles, posData, particle1, particle2, particle3, particle4, angle, kQuadratic, globalInPlaneAngleCubic, globalInPlaneAngleQuartic, globalInPlaneAnglePentic, globalInPlaneAngleSextic, forceData ); return static_cast(energy); } void ReferenceCalcAmoebaInPlaneAngleForceKernel::copyParametersToContext(ContextImpl& context, const AmoebaInPlaneAngleForce& force) { if (numAngles != force.getNumAngles()) throw OpenMMException("updateParametersInContext: The number of angles has changed"); // Record the values. for (int i = 0; i < numAngles; ++i) { int particle1Index, particle2Index, particle3Index, particle4Index; double angleValue, k; force.getAngleParameters(i, particle1Index, particle2Index, particle3Index, particle4Index, angleValue, k); if (particle1Index != particle1[i] || particle2Index != particle2[i] || particle3Index != particle3[i] || particle4Index != particle4[i]) throw OpenMMException("updateParametersInContext: The set of particles in an angle has changed"); angle[i] = (RealOpenMM) angleValue; kQuadratic[i] = (RealOpenMM) k; } } ReferenceCalcAmoebaPiTorsionForceKernel::ReferenceCalcAmoebaPiTorsionForceKernel(std::string name, const Platform& platform, System& system) : CalcAmoebaPiTorsionForceKernel(name, platform), system(system) { } ReferenceCalcAmoebaPiTorsionForceKernel::~ReferenceCalcAmoebaPiTorsionForceKernel() { } void ReferenceCalcAmoebaPiTorsionForceKernel::initialize(const System& system, const AmoebaPiTorsionForce& force) { numPiTorsions = force.getNumPiTorsions(); for (int ii = 0; ii < numPiTorsions; ii++) { int particle1Index, particle2Index, particle3Index, particle4Index, particle5Index, particle6Index; double kTorsionParameter; force.getPiTorsionParameters(ii, particle1Index, particle2Index, particle3Index, particle4Index, particle5Index, particle6Index, kTorsionParameter ); particle1.push_back( particle1Index ); particle2.push_back( particle2Index ); particle3.push_back( particle3Index ); particle4.push_back( particle4Index ); particle5.push_back( particle5Index ); particle6.push_back( particle6Index ); kTorsion.push_back( static_cast(kTorsionParameter) ); } } double ReferenceCalcAmoebaPiTorsionForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { vector& posData = extractPositions(context); vector& forceData = extractForces(context); AmoebaReferencePiTorsionForce amoebaReferencePiTorsionForce; RealOpenMM energy = amoebaReferencePiTorsionForce.calculateForceAndEnergy( numPiTorsions, posData, particle1, particle2, particle3, particle4, particle5, particle6, kTorsion, forceData ); return static_cast(energy); } void ReferenceCalcAmoebaPiTorsionForceKernel::copyParametersToContext(ContextImpl& context, const AmoebaPiTorsionForce& force) { if (numPiTorsions != force.getNumPiTorsions()) throw OpenMMException("updateParametersInContext: The number of torsions has changed"); // Record the values. for (int i = 0; i < numPiTorsions; ++i) { int particle1Index, particle2Index, particle3Index, particle4Index, particle5Index, particle6Index; double kTorsionParameter; force.getPiTorsionParameters(i, particle1Index, particle2Index, particle3Index, particle4Index, particle5Index, particle6Index, kTorsionParameter); if (particle1Index != particle1[i] || particle2Index != particle2[i] || particle3Index != particle3[i] || particle4Index != particle4[i] || particle5Index != particle5[i] || particle6Index != particle6[i]) throw OpenMMException("updateParametersInContext: The set of particles in a torsion has changed"); kTorsion[i] = (RealOpenMM) kTorsionParameter; } } ReferenceCalcAmoebaStretchBendForceKernel::ReferenceCalcAmoebaStretchBendForceKernel(std::string name, const Platform& platform, System& system) : CalcAmoebaStretchBendForceKernel(name, platform), system(system) { } ReferenceCalcAmoebaStretchBendForceKernel::~ReferenceCalcAmoebaStretchBendForceKernel() { } void ReferenceCalcAmoebaStretchBendForceKernel::initialize(const System& system, const AmoebaStretchBendForce& force) { numStretchBends = force.getNumStretchBends(); for ( int ii = 0; ii < numStretchBends; ii++) { int particle1Index, particle2Index, particle3Index; double lengthAB, lengthCB, angle, k; force.getStretchBendParameters(ii, particle1Index, particle2Index, particle3Index, lengthAB, lengthCB, angle, k); particle1.push_back( particle1Index ); particle2.push_back( particle2Index ); particle3.push_back( particle3Index ); lengthABParameters.push_back( static_cast(lengthAB) ); lengthCBParameters.push_back( static_cast(lengthCB) ); angleParameters.push_back( static_cast(angle) ); kParameters.push_back( static_cast(k) ); } } double ReferenceCalcAmoebaStretchBendForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { vector& posData = extractPositions(context); vector& forceData = extractForces(context); AmoebaReferenceStretchBendForce amoebaReferenceStretchBendForce; RealOpenMM energy = amoebaReferenceStretchBendForce.calculateForceAndEnergy( numStretchBends, posData, particle1, particle2, particle3, lengthABParameters, lengthCBParameters, angleParameters, kParameters, forceData ); return static_cast(energy); } void ReferenceCalcAmoebaStretchBendForceKernel::copyParametersToContext(ContextImpl& context, const AmoebaStretchBendForce& force) { if (numStretchBends != force.getNumStretchBends()) throw OpenMMException("updateParametersInContext: The number of stretch-bends has changed"); // Record the values. for (int i = 0; i < numStretchBends; ++i) { int particle1Index, particle2Index, particle3Index; double lengthAB, lengthCB, angle, k; force.getStretchBendParameters(i, particle1Index, particle2Index, particle3Index, lengthAB, lengthCB, angle, k); if (particle1Index != particle1[i] || particle2Index != particle2[i] || particle3Index != particle3[i]) throw OpenMMException("updateParametersInContext: The set of particles in a stretch-bend has changed"); lengthABParameters[i] = (RealOpenMM) lengthAB; lengthCBParameters[i] = (RealOpenMM) lengthCB; angleParameters[i] = (RealOpenMM) angle; kParameters[i] = (RealOpenMM) k; } } ReferenceCalcAmoebaOutOfPlaneBendForceKernel::ReferenceCalcAmoebaOutOfPlaneBendForceKernel(std::string name, const Platform& platform, System& system) : CalcAmoebaOutOfPlaneBendForceKernel(name, platform), system(system) { } ReferenceCalcAmoebaOutOfPlaneBendForceKernel::~ReferenceCalcAmoebaOutOfPlaneBendForceKernel() { } void ReferenceCalcAmoebaOutOfPlaneBendForceKernel::initialize(const System& system, const AmoebaOutOfPlaneBendForce& force) { numOutOfPlaneBends = force.getNumOutOfPlaneBends(); for (int ii = 0; ii < numOutOfPlaneBends; ii++) { int particle1Index, particle2Index, particle3Index, particle4Index; double k; force.getOutOfPlaneBendParameters(ii, particle1Index, particle2Index, particle3Index, particle4Index, k); particle1.push_back( particle1Index ); particle2.push_back( particle2Index ); particle3.push_back( particle3Index ); particle4.push_back( particle4Index ); kParameters.push_back( static_cast(k) ); } globalOutOfPlaneBendAngleCubic = static_cast( force.getAmoebaGlobalOutOfPlaneBendCubic()); globalOutOfPlaneBendAngleQuartic = static_cast( force.getAmoebaGlobalOutOfPlaneBendQuartic()); globalOutOfPlaneBendAnglePentic = static_cast( force.getAmoebaGlobalOutOfPlaneBendPentic()); globalOutOfPlaneBendAngleSextic = static_cast( force.getAmoebaGlobalOutOfPlaneBendSextic()); } double ReferenceCalcAmoebaOutOfPlaneBendForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { vector& posData = extractPositions(context); vector& forceData = extractForces(context); AmoebaReferenceOutOfPlaneBendForce amoebaReferenceOutOfPlaneBendForce; RealOpenMM energy = amoebaReferenceOutOfPlaneBendForce.calculateForceAndEnergy( numOutOfPlaneBends, posData, particle1, particle2, particle3, particle4, kParameters, globalOutOfPlaneBendAngleCubic, globalOutOfPlaneBendAngleQuartic, globalOutOfPlaneBendAnglePentic, globalOutOfPlaneBendAngleSextic, forceData ); return static_cast(energy); } void ReferenceCalcAmoebaOutOfPlaneBendForceKernel::copyParametersToContext(ContextImpl& context, const AmoebaOutOfPlaneBendForce& force) { if (numOutOfPlaneBends != force.getNumOutOfPlaneBends()) throw OpenMMException("updateParametersInContext: The number of out-of-plane bends has changed"); // Record the values. for (int i = 0; i < numOutOfPlaneBends; ++i) { int particle1Index, particle2Index, particle3Index, particle4Index; double k; force.getOutOfPlaneBendParameters(i, particle1Index, particle2Index, particle3Index, particle4Index, k); if (particle1Index != particle1[i] || particle2Index != particle2[i] || particle3Index != particle3[i] || particle4Index != particle4[i]) throw OpenMMException("updateParametersInContext: The set of particles in an out-of-plane bend has changed"); kParameters[i] = (RealOpenMM) k; } } ReferenceCalcAmoebaTorsionTorsionForceKernel::ReferenceCalcAmoebaTorsionTorsionForceKernel(std::string name, const Platform& platform, System& system) : CalcAmoebaTorsionTorsionForceKernel(name, platform), system(system) { } ReferenceCalcAmoebaTorsionTorsionForceKernel::~ReferenceCalcAmoebaTorsionTorsionForceKernel() { } void ReferenceCalcAmoebaTorsionTorsionForceKernel::initialize(const System& system, const AmoebaTorsionTorsionForce& force) { numTorsionTorsions = force.getNumTorsionTorsions(); // torsion-torsion parameters for (int ii = 0; ii < numTorsionTorsions; ii++) { int particle1Index, particle2Index, particle3Index, particle4Index, particle5Index, chiralCheckAtomIndex, gridIndex; force.getTorsionTorsionParameters(ii, particle1Index, particle2Index, particle3Index, particle4Index, particle5Index, chiralCheckAtomIndex, gridIndex); particle1.push_back( particle1Index ); particle2.push_back( particle2Index ); particle3.push_back( particle3Index ); particle4.push_back( particle4Index ); particle5.push_back( particle5Index ); chiralCheckAtom.push_back( chiralCheckAtomIndex ); gridIndices.push_back( gridIndex ); } // torsion-torsion grids numTorsionTorsionGrids = force.getNumTorsionTorsionGrids(); torsionTorsionGrids.resize(numTorsionTorsionGrids); for (int ii = 0; ii < numTorsionTorsionGrids; ii++) { const TorsionTorsionGrid grid = force.getTorsionTorsionGrid( ii ); torsionTorsionGrids[ii].resize( grid.size() ); // check if grid needs to be reordered: x-angle should be 'slow' index TorsionTorsionGrid reorderedGrid; int reorder = 0; if( grid[0][0][0] != grid[0][1][0] ){ AmoebaTorsionTorsionForceImpl::reorderGrid( grid, reorderedGrid ); reorder = 1; } for (unsigned int kk = 0; kk < grid.size(); kk++) { torsionTorsionGrids[ii][kk].resize( grid[kk].size() ); for (unsigned int jj = 0; jj < grid[kk].size(); jj++) { torsionTorsionGrids[ii][kk][jj].resize( grid[kk][jj].size() ); if( reorder ){ for (unsigned int ll = 0; ll < grid[ll][jj].size(); ll++) { torsionTorsionGrids[ii][kk][jj][ll] = static_cast(reorderedGrid[kk][jj][ll]); } } else { for (unsigned int ll = 0; ll < grid[ll][jj].size(); ll++) { torsionTorsionGrids[ii][kk][jj][ll] = static_cast(grid[kk][jj][ll]); } } } } } } double ReferenceCalcAmoebaTorsionTorsionForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { vector& posData = extractPositions(context); vector& forceData = extractForces(context); AmoebaReferenceTorsionTorsionForce amoebaReferenceTorsionTorsionForce; RealOpenMM energy = amoebaReferenceTorsionTorsionForce.calculateForceAndEnergy( numTorsionTorsions, posData, particle1, particle2, particle3, particle4, particle5, chiralCheckAtom, gridIndices, torsionTorsionGrids, forceData ); return static_cast(energy); } /* -------------------------------------------------------------------------- * * AmoebaMultipole * * -------------------------------------------------------------------------- */ ReferenceCalcAmoebaMultipoleForceKernel::ReferenceCalcAmoebaMultipoleForceKernel(std::string name, const Platform& platform, System& system) : CalcAmoebaMultipoleForceKernel(name, platform), system(system), numMultipoles(0), mutualInducedMaxIterations(60), mutualInducedTargetEpsilon(1.0e-03), usePme(false),alphaEwald(0.0), cutoffDistance(1.0) { } ReferenceCalcAmoebaMultipoleForceKernel::~ReferenceCalcAmoebaMultipoleForceKernel() { } void ReferenceCalcAmoebaMultipoleForceKernel::initialize(const System& system, const AmoebaMultipoleForce& force) { numMultipoles = force.getNumMultipoles(); charges.resize(numMultipoles); dipoles.resize(3*numMultipoles); quadrupoles.resize(9*numMultipoles); tholes.resize(numMultipoles); dampingFactors.resize(numMultipoles); polarity.resize(numMultipoles); axisTypes.resize(numMultipoles); multipoleAtomZs.resize(numMultipoles); multipoleAtomXs.resize(numMultipoles); multipoleAtomYs.resize(numMultipoles); multipoleAtomCovalentInfo.resize(numMultipoles); int dipoleIndex = 0; int quadrupoleIndex = 0; int maxCovalentRange = 0; double totalCharge = 0.0; for( int ii = 0; ii < numMultipoles; ii++ ){ // multipoles int axisType, multipoleAtomZ, multipoleAtomX, multipoleAtomY; double charge, tholeD, dampingFactorD, polarityD; std::vector dipolesD; std::vector quadrupolesD; force.getMultipoleParameters(ii, charge, dipolesD, quadrupolesD, axisType, multipoleAtomZ, multipoleAtomX, multipoleAtomY, tholeD, dampingFactorD, polarityD ); totalCharge += charge; axisTypes[ii] = axisType; multipoleAtomZs[ii] = multipoleAtomZ; multipoleAtomXs[ii] = multipoleAtomX; multipoleAtomYs[ii] = multipoleAtomY; charges[ii] = static_cast(charge); tholes[ii] = static_cast(tholeD); dampingFactors[ii] = static_cast(dampingFactorD); polarity[ii] = static_cast(polarityD); dipoles[dipoleIndex++] = static_cast(dipolesD[0]); dipoles[dipoleIndex++] = static_cast(dipolesD[1]); dipoles[dipoleIndex++] = static_cast(dipolesD[2]); quadrupoles[quadrupoleIndex++] = static_cast(quadrupolesD[0]); quadrupoles[quadrupoleIndex++] = static_cast(quadrupolesD[1]); quadrupoles[quadrupoleIndex++] = static_cast(quadrupolesD[2]); quadrupoles[quadrupoleIndex++] = static_cast(quadrupolesD[3]); quadrupoles[quadrupoleIndex++] = static_cast(quadrupolesD[4]); quadrupoles[quadrupoleIndex++] = static_cast(quadrupolesD[5]); quadrupoles[quadrupoleIndex++] = static_cast(quadrupolesD[6]); quadrupoles[quadrupoleIndex++] = static_cast(quadrupolesD[7]); quadrupoles[quadrupoleIndex++] = static_cast(quadrupolesD[8]); // covalent info std::vector< std::vector > covalentLists; force.getCovalentMaps(ii, covalentLists ); multipoleAtomCovalentInfo[ii] = covalentLists; } polarizationType = force.getPolarizationType(); if( polarizationType == AmoebaMultipoleForce::Mutual ){ mutualInducedMaxIterations = force.getMutualInducedMaxIterations(); mutualInducedTargetEpsilon = force.getMutualInducedTargetEpsilon(); } // PME nonbondedMethod = force.getNonbondedMethod(); if( nonbondedMethod == AmoebaMultipoleForce::PME ){ usePme = true; alphaEwald = force.getAEwald(); cutoffDistance = force.getCutoffDistance(); force.getPmeGridDimensions(pmeGridDimension); if (pmeGridDimension[0] == 0 || alphaEwald == 0.0) { NonbondedForce nb; nb.setEwaldErrorTolerance(force.getEwaldErrorTolerance()); nb.setCutoffDistance(force.getCutoffDistance()); int gridSizeX, gridSizeY, gridSizeZ; NonbondedForceImpl::calcPMEParameters(system, nb, alphaEwald, gridSizeX, gridSizeY, gridSizeZ); pmeGridDimension[0] = gridSizeX; pmeGridDimension[1] = gridSizeY; pmeGridDimension[2] = gridSizeZ; } } else { usePme = false; } return; } AmoebaReferenceMultipoleForce* ReferenceCalcAmoebaMultipoleForceKernel::setupAmoebaReferenceMultipoleForce(ContextImpl& context ) { // amoebaReferenceMultipoleForce is set to AmoebaReferenceGeneralizedKirkwoodForce if AmoebaGeneralizedKirkwoodForce is present // amoebaReferenceMultipoleForce is set to AmoebaReferencePmeMultipoleForce if 'usePme' is set // amoebaReferenceMultipoleForce is set to AmoebaReferenceMultipoleForce otherwise // check if AmoebaGeneralizedKirkwoodForce is present ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel* gkKernel = NULL; for (unsigned int ii = 0; ii < context.getForceImpls().size() && gkKernel == NULL; ii++) { AmoebaGeneralizedKirkwoodForceImpl* gkImpl = dynamic_cast(context.getForceImpls()[ii]); if (gkImpl != NULL) { gkKernel = dynamic_cast(&gkImpl->getKernel().getImpl()); } } AmoebaReferenceMultipoleForce* amoebaReferenceMultipoleForce = NULL; if( gkKernel ){ // amoebaReferenceGeneralizedKirkwoodForce is deleted in AmoebaReferenceGeneralizedKirkwoodMultipoleForce // destructor AmoebaReferenceGeneralizedKirkwoodForce* amoebaReferenceGeneralizedKirkwoodForce = new AmoebaReferenceGeneralizedKirkwoodForce(); amoebaReferenceGeneralizedKirkwoodForce->setNumParticles( gkKernel->getNumParticles() ); amoebaReferenceGeneralizedKirkwoodForce->setSoluteDielectric( gkKernel->getSoluteDielectric() ); amoebaReferenceGeneralizedKirkwoodForce->setSolventDielectric( gkKernel->getSolventDielectric() ); amoebaReferenceGeneralizedKirkwoodForce->setDielectricOffset( gkKernel->getDielectricOffset() ); amoebaReferenceGeneralizedKirkwoodForce->setProbeRadius( gkKernel->getProbeRadius() ); amoebaReferenceGeneralizedKirkwoodForce->setSurfaceAreaFactor( gkKernel->getSurfaceAreaFactor() ); amoebaReferenceGeneralizedKirkwoodForce->setIncludeCavityTerm( gkKernel->getIncludeCavityTerm() ); amoebaReferenceGeneralizedKirkwoodForce->setDirectPolarization( gkKernel->getDirectPolarization() ); vector parameters; gkKernel->getAtomicRadii( parameters ); amoebaReferenceGeneralizedKirkwoodForce->setAtomicRadii( parameters ); gkKernel->getScaleFactors( parameters ); amoebaReferenceGeneralizedKirkwoodForce->setScaleFactors( parameters ); gkKernel->getCharges( parameters ); amoebaReferenceGeneralizedKirkwoodForce->setCharges( parameters ); // calculate Grycuk Born radii vector& posData = extractPositions(context); amoebaReferenceGeneralizedKirkwoodForce->calculateGrycukBornRadii( posData ); amoebaReferenceMultipoleForce = new AmoebaReferenceGeneralizedKirkwoodMultipoleForce( amoebaReferenceGeneralizedKirkwoodForce ); } else if( usePme ) { AmoebaReferencePmeMultipoleForce* amoebaReferencePmeMultipoleForce = new AmoebaReferencePmeMultipoleForce( ); amoebaReferencePmeMultipoleForce->setAlphaEwald( alphaEwald ); amoebaReferencePmeMultipoleForce->setCutoffDistance( cutoffDistance ); amoebaReferencePmeMultipoleForce->setPmeGridDimensions( pmeGridDimension ); RealVec& box = extractBoxSize(context); double minAllowedSize = 1.999999*cutoffDistance; if (box[0] < minAllowedSize || box[1] < minAllowedSize || box[2] < minAllowedSize){ throw OpenMMException("The periodic box size has decreased to less than twice the nonbonded cutoff."); } amoebaReferencePmeMultipoleForce->setPeriodicBoxSize(box); amoebaReferenceMultipoleForce = static_cast(amoebaReferencePmeMultipoleForce); } else { amoebaReferenceMultipoleForce = new AmoebaReferenceMultipoleForce( AmoebaReferenceMultipoleForce::NoCutoff ); } // set polarization type if( polarizationType == AmoebaMultipoleForce::Mutual ){ amoebaReferenceMultipoleForce->setPolarizationType( AmoebaReferenceMultipoleForce::Mutual ); amoebaReferenceMultipoleForce->setMutualInducedDipoleTargetEpsilon( mutualInducedTargetEpsilon ); amoebaReferenceMultipoleForce->setMaximumMutualInducedDipoleIterations( mutualInducedMaxIterations ); } else if( polarizationType == AmoebaMultipoleForce::Direct ){ amoebaReferenceMultipoleForce->setPolarizationType( AmoebaReferenceMultipoleForce::Direct ); } else { throw OpenMMException("Polarization type not recognzied." ); } return amoebaReferenceMultipoleForce; } double ReferenceCalcAmoebaMultipoleForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { AmoebaReferenceMultipoleForce* amoebaReferenceMultipoleForce = setupAmoebaReferenceMultipoleForce( context ); vector& posData = extractPositions(context); vector& forceData = extractForces(context); RealOpenMM energy = amoebaReferenceMultipoleForce->calculateForceAndEnergy( posData, charges, dipoles, quadrupoles, tholes, dampingFactors, polarity, axisTypes, multipoleAtomZs, multipoleAtomXs, multipoleAtomYs, multipoleAtomCovalentInfo, forceData); delete amoebaReferenceMultipoleForce; return static_cast(energy); } void ReferenceCalcAmoebaMultipoleForceKernel::getElectrostaticPotential(ContextImpl& context, const std::vector< Vec3 >& inputGrid, std::vector< double >& outputElectrostaticPotential ){ AmoebaReferenceMultipoleForce* amoebaReferenceMultipoleForce = setupAmoebaReferenceMultipoleForce( context ); vector& posData = extractPositions(context); vector grid( inputGrid.size() ); vector potential( inputGrid.size() ); for( unsigned int ii = 0; ii < inputGrid.size(); ii++ ){ grid[ii] = inputGrid[ii]; } amoebaReferenceMultipoleForce->calculateElectrostaticPotential( posData, charges, dipoles, quadrupoles, tholes, dampingFactors, polarity, axisTypes, multipoleAtomZs, multipoleAtomXs, multipoleAtomYs, multipoleAtomCovalentInfo, grid, potential ); outputElectrostaticPotential.resize( inputGrid.size() ); for( unsigned int ii = 0; ii < inputGrid.size(); ii++ ){ outputElectrostaticPotential[ii] = potential[ii]; } delete amoebaReferenceMultipoleForce; return; } void ReferenceCalcAmoebaMultipoleForceKernel::getSystemMultipoleMoments(ContextImpl& context, std::vector< double >& outputMultipoleMoments){ // retrieve masses System& system = context.getSystem(); vector masses; for (int i = 0; i < system.getNumParticles(); ++i) { masses.push_back( static_cast(system.getParticleMass(i)) ); } AmoebaReferenceMultipoleForce* amoebaReferenceMultipoleForce = setupAmoebaReferenceMultipoleForce( context ); vector& posData = extractPositions(context); amoebaReferenceMultipoleForce->calculateAmoebaSystemMultipoleMoments( masses, posData, charges, dipoles, quadrupoles, tholes, dampingFactors, polarity, axisTypes, multipoleAtomZs, multipoleAtomXs, multipoleAtomYs, multipoleAtomCovalentInfo, outputMultipoleMoments ); delete amoebaReferenceMultipoleForce; return; } void ReferenceCalcAmoebaMultipoleForceKernel::copyParametersToContext(ContextImpl& context, const AmoebaMultipoleForce& force) { if (numMultipoles != force.getNumMultipoles()) throw OpenMMException("updateParametersInContext: The number of multipoles has changed"); // Record the values. int dipoleIndex = 0; int quadrupoleIndex = 0; for (int i = 0; i < numMultipoles; ++i) { int axisType, multipoleAtomZ, multipoleAtomX, multipoleAtomY; double charge, tholeD, dampingFactorD, polarityD; std::vector dipolesD; std::vector quadrupolesD; force.getMultipoleParameters(i, charge, dipolesD, quadrupolesD, axisType, multipoleAtomZ, multipoleAtomX, multipoleAtomY, tholeD, dampingFactorD, polarityD); axisTypes[i] = axisType; multipoleAtomZs[i] = multipoleAtomZ; multipoleAtomXs[i] = multipoleAtomX; multipoleAtomYs[i] = multipoleAtomY; charges[i] = (RealOpenMM) charge; tholes[i] = (RealOpenMM) tholeD; dampingFactors[i] = (RealOpenMM) dampingFactorD; polarity[i] = (RealOpenMM) polarityD; dipoles[dipoleIndex++] = (RealOpenMM) dipolesD[0]; dipoles[dipoleIndex++] = (RealOpenMM) dipolesD[1]; dipoles[dipoleIndex++] = (RealOpenMM) dipolesD[2]; quadrupoles[quadrupoleIndex++] = (RealOpenMM) quadrupolesD[0]; quadrupoles[quadrupoleIndex++] = (RealOpenMM) quadrupolesD[1]; quadrupoles[quadrupoleIndex++] = (RealOpenMM) quadrupolesD[2]; quadrupoles[quadrupoleIndex++] = (RealOpenMM) quadrupolesD[3]; quadrupoles[quadrupoleIndex++] = (RealOpenMM) quadrupolesD[4]; quadrupoles[quadrupoleIndex++] = (RealOpenMM) quadrupolesD[5]; quadrupoles[quadrupoleIndex++] = (RealOpenMM) quadrupolesD[6]; quadrupoles[quadrupoleIndex++] = (RealOpenMM) quadrupolesD[7]; quadrupoles[quadrupoleIndex++] = (RealOpenMM) quadrupolesD[8]; } } /* -------------------------------------------------------------------------- * * AmoebaGeneralizedKirkwood * * -------------------------------------------------------------------------- */ ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel(std::string name, const Platform& platform, System& system) : CalcAmoebaGeneralizedKirkwoodForceKernel(name, platform), system(system) { } ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::~ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel() { } int ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getNumParticles( void ) const { return numParticles; } int ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getIncludeCavityTerm( void ) const { return includeCavityTerm; } int ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getDirectPolarization( void ) const { return directPolarization; } RealOpenMM ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getSoluteDielectric( void ) const { return soluteDielectric; } RealOpenMM ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getSolventDielectric( void ) const { return solventDielectric; } RealOpenMM ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getDielectricOffset( void ) const { return dielectricOffset; } RealOpenMM ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getProbeRadius( void ) const { return probeRadius; } RealOpenMM ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getSurfaceAreaFactor( void ) const { return surfaceAreaFactor; } void ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getAtomicRadii( vector& outputAtomicRadii ) const { outputAtomicRadii.resize( atomicRadii.size() ); copy( atomicRadii.begin(), atomicRadii.end(), outputAtomicRadii.begin() ); } void ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getScaleFactors( vector& outputScaleFactors ) const { outputScaleFactors.resize( scaleFactors.size() ); copy( scaleFactors.begin(), scaleFactors.end(), outputScaleFactors.begin() ); } void ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getCharges( vector& outputCharges ) const { outputCharges.resize( charges.size() ); copy( charges.begin(), charges.end(), outputCharges.begin() ); } void ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::initialize(const System& system, const AmoebaGeneralizedKirkwoodForce& force) { // check that AmoebaMultipoleForce is present const AmoebaMultipoleForce* amoebaMultipoleForce = NULL; for (int ii = 0; ii < system.getNumForces() && amoebaMultipoleForce == NULL; ii++) { amoebaMultipoleForce = dynamic_cast(&system.getForce(ii)); } if (amoebaMultipoleForce == NULL) { throw OpenMMException("AmoebaGeneralizedKirkwoodForce requires the System to also contain an AmoebaMultipoleForce."); } if (amoebaMultipoleForce->getNonbondedMethod() != AmoebaMultipoleForce::NoCutoff ) { throw OpenMMException("AmoebaGeneralizedKirkwoodForce requires the AmoebaMultipoleForce use the NoCutoff nonbonded method."); } numParticles = system.getNumParticles(); for( int ii = 0; ii < numParticles; ii++ ){ double particleCharge, particleRadius, scalingFactor; force.getParticleParameters(ii, particleCharge, particleRadius, scalingFactor); atomicRadii.push_back( static_cast( particleRadius ) ); scaleFactors.push_back( static_cast( scalingFactor ) ); charges.push_back( static_cast( particleCharge ) ); // Make sure the charge matches the one specified by the AmoebaMultipoleForce. double charge2, thole, damping, polarity; int axisType, atomX, atomY, atomZ; vector dipole, quadrupole; amoebaMultipoleForce->getMultipoleParameters( ii, charge2, dipole, quadrupole, axisType, atomZ, atomX, atomY, thole, damping, polarity); if ( particleCharge != charge2 ){ throw OpenMMException("AmoebaGeneralizedKirkwoodForce and AmoebaMultipoleForce must specify the same charge for every atom."); } } includeCavityTerm = force.getIncludeCavityTerm(); soluteDielectric = static_cast( force.getSoluteDielectric() ); solventDielectric = static_cast( force.getSolventDielectric() ); dielectricOffset = static_cast( 0.009 ); probeRadius = static_cast( force.getProbeRadius() ), surfaceAreaFactor = static_cast( force.getSurfaceAreaFactor() ); directPolarization = amoebaMultipoleForce->getPolarizationType() == AmoebaMultipoleForce::Direct ? 1 : 0; } double ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { // handled in AmoebaReferenceGeneralizedKirkwoodMultipoleForce, a derived class of the class AmoebaReferenceMultipoleForce return 0.0; } void ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::copyParametersToContext(ContextImpl& context, const AmoebaGeneralizedKirkwoodForce& force) { if (numParticles != force.getNumParticles()) throw OpenMMException("updateParametersInContext: The number of particles has changed"); // Record the values. for (int i = 0; i < numParticles; ++i) { double particleCharge, particleRadius, scalingFactor; force.getParticleParameters(i, particleCharge, particleRadius, scalingFactor); atomicRadii[i] = particleRadius; scaleFactors[i] = scalingFactor; charges[i] = particleCharge; } } ReferenceCalcAmoebaVdwForceKernel::ReferenceCalcAmoebaVdwForceKernel(std::string name, const Platform& platform, System& system) : CalcAmoebaVdwForceKernel(name, platform), system(system) { useCutoff = 0; usePBC = 0; cutoff = 1.0e+10; neighborList = NULL; } ReferenceCalcAmoebaVdwForceKernel::~ReferenceCalcAmoebaVdwForceKernel() { if( neighborList ){ delete neighborList; } } void ReferenceCalcAmoebaVdwForceKernel::initialize(const System& system, const AmoebaVdwForce& force) { // per-particle parameters numParticles = system.getNumParticles(); indexIVs.resize( numParticles ); allExclusions.resize( numParticles ); sigmas.resize( numParticles ); epsilons.resize( numParticles ); reductions.resize( numParticles ); for( int ii = 0; ii < numParticles; ii++ ){ int indexIV; double sigma, epsilon, reduction; std::vector exclusions; force.getParticleParameters( ii, indexIV, sigma, epsilon, reduction ); force.getParticleExclusions( ii, exclusions ); for( unsigned int jj = 0; jj < exclusions.size(); jj++ ){ allExclusions[ii].insert( exclusions[jj] ); } indexIVs[ii] = indexIV; sigmas[ii] = static_cast( sigma ); epsilons[ii] = static_cast( epsilon ); reductions[ii] = static_cast( reduction ); } sigmaCombiningRule = force.getSigmaCombiningRule(); epsilonCombiningRule = force.getEpsilonCombiningRule(); useCutoff = (force.getNonbondedMethod() != AmoebaVdwForce::NoCutoff); usePBC = (force.getNonbondedMethod() == AmoebaVdwForce::CutoffPeriodic); cutoff = force.getCutoff(); neighborList = useCutoff ? new NeighborList() : NULL; dispersionCoefficient = force.getUseDispersionCorrection() ? AmoebaVdwForceImpl::calcDispersionCorrection(system, force) : 0.0; } double ReferenceCalcAmoebaVdwForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { vector& posData = extractPositions(context); vector& forceData = extractForces(context); AmoebaReferenceVdwForce vdwForce( sigmaCombiningRule, epsilonCombiningRule ); RealOpenMM energy; if( useCutoff ){ vdwForce.setCutoff( cutoff ); computeNeighborListVoxelHash( *neighborList, numParticles, posData, allExclusions, extractBoxSize(context), usePBC, cutoff, 0.0); if( usePBC ){ vdwForce.setNonbondedMethod( AmoebaReferenceVdwForce::CutoffPeriodic); RealVec& box = extractBoxSize(context); double minAllowedSize = 1.999999*cutoff; if (box[0] < minAllowedSize || box[1] < minAllowedSize || box[2] < minAllowedSize){ throw OpenMMException("The periodic box size has decreased to less than twice the cutoff."); } vdwForce.setPeriodicBox(box); energy = vdwForce.calculateForceAndEnergy( numParticles, posData, indexIVs, sigmas, epsilons, reductions, *neighborList, forceData); energy += dispersionCoefficient/(box[0]*box[1]*box[2]); } else { vdwForce.setNonbondedMethod( AmoebaReferenceVdwForce::CutoffNonPeriodic); } } else { vdwForce.setNonbondedMethod( AmoebaReferenceVdwForce::NoCutoff ); energy = vdwForce.calculateForceAndEnergy( numParticles, posData, indexIVs, sigmas, epsilons, reductions, allExclusions, forceData); } return static_cast(energy); } void ReferenceCalcAmoebaVdwForceKernel::copyParametersToContext(ContextImpl& context, const AmoebaVdwForce& force) { if (numParticles != force.getNumParticles()) throw OpenMMException("updateParametersInContext: The number of particles has changed"); // Record the values. for (int i = 0; i < numParticles; ++i) { int indexIV; double sigma, epsilon, reduction; force.getParticleParameters(i, indexIV, sigma, epsilon, reduction); indexIVs[i] = indexIV; sigmas[i] = (RealOpenMM) sigma; epsilons[i] = (RealOpenMM) epsilon; reductions[i]= (RealOpenMM) reduction; } } /* -------------------------------------------------------------------------- * * AmoebaWcaDispersion * * -------------------------------------------------------------------------- */ ReferenceCalcAmoebaWcaDispersionForceKernel::ReferenceCalcAmoebaWcaDispersionForceKernel(std::string name, const Platform& platform, System& system) : CalcAmoebaWcaDispersionForceKernel(name, platform), system(system) { } ReferenceCalcAmoebaWcaDispersionForceKernel::~ReferenceCalcAmoebaWcaDispersionForceKernel() { } void ReferenceCalcAmoebaWcaDispersionForceKernel::initialize(const System& system, const AmoebaWcaDispersionForce& force) { // per-particle parameters numParticles = system.getNumParticles(); radii.resize(numParticles); epsilons.resize(numParticles); for( int ii = 0; ii < numParticles; ii++ ){ double radius, epsilon; force.getParticleParameters( ii, radius, epsilon ); radii[ii] = static_cast( radius ); epsilons[ii] = static_cast( epsilon ); } totalMaximumDispersionEnergy = static_cast( AmoebaWcaDispersionForceImpl::getTotalMaximumDispersionEnergy( force ) ); epso = static_cast( force.getEpso() ); epsh = static_cast( force.getEpsh() ); rmino = static_cast( force.getRmino() ); rminh = static_cast( force.getRminh() ); awater = static_cast( force.getAwater() ); shctd = static_cast( force.getShctd() ); dispoff = static_cast( force.getDispoff()); slevy = static_cast( force.getSlevy() ); } double ReferenceCalcAmoebaWcaDispersionForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { vector& posData = extractPositions(context); vector& forceData = extractForces(context); AmoebaReferenceWcaDispersionForce amoebaReferenceWcaDispersionForce( epso, epsh, rmino, rminh, awater, shctd, dispoff, slevy ); RealOpenMM energy = amoebaReferenceWcaDispersionForce.calculateForceAndEnergy( numParticles, posData, radii, epsilons, totalMaximumDispersionEnergy, forceData); return static_cast(energy); } void ReferenceCalcAmoebaWcaDispersionForceKernel::copyParametersToContext(ContextImpl& context, const AmoebaWcaDispersionForce& force) { if (numParticles != force.getNumParticles()) throw OpenMMException("updateParametersInContext: The number of particles has changed"); // Record the values. for (int i = 0; i < numParticles; ++i) { double radius, epsilon; force.getParticleParameters(i, radius, epsilon); radii[i] = (RealOpenMM) radius; epsilons[i] = (RealOpenMM) epsilon; } }