CudaKernels.cpp 37 KB
Newer Older
1
2
3
4
5
6
7
8
/* -------------------------------------------------------------------------- *
 *                                   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.               *
 *                                                                            *
9
 * Portions copyright (c) 2008-2009 Stanford University and the Authors.      *
10
11
12
 * Authors: Peter Eastman                                                     *
 * Contributors:                                                              *
 *                                                                            *
13
14
15
16
 * 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.                                        *
17
 *                                                                            *
18
19
20
21
 * 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.                        *
22
 *                                                                            *
23
24
 * You should have received a copy of the GNU Lesser General Public License   *
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.      *
25
26
27
 * -------------------------------------------------------------------------- */

#include "CudaKernels.h"
28
#include "openmm/LangevinIntegrator.h"
29
30
#include "openmm/Context.h"
#include "openmm/internal/ContextImpl.h"
31
#include "openmm/internal/NonbondedForceImpl.h"
32
#include "kernels/gputypes.h"
33
#include "kernels/cudaKernels.h"
34
#include "../src/SimTKUtilities/SimTKOpenMMRealType.h"
35
36
37
38
39
40
41
#include <cmath>

extern "C" int gpuSetConstants( gpuContext gpu );

using namespace OpenMM;
using namespace std;

42
43
44
45
void CudaCalcForcesAndEnergyKernel::initialize(const System& system) {
}

void CudaCalcForcesAndEnergyKernel::beginForceComputation(ContextImpl& context) {
46
    _gpuContext* gpu = data.gpu;
47
    if (data.nonbondedMethod != NO_CUTOFF && data.computeForceCount%100 == 0)
48
        gpuReorderAtoms(gpu);
49
    data.computeForceCount++;
50
    kClearForces(gpu);
51
52
53
54
}

void CudaCalcForcesAndEnergyKernel::finishForceComputation(ContextImpl& context) {
    _gpuContext* gpu = data.gpu;
Mark Friedrichs's avatar
Mark Friedrichs committed
55
56

    if (gpu->bIncludeGBSA || gpu->bIncludeGBVI) {
57
        gpu->bRecalculateBornRadii = true;
58
59
        kCalculateCDLJObcGbsaForces1(gpu);
        kReduceObcGbsaBornForces(gpu);
Mark Friedrichs's avatar
Mark Friedrichs committed
60
61
62
63
64
        if (gpu->bIncludeGBSA ) { 
           kCalculateObcGbsaForces2(gpu);
        } else {
           kCalculateGBVIForces2(gpu);
        }
65
    }
66
    else if (data.hasNonbonded)
67
        kCalculateCDLJForces(gpu);
68
69
    if (data.hasCustomNonbonded)
        kCalculateCustomNonbondedForces(gpu, data.hasNonbonded);
70
    kCalculateLocalForces(gpu);
71
    kReduceForces(gpu);
72
73
}

74
void CudaCalcForcesAndEnergyKernel::beginEnergyComputation(ContextImpl& context) {
75
    _gpuContext* gpu = data.gpu;
76
77
78
79
    if (data.nonbondedMethod != NO_CUTOFF && data.stepCount%100 == 0)
        gpuReorderAtoms(gpu);
    data.stepCount++;
    kClearEnergy(gpu);
80
81
82
83
}

double CudaCalcForcesAndEnergyKernel::finishEnergyComputation(ContextImpl& context) {
    _gpuContext* gpu = data.gpu;
Mark Friedrichs's avatar
Mark Friedrichs committed
84
    if (gpu->bIncludeGBSA || gpu->bIncludeGBVI) {
85
86
87
        gpu->bRecalculateBornRadii = true;
        kCalculateCDLJObcGbsaForces1(gpu);
        kReduceObcGbsaBornForces(gpu);
Mark Friedrichs's avatar
Mark Friedrichs committed
88
89
90
91
92
        if (gpu->bIncludeGBSA ) {
           kCalculateObcGbsaForces2(gpu);
        } else {
           kCalculateGBVIForces2(gpu);
        }
93
    }
94
95
96
97
98
99
    else if (data.hasNonbonded)
        kCalculateCDLJForces(gpu);
    if (data.hasCustomNonbonded)
        kCalculateCustomNonbondedForces(gpu, data.hasNonbonded);
    kCalculateLocalForces(gpu);
    return kReduceEnergy(gpu)+data.ewaldSelfEnergy;
100
101
}

102
void CudaUpdateStateDataKernel::initialize(const System& system) {
103
104
}

105
double CudaUpdateStateDataKernel::getTime(const ContextImpl& context) const {
106
107
108
    return data.time;
}

109
void CudaUpdateStateDataKernel::setTime(ContextImpl& context, double time) {
110
111
112
    data.time = time;
}

113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
void CudaUpdateStateDataKernel::getPositions(ContextImpl& context, std::vector<Vec3>& positions) {
    _gpuContext* gpu = data.gpu;
    gpu->psPosq4->Download();
    int* order = gpu->psAtomIndex->_pSysData;
    int numParticles = context.getSystem().getNumParticles();
    positions.resize(numParticles);
    for (int i = 0; i < numParticles; ++i) {
        float4 pos = (*gpu->psPosq4)[i];
        int3 offset = gpu->posCellOffsets[i];
        positions[order[i]] = Vec3(pos.x-offset.x*gpu->sim.periodicBoxSizeX, pos.y-offset.y*gpu->sim.periodicBoxSizeY, pos.z-offset.z*gpu->sim.periodicBoxSizeZ);
    }
}

void CudaUpdateStateDataKernel::setPositions(ContextImpl& context, const std::vector<Vec3>& positions) {
    _gpuContext* gpu = data.gpu;
    int* order = gpu->psAtomIndex->_pSysData;
    int numParticles = context.getSystem().getNumParticles();
    for (int i = 0; i < numParticles; ++i) {
        float4& pos = (*gpu->psPosq4)[i];
        const Vec3& p = positions[order[i]];
133
134
135
        pos.x = (float) p[0];
        pos.y = (float) p[1];
        pos.z = (float) p[2];
136
137
    }
    gpu->psPosq4->Upload();
138
    for (int i = 0; i < (int) gpu->posCellOffsets.size(); i++)
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
        gpu->posCellOffsets[i] = make_int3(0, 0, 0);
}

