CudaKernels.cpp 31.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
28
 * -------------------------------------------------------------------------- */

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

extern "C" int gpuSetConstants( gpuContext gpu );

using namespace OpenMM;
using namespace std;

42
static void calcForces(ContextImpl& context, CudaPlatform::PlatformData& data) {
43
    _gpuContext* gpu = data.gpu;
44
    gpu->bReduceEnergies = false;
45
    if (data.nonbondedMethod != NO_CUTOFF && data.computeForceCount%100 == 0)
46
        gpuReorderAtoms(gpu);
47
    data.computeForceCount++;
48
49
    kClearForces(gpu);
    if (gpu->bIncludeGBSA) {
50
        gpu->bRecalculateBornRadii = true;
51
52
53
54
        kCalculateCDLJObcGbsaForces1(gpu);
        kReduceObcGbsaBornForces(gpu);
        kCalculateObcGbsaForces2(gpu);
    }
55
    else if (data.hasNonbonded)
56
        kCalculateCDLJForces(gpu);
57
58
    if (data.hasCustomNonbonded)
        kCalculateCustomNonbondedForces(gpu, data.hasNonbonded);
59
    kCalculateLocalForces(gpu);
60
    kReduceForces(gpu);
61
62
}

63
64
//static double calcEnergy(ContextImpl& context, System& system) {
static double calcEnergy(ContextImpl& context, CudaPlatform::PlatformData& data, System& system) {
65

66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
    // New section 2009-09-03: calculate energies and forces, then return reduced energies

    _gpuContext* gpu = data.gpu;
    
    if (gpu->sim.nonbondedMethod == EWALD)
    {
        // We don't currently have GPU kernels to calculate energy, so instead we have the reference
        // platform do it.  This is VERY slow.

        LangevinIntegrator integrator(0.0, 1.0, 0.0);
        ReferencePlatform platform;
        Context refContext(system, integrator, platform);
        const Stream& positions = context.getPositions();
        double* posData = new double[positions.getSize()*3];
        positions.saveToArray(posData);
        vector<Vec3> pos(positions.getSize());
        for (int i = 0; i < (int)pos.size(); i++)
            pos[i] = Vec3(posData[3*i], posData[3*i+1], posData[3*i+2]);
        delete[] posData;
        refContext.setPositions(pos);
 //       printf("Total CPU energies: %f\n", refContext.getState(State::Energy).getPotentialEnergy());
        return refContext.getState(State::Energy).getPotentialEnergy();
    }
    else
    {
        double totalEnergy = 0.0f;
        double energy;
        gpu->bReduceEnergies = true;
        if (data.nonbondedMethod != NO_CUTOFF && data.stepCount%100 == 0)
            gpuReorderAtoms(gpu);
        data.stepCount++;
        kClearForces(gpu);
        if (gpu->bIncludeGBSA) {
            gpu->bRecalculateBornRadii = true;
            energy = kCalculateCDLJObcGbsaForces1(gpu);
    //        printf("Calculated CDLJObcGbsa energy: %f\n", energy);
            totalEnergy += energy;
            energy = kReduceObcGbsaBornForces(gpu);
    //        printf("Calculated reduced GbsaBorn surface area energy: %f\n", energy);
            totalEnergy += energy;
            kCalculateObcGbsaForces2(gpu);
        }
        else if (data.hasNonbonded) {
            energy = kCalculateCDLJForces(gpu);
    //        printf("Calculated CDLJ energy: %f\n", energy);
            totalEnergy += energy;
        }
        energy = kCalculateLocalForces(gpu);
    //    printf("Calculated local interactions energy: %f\n", energy);
        totalEnergy += energy;
        if (gpu->bIncludeGBSA)
            kReduceBornSumAndForces(gpu);
        else
            kReduceForces(gpu);
 //       printf("Total GPU energies: %f\n", totalEnergy);
        return totalEnergy;
    }
    return 0.0f;
124
125
}

126
127
128
void CudaInitializeForcesKernel::initialize(const System& system) {
}

129
void CudaInitializeForcesKernel::execute(ContextImpl& context) {
130
131
}

