CudaKernels.cpp 32.6 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
35
36
37
38
39
40
#include <cmath>

extern "C" int gpuSetConstants( gpuContext gpu );

using namespace OpenMM;
using namespace std;

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

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

void CudaCalcForcesAndEnergyKernel::finishForceComputation(ContextImpl& context) {
    _gpuContext* gpu = data.gpu;
54
    if (gpu->bIncludeGBSA) {
55
        gpu->bRecalculateBornRadii = true;
56
57
58
59
        kCalculateCDLJObcGbsaForces1(gpu);
        kReduceObcGbsaBornForces(gpu);
        kCalculateObcGbsaForces2(gpu);
    }
60
    else if (data.hasNonbonded)
61
        kCalculateCDLJForces(gpu);
62
63
    if (data.hasCustomNonbonded)
        kCalculateCustomNonbondedForces(gpu, data.hasNonbonded);
64
    kCalculateLocalForces(gpu);
65
    kReduceForces(gpu);
66
67
}

68
void CudaCalcForcesAndEnergyKernel::beginEnergyComputation(ContextImpl& context) {
69
    _gpuContext* gpu = data.gpu;
70
71
72
73
    if (data.nonbondedMethod != NO_CUTOFF && data.stepCount%100 == 0)
        gpuReorderAtoms(gpu);
    data.stepCount++;
    kClearEnergy(gpu);
74
75
76
77
}

double CudaCalcForcesAndEnergyKernel::finishEnergyComputation(ContextImpl& context) {
    _gpuContext* gpu = data.gpu;
78
79
80
81
82
    if (gpu->bIncludeGBSA) {
        gpu->bRecalculateBornRadii = true;
        kCalculateCDLJObcGbsaForces1(gpu);
        kReduceObcGbsaBornForces(gpu);
        kCalculateObcGbsaForces2(gpu);
83
    }
84
85
86
87
88
89
90
91
    else if (data.hasNonbonded)
        kCalculateCDLJForces(gpu);
    if (data.hasCustomNonbonded)
        kCalculateCustomNonbondedForces(gpu, data.hasNonbonded);
    kCalculateLocalForces(gpu);
    if (gpu->bIncludeGBSA)
        kReduceBornSumAndForces(gpu);
    return kReduceEnergy(gpu)+data.ewaldSelfEnergy;
92
93
}

94
void CudaUpdateStateDataKernel::initialize(const System& system) {
95
96
}

97
double CudaUpdateStateDataKernel::getTime(const ContextImpl& context) const {
98
99
100
    return data.time;
}

101
void CudaUpdateStateDataKernel::setTime(ContextImpl& context, double time) {
102
103
104
    data.time = time;
}

105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
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]];
        pos.x = p[0];
        pos.y = p[1];
        pos.z = p[2];
    }
    gpu->psPosq4->Upload();
    for (int i = 0; i < gpu->posCellOffsets.size(); i++)
        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]];
        vel.x = v[0];
        vel.y = v[1];
        vel.z = v[2];
    }
    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);
    }
}

172
173
174
175
176
CudaCalcHarmonicBondForceKernel::~CudaCalcHarmonicBondForceKernel() {
}

void CudaCalcHarmonicBondForceKernel::initialize(const System& system, const HarmonicBondForce& force) {
    data.hasBonds = true;
177
    numBonds = force.getNumBonds();
Peter Eastman's avatar
Peter Eastman committed
178
179
    vector<int> particle1(numBonds);
    vector<int> particle2(numBonds);
180
181
182
183
    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
184
        force.getBondParameters(i, particle1[i], particle2[i], lengthValue, kValue);
185
186
187
        length[i] = (float) lengthValue;
        k[i] = (float) kValue;
    }
Peter Eastman's avatar
Peter Eastman committed
188
    gpuSetBondParameters(data.gpu, particle1, particle2, length, k);
189
190
}

191
void CudaCalcHarmonicBondForceKernel::executeForces(ContextImpl& context) {
192
193
}

194
double CudaCalcHarmonicBondForceKernel::executeEnergy(ContextImpl& context) {
195
196
197
198
199
200
201
202
    return 0.0;
}