void CudaUpdateStateDataKernel::getVelocities(ContextImpl& context, std::vector<Vec3>& velocities) {
    _gpuContext* gpu = data.gpu;
    gpu->psVelm4->Download();
    int* order = gpu->psAtomIndex->_pSysData;
    int numParticles = context.getSystem().getNumParticles();
    velocities.resize(numParticles);
    for (int i = 0; i < numParticles; ++i) {
        float4 vel = (*gpu->psVelm4)[i];
        velocities[order[i]] = Vec3(vel.x, vel.y, vel.z);
    }
}

void CudaUpdateStateDataKernel::setVelocities(ContextImpl& context, const std::vector<Vec3>& velocities) {
    _gpuContext* gpu = data.gpu;
    int* order = gpu->psAtomIndex->_pSysData;
    int numParticles = context.getSystem().getNumParticles();
    for (int i = 0; i < numParticles; ++i) {
        float4& vel = (*gpu->psVelm4)[i];
        const Vec3& v = velocities[order[i]];
161
162
163
        vel.x = (float) v[0];
        vel.y = (float) v[1];
        vel.z = (float) v[2];
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
    }
    gpu->psVelm4->Upload();
}

void CudaUpdateStateDataKernel::getForces(ContextImpl& context, std::vector<Vec3>& forces) {
    _gpuContext* gpu = data.gpu;
    int* order = gpu->psAtomIndex->_pSysData;
    gpu->psForce4->Download();
    int numParticles = context.getSystem().getNumParticles();
    forces.resize(numParticles);
    for (int i = 0; i < numParticles; ++i) {
        float4 force = (*gpu->psForce4)[i];
        forces[order[i]] = Vec3(force.x, force.y, force.z);
    }
}

180
181
182
183
184
CudaCalcHarmonicBondForceKernel::~CudaCalcHarmonicBondForceKernel() {
}

void CudaCalcHarmonicBondForceKernel::initialize(const System& system, const HarmonicBondForce& force) {
    data.hasBonds = true;
185
    numBonds = force.getNumBonds();
Peter Eastman's avatar
Peter Eastman committed
186
187
    vector<int> particle1(numBonds);
    vector<int> particle2(numBonds);
188
189
190
191
    vector<float> length(numBonds);
    vector<float> k(numBonds);
    for (int i = 0; i < numBonds; i++) {
        double lengthValue, kValue;
Peter Eastman's avatar
Peter Eastman committed
192
        force.getBondParameters(i, particle1[i], particle2[i], lengthValue, kValue);
193
194
195
        length[i] = (float) lengthValue;
        k[i] = (float) kValue;
    }
Peter Eastman's avatar
Peter Eastman committed
196
    gpuSetBondParameters(data.gpu, particle1, particle2, length, k);
197
198
}

199
void CudaCalcHarmonicBondForceKernel::executeForces(ContextImpl& context) {
200
201
}

202
double CudaCalcHarmonicBondForceKernel::executeEnergy(ContextImpl& context) {
203
204
205
    return 0.0;
}

206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
CudaCalcCustomBondForceKernel::~CudaCalcCustomBondForceKernel() {
}

void CudaCalcCustomBondForceKernel::initialize(const System& system, const CustomBondForce& force) {
    numBonds = force.getNumBonds();
    vector<int> particle1(numBonds);
    vector<int> particle2(numBonds);
    vector<vector<double> > params(numBonds);
    for (int i = 0; i < numBonds; i++)
        force.getBondParameters(i, particle1[i], particle2[i], params[i]);
    vector<string> paramNames;
    for (int i = 0; i < force.getNumPerBondParameters(); i++)
        paramNames.push_back(force.getPerBondParameterName(i));
    globalParamNames.resize(force.getNumGlobalParameters());
    globalParamValues.resize(force.getNumGlobalParameters());
    for (int i = 0; i < force.getNumGlobalParameters(); i++) {
        globalParamNames[i] = force.getGlobalParameterName(i);
        globalParamValues[i] = (float) force.getGlobalParameterDefaultValue(i);
    }
    gpuSetCustomBondParameters(data.gpu, particle1, particle2, params, force.getEnergyFunction(), paramNames, globalParamNames);
    if (globalParamValues.size() > 0)
Peter Eastman's avatar
Peter Eastman committed
227
        SetCustomBondGlobalParams(globalParamValues);
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
}

void CudaCalcCustomBondForceKernel::executeForces(ContextImpl& context) {
    updateGlobalParams(context);
    kCalculateCustomBondForces(data.gpu);
}

double CudaCalcCustomBondForceKernel::executeEnergy(ContextImpl& context) {
    updateGlobalParams(context);
    kCalculateCustomBondForces(data.gpu);
    return 0.0;
}

void CudaCalcCustomBondForceKernel::updateGlobalParams(ContextImpl& context) {
    bool changed = false;
    for (int i = 0; i < (int) globalParamNames.size(); i++) {
        float value = (float) context.getParameter(globalParamNames[i]);
        if (value != globalParamValues[i])
            changed = true;
        globalParamValues[i] = value;
    }
    if (changed)
Peter Eastman's avatar
Peter Eastman committed
250
        SetCustomBondGlobalParams(globalParamValues);
251
252
}

253
254
255
256
257
CudaCalcHarmonicAngleForceKernel::~CudaCalcHarmonicAngleForceKernel() {
}