132
133
134
void CudaUpdateTimeKernel::initialize(const System& system) {
}

135
double CudaUpdateTimeKernel::getTime(const ContextImpl& context) const {
136
137
138
    return data.time;
}

139
void CudaUpdateTimeKernel::setTime(ContextImpl& context, double time) {
140
141
142
    data.time = time;
}

143
144
145
146
147
148
149
CudaCalcHarmonicBondForceKernel::~CudaCalcHarmonicBondForceKernel() {
}

void CudaCalcHarmonicBondForceKernel::initialize(const System& system, const HarmonicBondForce& force) {
    if (data.primaryKernel == NULL)
        data.primaryKernel = this;
    data.hasBonds = true;
150
    numBonds = force.getNumBonds();
Peter Eastman's avatar
Peter Eastman committed
151
152
    vector<int> particle1(numBonds);
    vector<int> particle2(numBonds);
153
154
155
156
    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
157
        force.getBondParameters(i, particle1[i], particle2[i], lengthValue, kValue);
158
159
160
        length[i] = (float) lengthValue;
        k[i] = (float) kValue;
    }
Peter Eastman's avatar
Peter Eastman committed
161
    gpuSetBondParameters(data.gpu, particle1, particle2, length, k);
162
163
}

164
void CudaCalcHarmonicBondForceKernel::executeForces(ContextImpl& context) {
165
166
167
168
    if (data.primaryKernel == this)
        calcForces(context, data);
}

169
double CudaCalcHarmonicBondForceKernel::executeEnergy(ContextImpl& context) {
170
    if (data.primaryKernel == this)
171
        return calcEnergy(context, data, system);
172
173
174
175
176
177
178
179
180
181
    return 0.0;
}

CudaCalcHarmonicAngleForceKernel::~CudaCalcHarmonicAngleForceKernel() {
}

void CudaCalcHarmonicAngleForceKernel::initialize(const System& system, const HarmonicAngleForce& force) {
    if (data.primaryKernel == NULL)
        data.primaryKernel = this;
    data.hasAngles = true;
182
    numAngles = force.getNumAngles();
183
    const float RadiansToDegrees = (float) (180.0/3.14159265);
Peter Eastman's avatar
Peter Eastman committed
184
185
186
    vector<int> particle1(numAngles);
    vector<int> particle2(numAngles);
    vector<int> particle3(numAngles);
187
188
189
190
    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
191
        force.getAngleParameters(i, particle1[i], particle2[i], particle3[i], angleValue, kValue);
192
193
        angle[i] = (float) (angleValue*RadiansToDegrees);
        k[i] = (float) kValue;
194
    }
Peter Eastman's avatar
Peter Eastman committed
195
    gpuSetBondAngleParameters(data.gpu, particle1, particle2, particle3, angle, k);
196
}
197

198
void CudaCalcHarmonicAngleForceKernel::executeForces(ContextImpl& context) {
199
200
201
202
    if (data.primaryKernel == this)
        calcForces(context, data);
}

203
double CudaCalcHarmonicAngleForceKernel::executeEnergy(ContextImpl& context) {
204
    if (data.primaryKernel == this)
205
        return calcEnergy(context, data, system);
206
207
208
209
210
211
212
213
214
215
216
    return 0.0;
}

CudaCalcPeriodicTorsionForceKernel::~CudaCalcPeriodicTorsionForceKernel() {
}

void CudaCalcPeriodicTorsionForceKernel::initialize(const System& system, const PeriodicTorsionForce& force) {
    if (data.primaryKernel == NULL)
        data.primaryKernel = this;
    data.hasPeriodicTorsions = true;
    numTorsions = force.getNumTorsions();
217
    const float RadiansToDegrees = (float)(180.0/3.14159265);
Peter Eastman's avatar
Peter Eastman committed
218
219
220
221
    vector<int> particle1(numTorsions);
    vector<int> particle2(numTorsions);
    vector<int> particle3(numTorsions);
    vector<int> particle4(numTorsions);
222
223
224
225
226
    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
227
        force.getTorsionParameters(i, particle1[i], particle2[i], particle3[i], particle4[i], periodicity[i], phaseValue, kValue);
228
229
        k[i] = (float) kValue;
        phase[i] = (float) (phaseValue*RadiansToDegrees);
230
    }