CudaCalcHarmonicAngleForceKernel::~CudaCalcHarmonicAngleForceKernel() {
}

void CudaCalcHarmonicAngleForceKernel::initialize(const System& system, const HarmonicAngleForce& force) {
    data.hasAngles = true;
203
    numAngles = force.getNumAngles();
204
    const float RadiansToDegrees = (float) (180.0/3.14159265);
Peter Eastman's avatar
Peter Eastman committed
205
206
207
    vector<int> particle1(numAngles);
    vector<int> particle2(numAngles);
    vector<int> particle3(numAngles);
208
209
210
211
    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
212
        force.getAngleParameters(i, particle1[i], particle2[i], particle3[i], angleValue, kValue);
213
214
        angle[i] = (float) (angleValue*RadiansToDegrees);
        k[i] = (float) kValue;
215
    }
Peter Eastman's avatar
Peter Eastman committed
216
    gpuSetBondAngleParameters(data.gpu, particle1, particle2, particle3, angle, k);
217
}
218

219
void CudaCalcHarmonicAngleForceKernel::executeForces(ContextImpl& context) {
220
221
}

222
double CudaCalcHarmonicAngleForceKernel::executeEnergy(ContextImpl& context) {
223
224
225
226
227
228
229
230
231
    return 0.0;
}

CudaCalcPeriodicTorsionForceKernel::~CudaCalcPeriodicTorsionForceKernel() {
}

void CudaCalcPeriodicTorsionForceKernel::initialize(const System& system, const PeriodicTorsionForce& force) {
    data.hasPeriodicTorsions = true;
    numTorsions = force.getNumTorsions();
232
    const float RadiansToDegrees = (float)(180.0/3.14159265);
Peter Eastman's avatar
Peter Eastman committed
233
234
235
236
    vector<int> particle1(numTorsions);
    vector<int> particle2(numTorsions);
    vector<int> particle3(numTorsions);
    vector<int> particle4(numTorsions);
237
238
239
240
241
    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
242
        force.getTorsionParameters(i, particle1[i], particle2[i], particle3[i], particle4[i], periodicity[i], phaseValue, kValue);
243
244
        k[i] = (float) kValue;
        phase[i] = (float) (phaseValue*RadiansToDegrees);
245
    }
Peter Eastman's avatar
Peter Eastman committed
246
    gpuSetDihedralParameters(data.gpu, particle1, particle2, particle3, particle4, k, phase, periodicity);
247
248
}

249
void CudaCalcPeriodicTorsionForceKernel::executeForces(ContextImpl& context) {
250
251
}

252
double CudaCalcPeriodicTorsionForceKernel::executeEnergy(ContextImpl& context) {
253
254
255
256
257
258
259
260
261
    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
262
263
264
265
    vector<int> particle1(numTorsions);
    vector<int> particle2(numTorsions);
    vector<int> particle3(numTorsions);
    vector<int> particle4(numTorsions);
266
267
268
269
270
271
272
273
    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
274
        force.getTorsionParameters(i, particle1[i], particle2[i], particle3[i], particle4[i], c[0], c[1], c[2], c[3], c[4], c[5]);
275
276
277
278
279
280
        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];
281
    }
Peter Eastman's avatar
Peter Eastman committed
282
    gpuSetRbDihedralParameters(data.gpu, particle1, particle2, particle3, particle4, c0, c1, c2, c3, c4, c5);
283
284
}

285
void CudaCalcRBTorsionForceKernel::executeForces(ContextImpl& context) {
286
287
}

288
double CudaCalcRBTorsionForceKernel::executeEnergy(ContextImpl& context) {
289
290
291
292
293
294
    return 0.0;
}

CudaCalcNonbondedForceKernel::~CudaCalcNonbondedForceKernel() {
}