void CudaCalcHarmonicAngleForceKernel::initialize(const System& system, const HarmonicAngleForce& force) {
    data.hasAngles = true;
258
    numAngles = force.getNumAngles();
259
    const float RadiansToDegrees = (float) (180.0/3.14159265);
Peter Eastman's avatar
Peter Eastman committed
260
261
262
    vector<int> particle1(numAngles);
    vector<int> particle2(numAngles);
    vector<int> particle3(numAngles);
263
264
265
266
    vector<float> angle(numAngles);
    vector<float> k(numAngles);
    for (int i = 0; i < numAngles; i++) {
        double angleValue, kValue;
Peter Eastman's avatar
Peter Eastman committed
267
        force.getAngleParameters(i, particle1[i], particle2[i], particle3[i], angleValue, kValue);
268
269
        angle[i] = (float) (angleValue*RadiansToDegrees);
        k[i] = (float) kValue;
270
    }
Peter Eastman's avatar
Peter Eastman committed
271
    gpuSetBondAngleParameters(data.gpu, particle1, particle2, particle3, angle, k);
272
}
273

274
void CudaCalcHarmonicAngleForceKernel::executeForces(ContextImpl& context) {
275
276
}

277
double CudaCalcHarmonicAngleForceKernel::executeEnergy(ContextImpl& context) {
278
279
280
281
282
283
284
285
286
    return 0.0;
}

CudaCalcPeriodicTorsionForceKernel::~CudaCalcPeriodicTorsionForceKernel() {
}

void CudaCalcPeriodicTorsionForceKernel::initialize(const System& system, const PeriodicTorsionForce& force) {
    data.hasPeriodicTorsions = true;
    numTorsions = force.getNumTorsions();
287
    const float RadiansToDegrees = (float)(180.0/3.14159265);
Peter Eastman's avatar
Peter Eastman committed
288
289
290
291
    vector<int> particle1(numTorsions);
    vector<int> particle2(numTorsions);
    vector<int> particle3(numTorsions);
    vector<int> particle4(numTorsions);
292
293
294
295
296
    vector<float> k(numTorsions);
    vector<float> phase(numTorsions);
    vector<int> periodicity(numTorsions);
    for (int i = 0; i < numTorsions; i++) {
        double kValue, phaseValue;
Peter Eastman's avatar
Peter Eastman committed
297
        force.getTorsionParameters(i, particle1[i], particle2[i], particle3[i], particle4[i], periodicity[i], phaseValue, kValue);
298
299
        k[i] = (float) kValue;
        phase[i] = (float) (phaseValue*RadiansToDegrees);
300
    }
Peter Eastman's avatar
Peter Eastman committed
301
    gpuSetDihedralParameters(data.gpu, particle1, particle2, particle3, particle4, k, phase, periodicity);
302
303
}

304
void CudaCalcPeriodicTorsionForceKernel::executeForces(ContextImpl& context) {
305
306
}

307
double CudaCalcPeriodicTorsionForceKernel::executeEnergy(ContextImpl& context) {
308
309
310
311
312
313
314
315
316
    return 0.0;
}

CudaCalcRBTorsionForceKernel::~CudaCalcRBTorsionForceKernel() {
}

void CudaCalcRBTorsionForceKernel::initialize(const System& system, const RBTorsionForce& force) {
    data.hasRB = true;
    numTorsions = force.getNumTorsions();
Peter Eastman's avatar
Peter Eastman committed
317
318
319
320
    vector<int> particle1(numTorsions);
    vector<int> particle2(numTorsions);
    vector<int> particle3(numTorsions);
    vector<int> particle4(numTorsions);
321
322
323
324
325
326
327
328
    vector<float> c0(numTorsions);
    vector<float> c1(numTorsions);
    vector<float> c2(numTorsions);
    vector<float> c3(numTorsions);
    vector<float> c4(numTorsions);
    vector<float> c5(numTorsions);
    for (int i = 0; i < numTorsions; i++) {
        double c[6];
Peter Eastman's avatar
Peter Eastman committed
329
        force.getTorsionParameters(i, particle1[i], particle2[i], particle3[i], particle4[i], c[0], c[1], c[2], c[3], c[4], c[5]);
330
331
332
333
334
335
        c0[i] = (float) c[0];
        c1[i] = (float) c[1];
        c2[i] = (float) c[2];
        c3[i] = (float) c[3];
        c4[i] = (float) c[4];
        c5[i] = (float) c[5];
336
    }
Peter Eastman's avatar
Peter Eastman committed
337
    gpuSetRbDihedralParameters(data.gpu, particle1, particle2, particle3, particle4, c0, c1, c2, c3, c4, c5);
338
339
}

340
void CudaCalcRBTorsionForceKernel::executeForces(ContextImpl& context) {
341
342
}

343
double CudaCalcRBTorsionForceKernel::executeEnergy(ContextImpl& context) {
344
345
346
347
348
349
    return 0.0;
}

CudaCalcNonbondedForceKernel::~CudaCalcNonbondedForceKernel() {
}