Peter Eastman's avatar
Peter Eastman committed
231
    gpuSetDihedralParameters(data.gpu, particle1, particle2, particle3, particle4, k, phase, periodicity);
232
233
}

234
void CudaCalcPeriodicTorsionForceKernel::executeForces(ContextImpl& context) {
235
236
237
238
    if (data.primaryKernel == this)
        calcForces(context, data);
}

239
double CudaCalcPeriodicTorsionForceKernel::executeEnergy(ContextImpl& context) {
240
    if (data.primaryKernel == this)
241
        return calcEnergy(context, data, system);
242
243
244
245
246
247
248
249
250
251
252
    return 0.0;
}

CudaCalcRBTorsionForceKernel::~CudaCalcRBTorsionForceKernel() {
}

void CudaCalcRBTorsionForceKernel::initialize(const System& system, const RBTorsionForce& force) {
    if (data.primaryKernel == NULL)
        data.primaryKernel = this;
    data.hasRB = true;
    numTorsions = force.getNumTorsions();
Peter Eastman's avatar
Peter Eastman committed
253
254
255
256
    vector<int> particle1(numTorsions);
    vector<int> particle2(numTorsions);
    vector<int> particle3(numTorsions);
    vector<int> particle4(numTorsions);
257
258
259
260
261
262
263
264
    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
265
        force.getTorsionParameters(i, particle1[i], particle2[i], particle3[i], particle4[i], c[0], c[1], c[2], c[3], c[4], c[5]);
266
267
268
269
270
271
        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];
272
    }
Peter Eastman's avatar
Peter Eastman committed
273
    gpuSetRbDihedralParameters(data.gpu, particle1, particle2, particle3, particle4, c0, c1, c2, c3, c4, c5);
274
275
}

276
void CudaCalcRBTorsionForceKernel::executeForces(ContextImpl& context) {
277
278
279
280
    if (data.primaryKernel == this)
        calcForces(context, data);
}

281
double CudaCalcRBTorsionForceKernel::executeEnergy(ContextImpl& context) {
282
    if (data.primaryKernel == this)
283
        return calcEnergy(context, data, system);
284
285
286
287
288
289
    return 0.0;
}

CudaCalcNonbondedForceKernel::~CudaCalcNonbondedForceKernel() {
}