295
void CudaCalcNonbondedForceKernel::initialize(const System& system, const NonbondedForce& force) {
296
    data.hasNonbonded = true;
Peter Eastman's avatar
Peter Eastman committed
297
    numParticles = force.getNumParticles();
298
    _gpuContext* gpu = data.gpu;
299
300
301
302

    // Identify which exceptions are 1-4 interactions.

    vector<pair<int, int> > exclusions;
303
    vector<int> exceptions;
304
305
306
307
308
309
    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)
310
            exceptions.push_back(i);
311
312
    }

313
314
    // Initialize nonbonded interactions.
    
315
    {
Peter Eastman's avatar
Peter Eastman committed
316
317
318
319
        vector<int> particle(numParticles);
        vector<float> c6(numParticles);
        vector<float> c12(numParticles);
        vector<float> q(numParticles);
320
        vector<char> symbol;
Peter Eastman's avatar
Peter Eastman committed
321
322
        vector<vector<int> > exclusionList(numParticles);
        for (int i = 0; i < numParticles; i++) {
323
            double charge, radius, depth;
Peter Eastman's avatar
Peter Eastman committed
324
325
            force.getParticleParameters(i, charge, radius, depth);
            particle[i] = i;
326
327
328
            q[i] = (float) charge;
            c6[i] = (float) (4*depth*pow(radius, 6.0));
            c12[i] = (float) (4*depth*pow(radius, 12.0));
329
330
            exclusionList[i].push_back(i);
        }
331
        for (int i = 0; i < (int)exclusions.size(); i++) {
332
333
334
            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
335
        Vec3 boxVectors[3];
336
        system.getPeriodicBoxVectors(boxVectors[0], boxVectors[1], boxVectors[2]);
Peter Eastman's avatar
Peter Eastman committed
337
        gpuSetPeriodicBoxSize(gpu, (float)boxVectors[0][0], (float)boxVectors[1][1], (float)boxVectors[2][2]);
338
339
        CudaNonbondedMethod method = NO_CUTOFF;
        if (force.getNonbondedMethod() != NonbondedForce::NoCutoff) {
340
            gpuSetNonbondedCutoff(gpu, (float)force.getCutoffDistance(), force.getReactionFieldDielectric());
341
342
343
344
345
            method = CUTOFF;
        }
        if (force.getNonbondedMethod() == NonbondedForce::CutoffPeriodic) {
            method = PERIODIC;
        }
346
347
        if (force.getNonbondedMethod() == NonbondedForce::Ewald || force.getNonbondedMethod() == NonbondedForce::PME) {
            if (force.getNonbondedMethod() == NonbondedForce::Ewald) {
348
349
350
                double alpha;
                int kmaxx, kmaxy, kmaxz;
                NonbondedForceImpl::calcEwaldParameters(system, force, alpha, kmaxx, kmaxy, kmaxz);
351
352
353
354
                gpuSetEwaldParameters(gpu, (float) alpha, kmaxx, kmaxy, kmaxz);
                method = EWALD;
            }
            else {
355
356
357
                double alpha;
                int gridSizeX, gridSizeY, gridSizeZ;
                NonbondedForceImpl::calcPMEParameters(system, force, alpha, gridSizeX, gridSizeY, gridSizeZ);
Peter Eastman's avatar
Peter Eastman committed
358
                gpuSetPMEParameters(gpu, (float) alpha, gridSizeX, gridSizeY, gridSizeZ);
359
360
                method = PARTICLE_MESH_EWALD;
            }
361
        }
362
363
        data.nonbondedMethod = method;
        gpuSetCoulombParameters(gpu, 138.935485f, particle, c6, c12, q, symbol, exclusionList, method);
364
365
366
367

        // Compute the Ewald self energy.

        data.ewaldSelfEnergy = 0.0;
368
369
370
371
372
        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];
        }
373
374
375
376
    }

    // Initialize 1-4 nonbonded interactions.
    
377
    {
378
379
380
381
382
383
384
385
        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++) {
386
            double charge, sig, eps;
387
            force.getExceptionParameters(exceptions[i], particle1[i], particle2[i], charge, sig, eps);
388
389
            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
390
391
            q1[i] = (float) charge;
            q2[i] = 1.0f;
392
        }