350
void CudaCalcNonbondedForceKernel::initialize(const System& system, const NonbondedForce& force) {
351
    data.hasNonbonded = true;
Peter Eastman's avatar
Peter Eastman committed
352
    numParticles = force.getNumParticles();
353
    _gpuContext* gpu = data.gpu;
354
355
356
357

    // Identify which exceptions are 1-4 interactions.

    vector<pair<int, int> > exclusions;
358
    vector<int> exceptions;
359
360
361
362
363
364
    for (int i = 0; i < force.getNumExceptions(); i++) {
        int particle1, particle2;
        double chargeProd, sigma, epsilon;
        force.getExceptionParameters(i, particle1, particle2, chargeProd, sigma, epsilon);
        exclusions.push_back(pair<int, int>(particle1, particle2));
        if (chargeProd != 0.0 || epsilon != 0.0)
365
            exceptions.push_back(i);
366
367
    }

368
369
    // Initialize nonbonded interactions.
    
370
    {
Peter Eastman's avatar
Peter Eastman committed
371
372
373
374
        vector<int> particle(numParticles);
        vector<float> c6(numParticles);
        vector<float> c12(numParticles);
        vector<float> q(numParticles);
375
        vector<char> symbol;
Peter Eastman's avatar
Peter Eastman committed
376
377
        vector<vector<int> > exclusionList(numParticles);
        for (int i = 0; i < numParticles; i++) {
378
            double charge, radius, depth;
Peter Eastman's avatar
Peter Eastman committed
379
380
            force.getParticleParameters(i, charge, radius, depth);
            particle[i] = i;
381
382
383
            q[i] = (float) charge;
            c6[i] = (float) (4*depth*pow(radius, 6.0));
            c12[i] = (float) (4*depth*pow(radius, 12.0));
384
385
            exclusionList[i].push_back(i);
        }
386
        for (int i = 0; i < (int)exclusions.size(); i++) {
387
388
389
            exclusionList[exclusions[i].first].push_back(exclusions[i].second);
            exclusionList[exclusions[i].second].push_back(exclusions[i].first);
        }
Peter Eastman's avatar
Peter Eastman committed
390
        Vec3 boxVectors[3];
391
        system.getPeriodicBoxVectors(boxVectors[0], boxVectors[1], boxVectors[2]);
Peter Eastman's avatar
Peter Eastman committed
392
        gpuSetPeriodicBoxSize(gpu, (float)boxVectors[0][0], (float)boxVectors[1][1], (float)boxVectors[2][2]);
393
394
        CudaNonbondedMethod method = NO_CUTOFF;
        if (force.getNonbondedMethod() != NonbondedForce::NoCutoff) {
395
            gpuSetNonbondedCutoff(gpu, (float) force.getCutoffDistance(), (float) force.getReactionFieldDielectric());
396
397
398
399
400
            method = CUTOFF;
        }
        if (force.getNonbondedMethod() == NonbondedForce::CutoffPeriodic) {
            method = PERIODIC;
        }
401
402
        if (force.getNonbondedMethod() == NonbondedForce::Ewald || force.getNonbondedMethod() == NonbondedForce::PME) {
            if (force.getNonbondedMethod() == NonbondedForce::Ewald) {
403
404
405
                double alpha;
                int kmaxx, kmaxy, kmaxz;
                NonbondedForceImpl::calcEwaldParameters(system, force, alpha, kmaxx, kmaxy, kmaxz);
406
407
408
409
                gpuSetEwaldParameters(gpu, (float) alpha, kmaxx, kmaxy, kmaxz);
                method = EWALD;
            }
            else {
410
411
412
                double alpha;
                int gridSizeX, gridSizeY, gridSizeZ;
                NonbondedForceImpl::calcPMEParameters(system, force, alpha, gridSizeX, gridSizeY, gridSizeZ);
Peter Eastman's avatar
Peter Eastman committed
413
                gpuSetPMEParameters(gpu, (float) alpha, gridSizeX, gridSizeY, gridSizeZ);
414
415
                method = PARTICLE_MESH_EWALD;
            }
416
        }
417
        data.nonbondedMethod = method;
418
        gpuSetCoulombParameters(gpu, (float) ONE_4PI_EPS0, particle, c6, c12, q, symbol, exclusionList, method);
419
420
421
422

        // Compute the Ewald self energy.

        data.ewaldSelfEnergy = 0.0;
423
424
425
426
427
        if (force.getNonbondedMethod() == NonbondedForce::Ewald || force.getNonbondedMethod() == NonbondedForce::PME) {
            double selfEnergyScale = gpu->sim.epsfac*gpu->sim.alphaEwald/std::sqrt(PI);
                for (int i = 0; i < numParticles; i++)
                    data.ewaldSelfEnergy -= selfEnergyScale*q[i]*q[i];
        }
428
429
430
431
    }

    // Initialize 1-4 nonbonded interactions.
    
432
    {
433
434
435
436
437
438
439
440
        int numExceptions = exceptions.size();
        vector<int> particle1(numExceptions);
        vector<int> particle2(numExceptions);
        vector<float> c6(numExceptions);
        vector<float> c12(numExceptions);
        vector<float> q1(numExceptions);
        vector<float> q2(numExceptions);
        for (int i = 0; i < numExceptions; i++) {
441
            double charge, sig, eps;
442
            force.getExceptionParameters(exceptions[i], particle1[i], particle2[i], charge, sig, eps);
443
444
            c6[i] = (float) (4*eps*pow(sig, 6.0));
            c12[i] = (float) (4*eps*pow(sig, 12.0));
Peter Eastman's avatar
Peter Eastman committed
445
446
            q1[i] = (float) charge;
            q2[i] = 1.0f;
447
        }
448
        gpuSetLJ14Parameters(gpu, (float) ONE_4PI_EPS0, 1.0f, particle1, particle2, c6, c12, q1, q2);
449
450
451
    }
}

452
void CudaCalcNonbondedForceKernel::executeForces(ContextImpl& context) {
453
454
}

455
double CudaCalcNonbondedForceKernel::executeEnergy(ContextImpl& context) {
456
    return 0.0;
457
458
}

459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
CudaCalcCustomNonbondedForceKernel::~CudaCalcCustomNonbondedForceKernel() {
}