290
void CudaCalcNonbondedForceKernel::initialize(const System& system, const NonbondedForce& force) {
291
292
293
    if (data.primaryKernel == NULL)
        data.primaryKernel = this;
    data.hasNonbonded = true;
Peter Eastman's avatar
Peter Eastman committed
294
    numParticles = force.getNumParticles();
295
    _gpuContext* gpu = data.gpu;
296
297
298
299

    // Identify which exceptions are 1-4 interactions.

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

310
311
    // Initialize nonbonded interactions.
    
312
    {
Peter Eastman's avatar
Peter Eastman committed
313
314
315
316
        vector<int> particle(numParticles);
        vector<float> c6(numParticles);
        vector<float> c12(numParticles);
        vector<float> q(numParticles);
317
        vector<char> symbol;
Peter Eastman's avatar
Peter Eastman committed
318
319
        vector<vector<int> > exclusionList(numParticles);
        for (int i = 0; i < numParticles; i++) {
320
            double charge, radius, depth;
Peter Eastman's avatar
Peter Eastman committed
321
322
            force.getParticleParameters(i, charge, radius, depth);
            particle[i] = i;
323
324
325
            q[i] = (float) charge;
            c6[i] = (float) (4*depth*pow(radius, 6.0));
            c12[i] = (float) (4*depth*pow(radius, 12.0));
326
327
            exclusionList[i].push_back(i);
        }
328
        for (int i = 0; i < (int)exclusions.size(); i++) {
329
330
331
            exclusionList[exclusions[i].first].push_back(exclusions[i].second);
            exclusionList[exclusions[i].second].push_back(exclusions[i].first);
        }
332
333
        CudaNonbondedMethod method = NO_CUTOFF;
        if (force.getNonbondedMethod() != NonbondedForce::NoCutoff) {
334
            gpuSetNonbondedCutoff(gpu, (float)force.getCutoffDistance(), force.getReactionFieldDielectric());
335
336
337
338
339
            method = CUTOFF;
        }
        if (force.getNonbondedMethod() == NonbondedForce::CutoffPeriodic) {
            Vec3 boxVectors[3];
            force.getPeriodicBoxVectors(boxVectors[0], boxVectors[1], boxVectors[2]);
340
            gpuSetPeriodicBoxSize(gpu, (float)boxVectors[0][0], (float)boxVectors[1][1], (float)boxVectors[2][2]);
341
342
            method = PERIODIC;
        }
343
344
345
346

        if (force.getNonbondedMethod() == NonbondedForce::Ewald) {
            Vec3 boxVectors[3];
            force.getPeriodicBoxVectors(boxVectors[0], boxVectors[1], boxVectors[2]);
347
            gpuSetPeriodicBoxSize(gpu, (float)boxVectors[0][0], (float)boxVectors[1][1], (float)boxVectors[2][2]);
348
349
350
351
352
353
            double ewaldErrorTol = force.getEwaldErrorTolerance();
            double alpha = (1.0/force.getCutoffDistance())*std::sqrt(-std::log(ewaldErrorTol));
            double mx = boxVectors[0][0]/force.getCutoffDistance();
            double my = boxVectors[1][1]/force.getCutoffDistance();
            double mz = boxVectors[2][2]/force.getCutoffDistance();
            double pi = 3.1415926535897932385;
354
355
356
            int kmaxx = (int)std::ceil(-(mx/pi)*std::log(ewaldErrorTol));
            int kmaxy = (int)std::ceil(-(my/pi)*std::log(ewaldErrorTol));
            int kmaxz = (int)std::ceil(-(mz/pi)*std::log(ewaldErrorTol));
357
358
359
360
361
362
            if (kmaxx%2 == 0)
                kmaxx++;
            if (kmaxy%2 == 0)
                kmaxy++;
            if (kmaxz%2 == 0)
                kmaxz++;
363
            gpuSetEwaldParameters(gpu, (float)alpha, kmaxx, kmaxy, kmaxz);
364
365
            method = EWALD;
        }
366
367
        data.nonbondedMethod = method;
        gpuSetCoulombParameters(gpu, 138.935485f, particle, c6, c12, q, symbol, exclusionList, method);
368
369
370
371
    }

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

392
void CudaCalcNonbondedForceKernel::executeForces(ContextImpl& context) {
393
394
    if (data.primaryKernel == this)
        calcForces(context, data);
395
396
}

397
double CudaCalcNonbondedForceKernel::executeEnergy(ContextImpl& context) {
398
    if (data.primaryKernel == this)
399
        return calcEnergy(context, data, system);
400
    return 0.0;
401
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
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
CudaCalcCustomNonbondedForceKernel::~CudaCalcCustomNonbondedForceKernel() {
}

void CudaCalcCustomNonbondedForceKernel::initialize(const System& system, const CustomNonbondedForce& force) {
    if (data.primaryKernel == NULL)
        data.primaryKernel = this;
    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);
    }
    CudaNonbondedMethod method = NO_CUTOFF;
    if (force.getNonbondedMethod() != CustomNonbondedForce::NoCutoff)
        method = CUTOFF;
    if (force.getNonbondedMethod() == CustomNonbondedForce::CutoffPeriodic) {
        Vec3 boxVectors[3];
        force.getPeriodicBoxVectors(boxVectors[0], boxVectors[1], boxVectors[2]);
        gpuSetPeriodicBoxSize(gpu, (float)boxVectors[0][0], (float)boxVectors[1][1], (float)boxVectors[2][2]);
        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]);

    // 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));
    }
    gpuSetCustomNonbondedParameters(gpu, parameters, exclusionList, exceptionParticle1, exceptionParticle2, exceptionParams, method,
            (float)force.getCutoffDistance(), force.getEnergyFunction(), combiningRules, paramNames);
}