Peter Eastman's avatar
Peter Eastman committed
393
        gpuSetLJ14Parameters(gpu, 138.935485f, 1.0f, particle1, particle2, c6, c12, q1, q2);
394
395
396
    }
}

397
void CudaCalcNonbondedForceKernel::executeForces(ContextImpl& context) {
398
399
}

400
double CudaCalcNonbondedForceKernel::executeEnergy(ContextImpl& context) {
401
    return 0.0;
402
403
}

404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
CudaCalcCustomNonbondedForceKernel::~CudaCalcCustomNonbondedForceKernel() {
}

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

    // Identify which exceptions are actual interactions.

    vector<pair<int, int> > exclusions;
    vector<int> exceptions;
    {
        vector<double> parameters;
        for (int i = 0; i < force.getNumExceptions(); i++) {
            int particle1, particle2;
            force.getExceptionParameters(i, particle1, particle2, parameters);
            exclusions.push_back(pair<int, int>(particle1, particle2));
            if (parameters.size() > 0)
                exceptions.push_back(i);
        }
    }

    // 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);
    }
    for (int i = 0; i < (int)exclusions.size(); i++) {
        exclusionList[exclusions[i].first].push_back(exclusions[i].second);
        exclusionList[exclusions[i].second].push_back(exclusions[i].first);
    }
441
442
443
    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]);
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
    CudaNonbondedMethod method = NO_CUTOFF;
    if (force.getNonbondedMethod() != CustomNonbondedForce::NoCutoff)
        method = CUTOFF;
    if (force.getNonbondedMethod() == CustomNonbondedForce::CutoffPeriodic) {
        method = PERIODIC;
    }
    data.customNonbondedMethod = method;

    // Initialize exceptions.

    int numExceptions = exceptions.size();
    vector<int> exceptionParticle1(numExceptions);
    vector<int> exceptionParticle2(numExceptions);
    vector<vector<double> > exceptionParams(numExceptions);
    for (int i = 0; i < numExceptions; i++)
        force.getExceptionParameters(exceptions[i], exceptionParticle1[i], exceptionParticle2[i], exceptionParams[i]);

461
462
463
464
465
466
467
468
469
470
471
    // 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);
    }

472
473
474
475
476
477
478
479
    // Record information for the expressions.

    vector<string> paramNames;
    vector<string> combiningRules;
    for (int i = 0; i < force.getNumParameters(); i++) {
        paramNames.push_back(force.getParameterName(i));
        combiningRules.push_back(force.getParameterCombiningRule(i));
    }
480
481
482
483
    globalParamNames.resize(force.getNumGlobalParameters());
    globalParamValues.resize(force.getNumGlobalParameters());
    for (int i = 0; i < force.getNumGlobalParameters(); i++) {
        globalParamNames[i] = force.getGlobalParameterName(i);
484
        globalParamValues[i] = (float) force.getGlobalParameterDefaultValue(i);
485
    }
486
    gpuSetCustomNonbondedParameters(gpu, parameters, exclusionList, exceptionParticle1, exceptionParticle2, exceptionParams, method,
487
488
            (float)force.getCutoffDistance(), force.getEnergyFunction(), combiningRules, paramNames, globalParamNames);
    if (globalParamValues.size() > 0)
489
        SetCustomNonbondedGlobalParams(&globalParamValues[0]);
490
491
492
}

void CudaCalcCustomNonbondedForceKernel::executeForces(ContextImpl& context) {
493
    updateGlobalParams(context);
494
495
496
}

double CudaCalcCustomNonbondedForceKernel::executeEnergy(ContextImpl& context) {
497
    updateGlobalParams(context);
498
499
500
    return 0.0;
}

501
502
void CudaCalcCustomNonbondedForceKernel::updateGlobalParams(ContextImpl& context) {
    bool changed = false;
503
    for (int i = 0; i < (int) globalParamNames.size(); i++) {
504
505
506
507
508
509
        float value = (float) context.getParameter(globalParamNames[i]);
        if (value != globalParamValues[i])
            changed = true;
        globalParamValues[i] = value;
    }
    if (changed)
510
        SetCustomNonbondedGlobalParams(&globalParamValues[0]);
511
512
}