void CudaCalcCustomNonbondedForceKernel::initialize(const System& system, const CustomNonbondedForce& force) {
    data.hasCustomNonbonded = true;
    numParticles = force.getNumParticles();
    _gpuContext* gpu = data.gpu;

    // Initialize nonbonded interactions.

    vector<int> particle(numParticles);
    vector<vector<double> > parameters(numParticles);
    vector<vector<int> > exclusionList(numParticles);
    for (int i = 0; i < numParticles; i++) {
        force.getParticleParameters(i, parameters[i]);
        particle[i] = i;
        exclusionList[i].push_back(i);
    }
477
478
479
480
481
    for (int i = 0; i < force.getNumExclusions(); i++) {
        int particle1, particle2;
        force.getExclusionParticles(i, particle1, particle2);
        exclusionList[particle1].push_back(particle2);
        exclusionList[particle2].push_back(particle1);
482
    }
483
484
485
    Vec3 boxVectors[3];
    system.getPeriodicBoxVectors(boxVectors[0], boxVectors[1], boxVectors[2]);
    gpuSetPeriodicBoxSize(gpu, (float)boxVectors[0][0], (float)boxVectors[1][1], (float)boxVectors[2][2]);
486
487
488
489
490
491
492
493
    CudaNonbondedMethod method = NO_CUTOFF;
    if (force.getNonbondedMethod() != CustomNonbondedForce::NoCutoff)
        method = CUTOFF;
    if (force.getNonbondedMethod() == CustomNonbondedForce::CutoffPeriodic) {
        method = PERIODIC;
    }
    data.customNonbondedMethod = method;

494
495
496
497
498
499
500
501
502
503
504
    // Record the tabulated functions.

    for (int i = 0; i < force.getNumFunctions(); i++) {
        string name;
        vector<double> values;
        double min, max;
        bool interpolating;
        force.getFunctionParameters(i, name, values, min, max, interpolating);
        gpuSetTabulatedFunction(gpu, i, name, values, min, max, interpolating);
    }

505
506
507
    // Record information for the expressions.

    vector<string> paramNames;
508
509
    for (int i = 0; i < force.getNumPerParticleParameters(); i++)
        paramNames.push_back(force.getPerParticleParameterName(i));
510
511
512
513
    globalParamNames.resize(force.getNumGlobalParameters());
    globalParamValues.resize(force.getNumGlobalParameters());
    for (int i = 0; i < force.getNumGlobalParameters(); i++) {
        globalParamNames[i] = force.getGlobalParameterName(i);
514
        globalParamValues[i] = (float) force.getGlobalParameterDefaultValue(i);
515
    }
516
    gpuSetCustomNonbondedParameters(gpu, parameters, exclusionList, method, (float) force.getCutoffDistance(), force.getEnergyFunction(), paramNames, globalParamNames);
517
    if (globalParamValues.size() > 0)
Peter Eastman's avatar
Peter Eastman committed
518
        SetCustomNonbondedGlobalParams(globalParamValues);
519
520
521
}

void CudaCalcCustomNonbondedForceKernel::executeForces(ContextImpl& context) {
522
    updateGlobalParams(context);
523
524
525
}

double CudaCalcCustomNonbondedForceKernel::executeEnergy(ContextImpl& context) {
526
    updateGlobalParams(context);
527
528
529
    return 0.0;
}

530
531
void CudaCalcCustomNonbondedForceKernel::updateGlobalParams(ContextImpl& context) {
    bool changed = false;
532
    for (int i = 0; i < (int) globalParamNames.size(); i++) {
533
534
535
536
537
538
        float value = (float) context.getParameter(globalParamNames[i]);
        if (value != globalParamValues[i])
            changed = true;
        globalParamValues[i] = value;
    }
    if (changed)
Peter Eastman's avatar
Peter Eastman committed
539
        SetCustomNonbondedGlobalParams(globalParamValues);
540
541
}

542
CudaCalcGBSAOBCForceKernel::~CudaCalcGBSAOBCForceKernel() {
543
544
}

545
void CudaCalcGBSAOBCForceKernel::initialize(const System& system, const GBSAOBCForce& force) {
546

Peter Eastman's avatar
Peter Eastman committed
547
    int numParticles = system.getNumParticles();
548
    _gpuContext* gpu = data.gpu;
Peter Eastman's avatar
Peter Eastman committed
549
550
    vector<float> radius(numParticles);
    vector<float> scale(numParticles);
551
    vector<float> charge(numParticles);
Peter Eastman's avatar
Peter Eastman committed
552
    for (int i = 0; i < numParticles; i++) {
553
554
        double particleCharge, particleRadius, scalingFactor;
        force.getParticleParameters(i, particleCharge, particleRadius, scalingFactor);
Peter Eastman's avatar
Peter Eastman committed
555
        radius[i] = (float) particleRadius;
556
        scale[i] = (float) scalingFactor;
557
        charge[i] = (float) particleCharge;
558
    }
559
    gpuSetObcParameters(gpu, (float) force.getSoluteDielectric(), (float) force.getSolventDielectric(), radius, scale, charge);
560
561
}

562
void CudaCalcGBSAOBCForceKernel::executeForces(ContextImpl& context) {
563
564
}

Mark Friedrichs's avatar
Mark Friedrichs committed
565
566
567
568
569
570
571
572
573
574
575
576
577
578
CudaCalcGBVIForceKernel::~CudaCalcGBVIForceKernel() {
}

void CudaCalcGBVIForceKernel::initialize(const System& system, const GBVIForce& force, const std::vector<double> & inputScaledRadii) {

    int numParticles = system.getNumParticles();
    _gpuContext* gpu = data.gpu;

    vector<int> particle(numParticles);
    vector<float> radius(numParticles);
    vector<float> scaledRadii(numParticles);
    vector<float> gammas(numParticles);

    for (int i = 0; i < numParticles; i++) {
579
        double charge, particleRadius, gamma;
Mark Friedrichs's avatar
Mark Friedrichs committed
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
        force.getParticleParameters(i, charge, particleRadius, gamma );
        particle[i]                  = i;
        radius[i]                    = (float) particleRadius;
        gammas[i]                    = (float) gamma;
        scaledRadii[i]               = (float) inputScaledRadii[i];
    }
    gpuSetGBVIParameters(gpu, (float) force.getSoluteDielectric(), (float) force.getSolventDielectric(), particle,
                         radius, gammas, scaledRadii );
}

void CudaCalcGBVIForceKernel::executeForces(ContextImpl& context) {
}

double CudaCalcGBVIForceKernel::executeEnergy(ContextImpl& context) {
    return 0.0;
}

597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
CudaCalcCustomExternalForceKernel::~CudaCalcCustomExternalForceKernel() {
}