void CudaCalcCustomNonbondedForceKernel::executeForces(ContextImpl& context) {
    if (data.primaryKernel == this)
        calcForces(context, data);
}

double CudaCalcCustomNonbondedForceKernel::executeEnergy(ContextImpl& context) {
    if (data.primaryKernel == this)
481
        return calcEnergy(context, data, system);
482
483
484
    return 0.0;
}

485
CudaCalcGBSAOBCForceKernel::~CudaCalcGBSAOBCForceKernel() {
486
487
}

488
void CudaCalcGBSAOBCForceKernel::initialize(const System& system, const GBSAOBCForce& force) {
489

Peter Eastman's avatar
Peter Eastman committed
490
    int numParticles = system.getNumParticles();
491
    _gpuContext* gpu = data.gpu;
Peter Eastman's avatar
Peter Eastman committed
492
493
    vector<float> radius(numParticles);
    vector<float> scale(numParticles);
494
    vector<float> charge(numParticles);
Peter Eastman's avatar
Peter Eastman committed
495
    for (int i = 0; i < numParticles; i++) {
496
497
        double particleCharge, particleRadius, scalingFactor;
        force.getParticleParameters(i, particleCharge, particleRadius, scalingFactor);
Peter Eastman's avatar
Peter Eastman committed
498
        radius[i] = (float) particleRadius;
499
        scale[i] = (float) scalingFactor;
500
        charge[i] = (float) particleCharge;
501
    }
502
    gpuSetObcParameters(gpu, (float) force.getSoluteDielectric(), (float) force.getSolventDielectric(), radius, scale, charge);
503
504
}

505
void CudaCalcGBSAOBCForceKernel::executeForces(ContextImpl& context) {
506
507
}

508
static void initializeIntegration(const System& system, CudaPlatform::PlatformData& data, const Integrator& integrator) {
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525

    // 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>());
    }
526
527
528
    
    // Set masses.
    
Peter Eastman's avatar
Peter Eastman committed
529
530
531
532
    int numParticles = system.getNumParticles();
    vector<float> mass(numParticles);
    for (int i = 0; i < numParticles; i++)
        mass[i] = (float) system.getParticleMass(i);
533
534
535
536
    gpuSetMass(gpu, mass);
    
    // Set constraints.
    
537
    int numConstraints = system.getNumConstraints();
Peter Eastman's avatar
Peter Eastman committed
538
539
    vector<int> particle1(numConstraints);
    vector<int> particle2(numConstraints);
540
541
542
543
    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
544
        int particle1Index, particle2Index;
545
        double constraintDistance;
Peter Eastman's avatar
Peter Eastman committed
546
547
548
        system.getConstraintParameters(i, particle1Index, particle2Index, constraintDistance);
        particle1[i] = particle1Index;
        particle2[i] = particle2Index;
549
        distance[i] = (float) constraintDistance;
Peter Eastman's avatar
Peter Eastman committed
550
551
        invMass1[i] = 1.0f/mass[particle1Index];
        invMass2[i] = 1.0f/mass[particle2Index];
552
    }
553
    gpuSetConstraintParameters(gpu, particle1, particle2, distance, invMass1, invMass2, (float)integrator.getConstraintTolerance());
554
555
    
    // Finish initialization.
556

557
558
559
    gpuBuildThreadBlockWorkList(gpu);
    gpuBuildExclusionList(gpu);
    gpuBuildOutputBuffers(gpu);
560
    gpuSetConstants(gpu);
561
562
563
    kClearBornForces(gpu);
    kClearForces(gpu);
    cudaThreadSynchronize();
564
565
}

566
double CudaCalcGBSAOBCForceKernel::executeEnergy(ContextImpl& context) {
567
	return 0.0;
568
569
570
571
572
573
}

CudaIntegrateVerletStepKernel::~CudaIntegrateVerletStepKernel() {
}

void CudaIntegrateVerletStepKernel::initialize(const System& system, const VerletIntegrator& integrator) {
574
    initializeIntegration(system, data, integrator);
575
576
577
    prevStepSize = -1.0;
}