513
CudaCalcGBSAOBCForceKernel::~CudaCalcGBSAOBCForceKernel() {
514
515
}

516
void CudaCalcGBSAOBCForceKernel::initialize(const System& system, const GBSAOBCForce& force) {
517

Peter Eastman's avatar
Peter Eastman committed
518
    int numParticles = system.getNumParticles();
519
    _gpuContext* gpu = data.gpu;
Peter Eastman's avatar
Peter Eastman committed
520
521
    vector<float> radius(numParticles);
    vector<float> scale(numParticles);
522
    vector<float> charge(numParticles);
Peter Eastman's avatar
Peter Eastman committed
523
    for (int i = 0; i < numParticles; i++) {
524
525
        double particleCharge, particleRadius, scalingFactor;
        force.getParticleParameters(i, particleCharge, particleRadius, scalingFactor);
Peter Eastman's avatar
Peter Eastman committed
526
        radius[i] = (float) particleRadius;
527
        scale[i] = (float) scalingFactor;
528
        charge[i] = (float) particleCharge;
529
    }
530
    gpuSetObcParameters(gpu, (float) force.getSoluteDielectric(), (float) force.getSolventDielectric(), radius, scale, charge);
531
532
}

533
void CudaCalcGBSAOBCForceKernel::executeForces(ContextImpl& context) {
534
535
}

536
static void initializeIntegration(const System& system, CudaPlatform::PlatformData& data, const Integrator& integrator) {
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553

    // 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) {
        gpuSetCoulombParameters(gpu, 138.935485f, vector<int>(), vector<float>(), vector<float>(), vector<float>(), vector<char>(), vector<vector<int> >(), NO_CUTOFF);
        gpuSetLJ14Parameters(gpu, 138.935485f, 1.0f, vector<int>(), vector<int>(), vector<float>(), vector<float>(), vector<float>(), vector<float>());
    }
554
555
556
    
    // Set masses.
    
Peter Eastman's avatar
Peter Eastman committed
557
558
559
560
    int numParticles = system.getNumParticles();
    vector<float> mass(numParticles);
    for (int i = 0; i < numParticles; i++)
        mass[i] = (float) system.getParticleMass(i);
561
562
563
564
    gpuSetMass(gpu, mass);
    
    // Set constraints.
    
565
    int numConstraints = system.getNumConstraints();
Peter Eastman's avatar
Peter Eastman committed
566
567
    vector<int> particle1(numConstraints);
    vector<int> particle2(numConstraints);
568
569
570
571
    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
572
        int particle1Index, particle2Index;
573
        double constraintDistance;
Peter Eastman's avatar
Peter Eastman committed
574
575
576
        system.getConstraintParameters(i, particle1Index, particle2Index, constraintDistance);
        particle1[i] = particle1Index;
        particle2[i] = particle2Index;
577
        distance[i] = (float) constraintDistance;
Peter Eastman's avatar
Peter Eastman committed
578
579
        invMass1[i] = 1.0f/mass[particle1Index];
        invMass2[i] = 1.0f/mass[particle2Index];
580
    }
581
    gpuSetConstraintParameters(gpu, particle1, particle2, distance, invMass1, invMass2, (float)integrator.getConstraintTolerance());
582
583
    
    // Finish initialization.
584

585
586
587
    gpuBuildThreadBlockWorkList(gpu);
    gpuBuildExclusionList(gpu);
    gpuBuildOutputBuffers(gpu);
588
    gpuSetConstants(gpu);
589
590
591
    kClearBornForces(gpu);
    kClearForces(gpu);
    cudaThreadSynchronize();
592
593
}

594
double CudaCalcGBSAOBCForceKernel::executeEnergy(ContextImpl& context) {
595
	return 0.0;
596
597
598
599
600
601
}

CudaIntegrateVerletStepKernel::~CudaIntegrateVerletStepKernel() {
}