void CudaCalcCustomExternalForceKernel::initialize(const System& system, const CustomExternalForce& force) {
    numParticles = force.getNumParticles();
    vector<int> particle(numParticles);
    vector<vector<double> > params(numParticles);
    for (int i = 0; i < numParticles; i++)
        force.getParticleParameters(i, particle[i], params[i]);
    vector<string> paramNames;
    for (int i = 0; i < force.getNumPerParticleParameters(); i++)
        paramNames.push_back(force.getPerParticleParameterName(i));
    globalParamNames.resize(force.getNumGlobalParameters());
    globalParamValues.resize(force.getNumGlobalParameters());
    for (int i = 0; i < force.getNumGlobalParameters(); i++) {
        globalParamNames[i] = force.getGlobalParameterName(i);
        globalParamValues[i] = (float) force.getGlobalParameterDefaultValue(i);
    }
    gpuSetCustomExternalParameters(data.gpu, particle, params, force.getEnergyFunction(), paramNames, globalParamNames);
    if (globalParamValues.size() > 0)
Peter Eastman's avatar
Peter Eastman committed
617
        SetCustomExternalGlobalParams(globalParamValues);
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
}

void CudaCalcCustomExternalForceKernel::executeForces(ContextImpl& context) {
    updateGlobalParams(context);
    kCalculateCustomExternalForces(data.gpu);
}

double CudaCalcCustomExternalForceKernel::executeEnergy(ContextImpl& context) {
    updateGlobalParams(context);
    kCalculateCustomExternalForces(data.gpu);
    return 0.0;
}

void CudaCalcCustomExternalForceKernel::updateGlobalParams(ContextImpl& context) {
    bool changed = false;
    for (int i = 0; i < (int) globalParamNames.size(); i++) {
        float value = (float) context.getParameter(globalParamNames[i]);
        if (value != globalParamValues[i])
            changed = true;
        globalParamValues[i] = value;
    }
    if (changed)
Peter Eastman's avatar
Peter Eastman committed
640
        SetCustomExternalGlobalParams(globalParamValues);
641
642
}

643
static void initializeIntegration(const System& system, CudaPlatform::PlatformData& data, const Integrator& integrator) {
644
645
646
647
648
649
650
651
652
653
654
655
656
657

    // Initialize any terms that haven't already been handled by a Force.

    _gpuContext* gpu = data.gpu;
    if (!data.hasBonds)
        gpuSetBondParameters(gpu, vector<int>(), vector<int>(), vector<float>(), vector<float>());
    if (!data.hasAngles)
        gpuSetBondAngleParameters(gpu, vector<int>(), vector<int>(), vector<int>(), vector<float>(), vector<float>());
    if (!data.hasPeriodicTorsions)
        gpuSetDihedralParameters(gpu, vector<int>(), vector<int>(), vector<int>(), vector<int>(), vector<float>(), vector<float>(), vector<int>());
    if (!data.hasRB)
        gpuSetRbDihedralParameters(gpu, vector<int>(), vector<int>(), vector<int>(), vector<int>(), vector<float>(), vector<float>(),
                vector<float>(), vector<float>(), vector<float>(), vector<float>());
    if (!data.hasNonbonded) {
658
659
        gpuSetCoulombParameters(gpu, (float) ONE_4PI_EPS0, vector<int>(), vector<float>(), vector<float>(), vector<float>(), vector<char>(), vector<vector<int> >(), NO_CUTOFF);
        gpuSetLJ14Parameters(gpu, (float) ONE_4PI_EPS0, 1.0f, vector<int>(), vector<int>(), vector<float>(), vector<float>(), vector<float>(), vector<float>());
660
    }
661
662
663
    
    // Set masses.
    
Peter Eastman's avatar
Peter Eastman committed
664
665
666
667
    int numParticles = system.getNumParticles();
    vector<float> mass(numParticles);
    for (int i = 0; i < numParticles; i++)
        mass[i] = (float) system.getParticleMass(i);
668
669
670
671
    gpuSetMass(gpu, mass);
    
    // Set constraints.
    
672
    int numConstraints = system.getNumConstraints();
Peter Eastman's avatar
Peter Eastman committed
673
674
    vector<int> particle1(numConstraints);
    vector<int> particle2(numConstraints);
675
676
677
678
    vector<float> distance(numConstraints);
    vector<float> invMass1(numConstraints);
    vector<float> invMass2(numConstraints);
    for (int i = 0; i < numConstraints; i++) {
Peter Eastman's avatar
Peter Eastman committed
679
        int particle1Index, particle2Index;
680
        double constraintDistance;
Peter Eastman's avatar
Peter Eastman committed
681
682
683
        system.getConstraintParameters(i, particle1Index, particle2Index, constraintDistance);
        particle1[i] = particle1Index;
        particle2[i] = particle2Index;
684
        distance[i] = (float) constraintDistance;
Peter Eastman's avatar
Peter Eastman committed
685
686
        invMass1[i] = 1.0f/mass[particle1Index];
        invMass2[i] = 1.0f/mass[particle2Index];
687
    }
688
    gpuSetConstraintParameters(gpu, particle1, particle2, distance, invMass1, invMass2, (float)integrator.getConstraintTolerance());
689
690
    
    // Finish initialization.
691

692
693
694
    gpuBuildThreadBlockWorkList(gpu);
    gpuBuildExclusionList(gpu);
    gpuBuildOutputBuffers(gpu);
695
    gpuSetConstants(gpu);
696
697
698
    kClearBornForces(gpu);
    kClearForces(gpu);
    cudaThreadSynchronize();
699
700
}

701
double CudaCalcGBSAOBCForceKernel::executeEnergy(ContextImpl& context) {
702
	return 0.0;
703
704
705
706
707
708
}

CudaIntegrateVerletStepKernel::~CudaIntegrateVerletStepKernel() {
}

void CudaIntegrateVerletStepKernel::initialize(const System& system, const VerletIntegrator& integrator) {
709
    initializeIntegration(system, data, integrator);
710
711
712
    prevStepSize = -1.0;
}

