/* -------------------------------------------------------------------------- * * 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) 2011-2023 Stanford University and the Authors. * * Authors: Peter Eastman * * 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 "openmm/common/BondedUtilities.h" #include "openmm/common/ComputeContext.h" #include "openmm/OpenMMException.h" #include using namespace OpenMM; using namespace std; BondedUtilities::BondedUtilities(ComputeContext& context) : context(context), numForceBuffers(0), maxBonds(0), allGroups(0), hasInitializedKernels(false) { } void BondedUtilities::addInteraction(const vector >& atoms, const string& source, int group) { if (atoms.size() > 0) { forceAtoms.push_back(atoms); forceSource.push_back(source); forceGroup.push_back(group); allGroups |= 1< 0); if (!hasInteractions) return; // Build the lists of atom indices. atomIndices.resize(numForces); for (int i = 0; i < numForces; i++) { int numBonds = forceAtoms[i].size(); int numAtoms = forceAtoms[i][0].size(); int numArrays = (numAtoms+3)/4; int startAtom = 0; atomIndices[i].resize(numArrays); for (int j = 0; j < numArrays; j++) { int width = min(numAtoms-startAtom, 4); int paddedWidth = (width == 3 ? 4 : width); vector indexVec(paddedWidth*numBonds); for (int bond = 0; bond < numBonds; bond++) { for (int atom = 0; atom < width; atom++) indexVec[bond*paddedWidth+atom] = forceAtoms[i][bond][startAtom+atom]; } atomIndices[i][j].initialize(context, numBonds, 4*paddedWidth, "bondedIndices"); atomIndices[i][j].upload(&indexVec[0]); startAtom += width; } } // Create the kernel. stringstream s; for (int i = 0; i < (int) prefixCode.size(); i++) s< 0) s<<", GLOBAL mixed* RESTRICT energyParamDerivs"; s<<") {\n"; s<<"mixed energy = 0;\n"; for (int i = 0; i < energyParameterDerivatives.size(); i++) s<<"mixed energyParamDeriv"<& allParamDerivNames = context.getEnergyParamDerivNames(); int numDerivs = allParamDerivNames.size(); for (int i = 0; i < energyParameterDerivatives.size(); i++) for (int index = 0; index < numDerivs; index++) if (allParamDerivNames[index] == energyParameterDerivatives[i]) s<<"energyParamDerivs[(GLOBAL_ID)*"< defines; defines["PADDED_NUM_ATOMS"] = context.intToString(context.getPaddedNumAtoms()); ComputeProgram program = context.compileProgram(s.str(), defines); kernel = program->createKernel("computeBondedForces"); forceAtoms.clear(); forceSource.clear(); } string BondedUtilities::createForceSource(int forceIndex, int numBonds, int numAtoms, int group, const string& computeForce) { maxBonds = max(maxBonds, numBonds); string suffix1[] = {""}; string suffix4[] = {".x", ".y", ".z", ".w"}; stringstream s; s<<"if ((groups&"<<(1<addArg(context.getLongForceBuffer()); kernel->addArg(context.getEnergyBuffer()); kernel->addArg(context.getPosq()); for (int i = 0; i < 6; i++) kernel->addArg(); for (int i = 0; i < (int) atomIndices.size(); i++) for (int j = 0; j < (int) atomIndices[i].size(); j++) kernel->addArg(atomIndices[i][j]); for (int i = 0; i < (int) arguments.size(); i++) kernel->addArg(*arguments[i]); if (energyParameterDerivatives.size() > 0) kernel->addArg(context.getEnergyParamDerivBuffer()); } if (!hasInteractions) return; kernel->setArg(3, groups); Vec3 a, b, c; context.getPeriodicBoxVectors(a, b, c); if (context.getUseDoublePrecision()) { kernel->setArg(4, mm_double4(a[0], b[1], c[2], 0.0)); kernel->setArg(5, mm_double4(1.0/a[0], 1.0/b[1], 1.0/c[2], 0.0)); kernel->setArg(6, mm_double4(a[0], a[1], a[2], 0.0)); kernel->setArg(7, mm_double4(b[0], b[1], b[2], 0.0)); kernel->setArg(8, mm_double4(c[0], c[1], c[2], 0.0)); } else { kernel->setArg(4, mm_float4((float) a[0], (float) b[1], (float) c[2], 0.0f)); kernel->setArg(5, mm_float4(1.0f/(float) a[0], 1.0f/(float) b[1], 1.0f/(float) c[2], 0.0f)); kernel->setArg(6, mm_float4((float) a[0], (float) a[1], (float) a[2], 0.0f)); kernel->setArg(7, mm_float4((float) b[0], (float) b[1], (float) b[2], 0.0f)); kernel->setArg(8, mm_float4((float) c[0], (float) c[1], (float) c[2], 0.0f)); } kernel->execute(maxBonds); }