void CudaIntegrateVerletStepKernel::initialize(const System& system, const VerletIntegrator& integrator) {
602
    initializeIntegration(system, data, integrator);
603
604
605
    prevStepSize = -1.0;
}

606
void CudaIntegrateVerletStepKernel::execute(ContextImpl& context, const VerletIntegrator& integrator) {
607
608
609
610
611
    _gpuContext* gpu = data.gpu;
    double stepSize = integrator.getStepSize();
    if (stepSize != prevStepSize) {
        // Initialize the GPU parameters.
        
612
        gpuSetVerletIntegrationParameters(gpu, (float) stepSize, 0.0f);
613
614
615
616
617
        gpuSetConstants(gpu);
        prevStepSize = stepSize;
    }
    kVerletUpdatePart1(gpu);
    kApplyFirstShake(gpu);
618
    kApplyFirstSettle(gpu);
619
    kApplyFirstCCMA(gpu);
620
621
    if (data.removeCM)
        if (data.stepCount%data.cmMotionFrequency == 0)
622
623
            gpu->bCalculateCM = true;
    kVerletUpdatePart2(gpu);
624
    data.time += stepSize;
625
    data.stepCount++;
626
627
628
629
630
631
}

CudaIntegrateLangevinStepKernel::~CudaIntegrateLangevinStepKernel() {
}

void CudaIntegrateLangevinStepKernel::initialize(const System& system, const LangevinIntegrator& integrator) {
632
    initializeIntegration(system, data, integrator);
633
634
635
    _gpuContext* gpu = data.gpu;
    gpu->seed = (unsigned long) integrator.getRandomNumberSeed();
    gpuInitializeRandoms(gpu);
636
637
638
    prevStepSize = -1.0;
}

639
void CudaIntegrateLangevinStepKernel::execute(ContextImpl& context, const LangevinIntegrator& integrator) {
640
    _gpuContext* gpu = data.gpu;
641
642
643
    double temperature = integrator.getTemperature();
    double friction = integrator.getFriction();
    double stepSize = integrator.getStepSize();
644
645
646
647
    if (temperature != prevTemp || friction != prevFriction || stepSize != prevStepSize) {
        // Initialize the GPU parameters.
        
        double tau = (friction == 0.0 ? 0.0 : 1.0/friction);
648
        gpuSetLangevinIntegrationParameters(gpu, (float) tau, (float) stepSize, (float) temperature, 0.0f);
649
650
651
652
653
654
        gpuSetConstants(gpu);
        kGenerateRandoms(gpu);
        prevTemp = temperature;
        prevFriction = friction;
        prevStepSize = stepSize;
    }
655
    kLangevinUpdatePart1(gpu);
656
    kApplyFirstShake(gpu);
657
    kApplyFirstSettle(gpu);
658
    kApplyFirstCCMA(gpu);
659
660
    if (data.removeCM)
        if (data.stepCount%data.cmMotionFrequency == 0)
661
            gpu->bCalculateCM = true;
662
    kLangevinUpdatePart2(gpu);
663
    kApplySecondShake(gpu);
664
    kApplySecondSettle(gpu);
665
    kApplySecondCCMA(gpu);
666
    data.time += stepSize;
667
    data.stepCount++;
668
}
669
670
671
672
673

CudaIntegrateBrownianStepKernel::~CudaIntegrateBrownianStepKernel() {
}

void CudaIntegrateBrownianStepKernel::initialize(const System& system, const BrownianIntegrator& integrator) {
674
    initializeIntegration(system, data, integrator);
675
676
677
    _gpuContext* gpu = data.gpu;
    gpu->seed = (unsigned long) integrator.getRandomNumberSeed();
    gpuInitializeRandoms(gpu);
678
679
680
    prevStepSize = -1.0;
}

681
void CudaIntegrateBrownianStepKernel::execute(ContextImpl& context, const BrownianIntegrator& integrator) {
682
683
684
685
686
687
688
689
    _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);
690
        gpuSetBrownianIntegrationParameters(gpu, (float) tau, (float) stepSize, (float) temperature);