713
void CudaIntegrateVerletStepKernel::execute(ContextImpl& context, const VerletIntegrator& integrator) {
714
715
716
717
718
    _gpuContext* gpu = data.gpu;
    double stepSize = integrator.getStepSize();
    if (stepSize != prevStepSize) {
        // Initialize the GPU parameters.
        
719
        gpuSetVerletIntegrationParameters(gpu, (float) stepSize, 0.0f);
720
721
722
723
724
        gpuSetConstants(gpu);
        prevStepSize = stepSize;
    }
    kVerletUpdatePart1(gpu);
    kApplyFirstShake(gpu);
725
    kApplyFirstSettle(gpu);
726
    kApplyFirstCCMA(gpu);
727
728
    if (data.removeCM)
        if (data.stepCount%data.cmMotionFrequency == 0)
729
730
            gpu->bCalculateCM = true;
    kVerletUpdatePart2(gpu);
731
    data.time += stepSize;
732
    data.stepCount++;
733
734
735
736
737
738
}

CudaIntegrateLangevinStepKernel::~CudaIntegrateLangevinStepKernel() {
}

void CudaIntegrateLangevinStepKernel::initialize(const System& system, const LangevinIntegrator& integrator) {
739
    initializeIntegration(system, data, integrator);
740
741
742
    _gpuContext* gpu = data.gpu;
    gpu->seed = (unsigned long) integrator.getRandomNumberSeed();
    gpuInitializeRandoms(gpu);
743
744
    prevTemp = -1.0;
    prevFriction = -1.0;
745
746
747
    prevStepSize = -1.0;
}

748
void CudaIntegrateLangevinStepKernel::execute(ContextImpl& context, const LangevinIntegrator& integrator) {
749
    _gpuContext* gpu = data.gpu;
750
751
752
    double temperature = integrator.getTemperature();
    double friction = integrator.getFriction();
    double stepSize = integrator.getStepSize();
753
754
    if (temperature != prevTemp || friction != prevFriction || stepSize != prevStepSize) {
        // Initialize the GPU parameters.
755
        
756
        double tau = (friction == 0.0 ? 0.0 : 1.0/friction);
757
        gpuSetLangevinIntegrationParameters(gpu, (float) tau, (float) stepSize, (float) temperature, 0.0f);
758
759
760
761
762
763
        gpuSetConstants(gpu);
        kGenerateRandoms(gpu);
        prevTemp = temperature;
        prevFriction = friction;
        prevStepSize = stepSize;
    }
764
    kLangevinUpdatePart1(gpu);
765
    kApplyFirstShake(gpu);
766
    kApplyFirstSettle(gpu);
767
    kApplyFirstCCMA(gpu);
768
769
    if (data.removeCM)
        if (data.stepCount%data.cmMotionFrequency == 0)
770
            gpu->bCalculateCM = true;
771
    kLangevinUpdatePart2(gpu);
772
    kApplySecondShake(gpu);
773
    kApplySecondSettle(gpu);
774
    kApplySecondCCMA(gpu);
775
    data.time += stepSize;
776
    data.stepCount++;
777
}
778
779
780
781
782

CudaIntegrateBrownianStepKernel::~CudaIntegrateBrownianStepKernel() {
}

void CudaIntegrateBrownianStepKernel::initialize(const System& system, const BrownianIntegrator& integrator) {
783
    initializeIntegration(system, data, integrator);
784
785
786
    _gpuContext* gpu = data.gpu;
    gpu->seed = (unsigned long) integrator.getRandomNumberSeed();
    gpuInitializeRandoms(gpu);
787
788
    prevTemp = -1.0;
    prevFriction = -1.0;
789
790
791
    prevStepSize = -1.0;
}

792
void CudaIntegrateBrownianStepKernel::execute(ContextImpl& context, const BrownianIntegrator& integrator) {
793
794
795
796
797
798
799
800
    _gpuContext* gpu = data.gpu;
    double temperature = integrator.getTemperature();
    double friction = integrator.getFriction();
    double stepSize = integrator.getStepSize();
    if (temperature != prevTemp || friction != prevFriction || stepSize != prevStepSize) {
        // Initialize the GPU parameters.
        
        double tau = (friction == 0.0 ? 0.0 : 1.0/friction);
801
        gpuSetBrownianIntegrationParameters(gpu, (float) tau, (float) stepSize, (float) temperature);
802
803
804
805
806
807
808
809
        gpuSetConstants(gpu);
        kGenerateRandoms(gpu);
        prevTemp = temperature;
        prevFriction = friction;
        prevStepSize = stepSize;
    }
    kBrownianUpdatePart1(gpu);
    kApplyFirstShake(gpu);
810
    kApplyFirstSettle(gpu);
811
    kApplyFirstCCMA(gpu);
812
813
    if (data.removeCM)
        if (data.stepCount%data.cmMotionFrequency == 0)
814
815
            gpu->bCalculateCM = true;
    kBrownianUpdatePart2(gpu);
816
    data.time += stepSize;
817
818
819
820
821
822
823
824
825
826
827
    data.stepCount++;
}

CudaIntegrateVariableVerletStepKernel::~CudaIntegrateVariableVerletStepKernel() {
}

void CudaIntegrateVariableVerletStepKernel::initialize(const System& system, const VariableVerletIntegrator& integrator) {
    initializeIntegration(system, data, integrator);
    prevErrorTol = -1.0;
}