578
void CudaIntegrateVerletStepKernel::execute(ContextImpl& context, const VerletIntegrator& integrator) {
579
580
581
582
583
    _gpuContext* gpu = data.gpu;
    double stepSize = integrator.getStepSize();
    if (stepSize != prevStepSize) {
        // Initialize the GPU parameters.
        
584
        gpuSetVerletIntegrationParameters(gpu, (float) stepSize, 0.0f);
585
586
587
588
589
        gpuSetConstants(gpu);
        prevStepSize = stepSize;
    }
    kVerletUpdatePart1(gpu);
    kApplyFirstShake(gpu);
590
    kApplyFirstSettle(gpu);
591
    kApplyFirstCCMA(gpu);
592
593
    if (data.removeCM)
        if (data.stepCount%data.cmMotionFrequency == 0)
594
595
            gpu->bCalculateCM = true;
    kVerletUpdatePart2(gpu);
596
    data.time += stepSize;
597
    data.stepCount++;
598
599
600
601
602
603
}

CudaIntegrateLangevinStepKernel::~CudaIntegrateLangevinStepKernel() {
}

void CudaIntegrateLangevinStepKernel::initialize(const System& system, const LangevinIntegrator& integrator) {
604
    initializeIntegration(system, data, integrator);
605
606
607
    _gpuContext* gpu = data.gpu;
    gpu->seed = (unsigned long) integrator.getRandomNumberSeed();
    gpuInitializeRandoms(gpu);
608
609
610
    prevStepSize = -1.0;
}

611
void CudaIntegrateLangevinStepKernel::execute(ContextImpl& context, const LangevinIntegrator& integrator) {
612
    _gpuContext* gpu = data.gpu;
613
614
615
    double temperature = integrator.getTemperature();
    double friction = integrator.getFriction();
    double stepSize = integrator.getStepSize();
616
617
618
619
    if (temperature != prevTemp || friction != prevFriction || stepSize != prevStepSize) {
        // Initialize the GPU parameters.
        
        double tau = (friction == 0.0 ? 0.0 : 1.0/friction);
620
        gpuSetLangevinIntegrationParameters(gpu, (float) tau, (float) stepSize, (float) temperature, 0.0f);
621
622
623
624
625
626
        gpuSetConstants(gpu);
        kGenerateRandoms(gpu);
        prevTemp = temperature;
        prevFriction = friction;
        prevStepSize = stepSize;
    }
627
    kLangevinUpdatePart1(gpu);
628
    kApplyFirstShake(gpu);
629
    kApplyFirstSettle(gpu);
630
    kApplyFirstCCMA(gpu);
631
632
    if (data.removeCM)
        if (data.stepCount%data.cmMotionFrequency == 0)
633
            gpu->bCalculateCM = true;
634
    kLangevinUpdatePart2(gpu);
635
    kApplySecondShake(gpu);
636
    kApplySecondSettle(gpu);
637
    kApplySecondCCMA(gpu);
638
    data.time += stepSize;
639
    data.stepCount++;
640
}
641
642
643
644
645

CudaIntegrateBrownianStepKernel::~CudaIntegrateBrownianStepKernel() {
}

void CudaIntegrateBrownianStepKernel::initialize(const System& system, const BrownianIntegrator& integrator) {
646
    initializeIntegration(system, data, integrator);
647
648
649
    _gpuContext* gpu = data.gpu;
    gpu->seed = (unsigned long) integrator.getRandomNumberSeed();
    gpuInitializeRandoms(gpu);
650
651
652
    prevStepSize = -1.0;
}

653
void CudaIntegrateBrownianStepKernel::execute(ContextImpl& context, const BrownianIntegrator& integrator) {
654
655
656
657
658
659
660
661
    _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);
662
        gpuSetBrownianIntegrationParameters(gpu, (float) tau, (float) stepSize, (float) temperature);
663
664
665
666
667
668
669
670
        gpuSetConstants(gpu);
        kGenerateRandoms(gpu);
        prevTemp = temperature;
        prevFriction = friction;
        prevStepSize = stepSize;
    }
    kBrownianUpdatePart1(gpu);
    kApplyFirstShake(gpu);