691
692
693
694
695
696
697
698
        gpuSetConstants(gpu);
        kGenerateRandoms(gpu);
        prevTemp = temperature;
        prevFriction = friction;
        prevStepSize = stepSize;
    }
    kBrownianUpdatePart1(gpu);
    kApplyFirstShake(gpu);
699
    kApplyFirstSettle(gpu);
700
    kApplyFirstCCMA(gpu);
701
702
    if (data.removeCM)
        if (data.stepCount%data.cmMotionFrequency == 0)
703
704
            gpu->bCalculateCM = true;
    kBrownianUpdatePart2(gpu);
705
    data.time += stepSize;
706
707
708
709
710
711
712
713
714
715
716
    data.stepCount++;
}

CudaIntegrateVariableVerletStepKernel::~CudaIntegrateVariableVerletStepKernel() {
}

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

717
void CudaIntegrateVariableVerletStepKernel::execute(ContextImpl& context, const VariableVerletIntegrator& integrator, double maxTime) {
718
719
720
721
722
723
724
725
726
    _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;
    }
727
    float maxStepSize = (float)(maxTime-data.time);
728
    kSelectVerletStepSize(gpu, maxStepSize);
729
730
731
732
733
734
735
736
737
738
    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;
739
740
    if ((*gpu->psStepSize)[0].y == maxStepSize)
        data.time = maxTime; // Avoid round-off error
741
    data.stepCount++;
742
}
743

744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
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);
    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);
764
        gpuSetLangevinIntegrationParameters(gpu, (float) tau, 0.0f, (float) temperature, (float) errorTol);
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
        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++;
}

791
792
793
794
CudaApplyAndersenThermostatKernel::~CudaApplyAndersenThermostatKernel() {
}

void CudaApplyAndersenThermostatKernel::initialize(const System& system, const AndersenThermostat& thermostat) {
795
796
797
    _gpuContext* gpu = data.gpu;
    gpu->seed = (unsigned long) thermostat.getRandomNumberSeed();
    gpuInitializeRandoms(gpu);
798
799
800
    prevStepSize = -1.0;
}

801
void CudaApplyAndersenThermostatKernel::execute(ContextImpl& context) {
802
    _gpuContext* gpu = data.gpu;
803
804
    double temperature = context.getParameter(AndersenThermostat::Temperature());
    double frequency = context.getParameter(AndersenThermostat::CollisionFrequency());
805
806
807
808
    double stepSize = context.getIntegrator().getStepSize();
    if (temperature != prevTemp || frequency != prevFrequency || stepSize != prevStepSize) {
        // Initialize the GPU parameters.
        
809
        gpuSetAndersenThermostatParameters(gpu, (float) temperature, (float) frequency);
810
811
812
813
814
815
816
817
        gpuSetConstants(gpu);
        kGenerateRandoms(gpu);
        prevTemp = temperature;
        prevFrequency = frequency;
        prevStepSize = stepSize;
    }
    kCalculateAndersenThermostat(gpu);
}
818

819
void CudaCalcKineticEnergyKernel::initialize(const System& system) {
Peter Eastman's avatar
Peter Eastman committed
820
821
    int numParticles = system.getNumParticles();
    masses.resize(numParticles);
822
    for (int i = 0; i < numParticles; ++i)
Peter Eastman's avatar
Peter Eastman committed
823
        masses[i] = system.getParticleMass(i);
824
825
}

826
double CudaCalcKineticEnergyKernel::execute(ContextImpl& context) {
827
828
829
    // We don't currently have a GPU kernel to do this, so we retrieve the velocities and calculate the energy
    // on the CPU.
    
830
831
    _gpuContext* gpu = data.gpu;
    gpu->psVelm4->Download();
832
    double energy = 0.0;
833
834
835
836
    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);
    }
837
838
    return 0.5*energy;
}
839

840
void CudaRemoveCMMotionKernel::initialize(const System& system, const CMMotionRemover& force) {
841
    data.removeCM = true;
842
    data.cmMotionFrequency = force.getFrequency();
843
844
}

845
void CudaRemoveCMMotionKernel::execute(ContextImpl& context) {
846
}