828
void CudaIntegrateVariableVerletStepKernel::execute(ContextImpl& context, const VariableVerletIntegrator& integrator, double maxTime) {
829
830
831
832
833
834
835
836
837
    _gpuContext* gpu = data.gpu;
    double errorTol = integrator.getErrorTolerance();
    if (errorTol != prevErrorTol) {
        // Initialize the GPU parameters.

        gpuSetVerletIntegrationParameters(gpu, 0.0f, (float) errorTol);
        gpuSetConstants(gpu);
        prevErrorTol = errorTol;
    }
838
    float maxStepSize = (float)(maxTime-data.time);
839
    kSelectVerletStepSize(gpu, maxStepSize);
840
841
842
843
844
845
846
847
848
849
    kVerletUpdatePart1(gpu);
    kApplyFirstShake(gpu);
    kApplyFirstSettle(gpu);
    kApplyFirstCCMA(gpu);
    if (data.removeCM)
        if (data.stepCount%data.cmMotionFrequency == 0)
            gpu->bCalculateCM = true;
    kVerletUpdatePart2(gpu);
    gpu->psStepSize->Download();
    data.time += (*gpu->psStepSize)[0].y;
850
851
    if ((*gpu->psStepSize)[0].y == maxStepSize)
        data.time = maxTime; // Avoid round-off error
852
    data.stepCount++;
853
}
854

855
856
857
858
859
860
861
862
CudaIntegrateVariableLangevinStepKernel::~CudaIntegrateVariableLangevinStepKernel() {
}

void CudaIntegrateVariableLangevinStepKernel::initialize(const System& system, const VariableLangevinIntegrator& integrator) {
    initializeIntegration(system, data, integrator);
    _gpuContext* gpu = data.gpu;
    gpu->seed = (unsigned long) integrator.getRandomNumberSeed();
    gpuInitializeRandoms(gpu);
863
864
    prevTemp = -1.0;
    prevFriction = -1.0;
865
866
867
868
869
870
871
872
873
874
875
876
    prevErrorTol = -1.0;
}

void CudaIntegrateVariableLangevinStepKernel::execute(ContextImpl& context, const VariableLangevinIntegrator& integrator, double maxTime) {
    _gpuContext* gpu = data.gpu;
    double temperature = integrator.getTemperature();
    double friction = integrator.getFriction();
    double errorTol = integrator.getErrorTolerance();
    if (temperature != prevTemp || friction != prevFriction || errorTol != prevErrorTol) {
        // Initialize the GPU parameters.

        double tau = (friction == 0.0 ? 0.0 : 1.0/friction);
877
        gpuSetLangevinIntegrationParameters(gpu, (float) tau, 0.0f, (float) temperature, (float) errorTol);
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
        gpuSetConstants(gpu);
        kGenerateRandoms(gpu);
        prevTemp = temperature;
        prevFriction = friction;
        prevErrorTol = errorTol;
    }
    float maxStepSize = (float)(maxTime-data.time);
    kSelectLangevinStepSize(gpu, maxStepSize);
    kLangevinUpdatePart1(gpu);
    kApplyFirstShake(gpu);
    kApplyFirstSettle(gpu);
    kApplyFirstCCMA(gpu);
    if (data.removeCM)
        if (data.stepCount%data.cmMotionFrequency == 0)
            gpu->bCalculateCM = true;
    kLangevinUpdatePart2(gpu);
    kApplySecondShake(gpu);
    kApplySecondSettle(gpu);
    kApplySecondCCMA(gpu);
    gpu->psStepSize->Download();
    data.time += (*gpu->psStepSize)[0].y;
    if ((*gpu->psStepSize)[0].y == maxStepSize)
        data.time = maxTime; // Avoid round-off error
    data.stepCount++;
}

904
905
906
907
CudaApplyAndersenThermostatKernel::~CudaApplyAndersenThermostatKernel() {
}

void CudaApplyAndersenThermostatKernel::initialize(const System& system, const AndersenThermostat& thermostat) {
908
909
910
    _gpuContext* gpu = data.gpu;
    gpu->seed = (unsigned long) thermostat.getRandomNumberSeed();
    gpuInitializeRandoms(gpu);
911
912
    prevTemp = -1.0;
    prevFrequency = -1.0;
913
914
915
    prevStepSize = -1.0;
}

916
void CudaApplyAndersenThermostatKernel::execute(ContextImpl& context) {
917
    _gpuContext* gpu = data.gpu;
918
919
    double temperature = context.getParameter(AndersenThermostat::Temperature());
    double frequency = context.getParameter(AndersenThermostat::CollisionFrequency());
920
921
922
923
    double stepSize = context.getIntegrator().getStepSize();
    if (temperature != prevTemp || frequency != prevFrequency || stepSize != prevStepSize) {
        // Initialize the GPU parameters.
        
924
        gpuSetAndersenThermostatParameters(gpu, (float) temperature, (float) frequency);
925
926
927
928
929
930
931
932
        gpuSetConstants(gpu);
        kGenerateRandoms(gpu);
        prevTemp = temperature;
        prevFrequency = frequency;
        prevStepSize = stepSize;
    }
    kCalculateAndersenThermostat(gpu);
}
933

934
void CudaCalcKineticEnergyKernel::initialize(const System& system) {
Peter Eastman's avatar
Peter Eastman committed
935
936
    int numParticles = system.getNumParticles();
    masses.resize(numParticles);
937
    for (int i = 0; i < numParticles; ++i)
Peter Eastman's avatar
Peter Eastman committed
938
        masses[i] = system.getParticleMass(i);
939
940
}

941
double CudaCalcKineticEnergyKernel::execute(ContextImpl& context) {
942
943
944
    // We don't currently have a GPU kernel to do this, so we retrieve the velocities and calculate the energy
    // on the CPU.
    
945
946
    _gpuContext* gpu = data.gpu;
    gpu->psVelm4->Download();
947
    double energy = 0.0;
948
949
950
951
    for (int i = 0; i < (int) masses.size(); ++i) {
        float4 v = (*gpu->psVelm4)[i];
        energy += masses[i]*(v.x*v.x+v.y*v.y+v.z*v.z);
    }
952
953
    return 0.5*energy;
}
954

955
void CudaRemoveCMMotionKernel::initialize(const System& system, const CMMotionRemover& force) {
956
    data.removeCM = true;
957
    data.cmMotionFrequency = force.getFrequency();
958
959
}

960
void CudaRemoveCMMotionKernel::execute(ContextImpl& context) {
961
}