671
    kApplyFirstSettle(gpu);
672
    kApplyFirstCCMA(gpu);
673
674
    if (data.removeCM)
        if (data.stepCount%data.cmMotionFrequency == 0)
675
676
            gpu->bCalculateCM = true;
    kBrownianUpdatePart2(gpu);
677
    data.time += stepSize;
678
679
680
681
682
683
684
685
686
687
688
    data.stepCount++;
}

CudaIntegrateVariableVerletStepKernel::~CudaIntegrateVariableVerletStepKernel() {
}

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

689
void CudaIntegrateVariableVerletStepKernel::execute(ContextImpl& context, const VariableVerletIntegrator& integrator, double maxTime) {
690
691
692
693
694
695
696
697
698
    _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;
    }
699
    float maxStepSize = (float)(maxTime-data.time);
700
    kSelectVerletStepSize(gpu, maxStepSize);
701
702
703
704
705
706
707
708
709
710
    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;
711
712
    if ((*gpu->psStepSize)[0].y == maxStepSize)
        data.time = maxTime; // Avoid round-off error
713
    data.stepCount++;
714
}
715

716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
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);
        gpuSetLangevinIntegrationParameters(gpu, (float) tau, 0.0f, (float) temperature, errorTol);
        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++;
}

763
764
765
766
CudaApplyAndersenThermostatKernel::~CudaApplyAndersenThermostatKernel() {
}

void CudaApplyAndersenThermostatKernel::initialize(const System& system, const AndersenThermostat& thermostat) {
767
768
769
    _gpuContext* gpu = data.gpu;
    gpu->seed = (unsigned long) thermostat.getRandomNumberSeed();
    gpuInitializeRandoms(gpu);
770
771
772
    prevStepSize = -1.0;
}

773
void CudaApplyAndersenThermostatKernel::execute(ContextImpl& context) {
774
    _gpuContext* gpu = data.gpu;
775
776
    double temperature = context.getParameter(AndersenThermostat::Temperature());
    double frequency = context.getParameter(AndersenThermostat::CollisionFrequency());
777
778
779
780
    double stepSize = context.getIntegrator().getStepSize();
    if (temperature != prevTemp || frequency != prevFrequency || stepSize != prevStepSize) {
        // Initialize the GPU parameters.
        
781
        gpuSetAndersenThermostatParameters(gpu, (float) temperature, frequency);
782
783
784
785
786
787
788
789
        gpuSetConstants(gpu);
        kGenerateRandoms(gpu);
        prevTemp = temperature;
        prevFrequency = frequency;
        prevStepSize = stepSize;
    }
    kCalculateAndersenThermostat(gpu);
}
790

791
void CudaCalcKineticEnergyKernel::initialize(const System& system) {
Peter Eastman's avatar
Peter Eastman committed
792
793
    int numParticles = system.getNumParticles();
    masses.resize(numParticles);
794
    for (int i = 0; i < numParticles; ++i)
Peter Eastman's avatar
Peter Eastman committed
795
        masses[i] = system.getParticleMass(i);
796
797
}

798
double CudaCalcKineticEnergyKernel::execute(ContextImpl& context) {
799
800
801
    // We don't currently have a GPU kernel to do this, so we retrieve the velocities and calculate the energy
    // on the CPU.
    
802
    const Stream& velocities = context.getVelocities();
803
804
805
806
807
808
809
810
    double* v = new double[velocities.getSize()*3];
    velocities.saveToArray(v);
    double energy = 0.0;
    for (size_t i = 0; i < masses.size(); ++i)
        energy += masses[i]*(v[i*3]*v[i*3]+v[i*3+1]*v[i*3+1]+v[i*3+2]*v[i*3+2]);
    delete v;
    return 0.5*energy;
}
811

812
void CudaRemoveCMMotionKernel::initialize(const System& system, const CMMotionRemover& force) {
813
    data.removeCM = true;
814
    data.cmMotionFrequency = force.getFrequency();
815
816
}

817
void CudaRemoveCMMotionKernel::execute(ContextImpl& context) {
818
}