CudaKernels.cpp 41.5 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
#include "openmm/Context.h"
30
#include "openmm/OpenMMException.h"
31
#include "openmm/internal/ContextImpl.h"
32
#include "openmm/internal/NonbondedForceImpl.h"
33
#include "kernels/gputypes.h"
34
#include "kernels/cudaKernels.h"
35
#include "../src/SimTKUtilities/SimTKOpenMMRealType.h"
36
37
#include <cmath>

38
extern "C" int OPENMMCUDA_EXPORT gpuSetConstants( gpuContext gpu );
39
40
41
42

using namespace OpenMM;
using namespace std;

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

void CudaCalcForcesAndEnergyKernel::beginForceComputation(ContextImpl& context) {
47
    _gpuContext* gpu = data.gpu;
48
    if (data.nonbondedMethod != NO_CUTOFF && data.computeForceCount%100 == 0)
49
        gpuReorderAtoms(gpu);
50
    data.computeForceCount++;
51
52
53
54
    if (gpu->bIncludeGBSA || gpu->bIncludeGBVI)
        kClearBornSumAndForces(gpu);
    else
        kClearForces(gpu);
55
56
57
58
}

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

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

78
void CudaCalcForcesAndEnergyKernel::beginEnergyComputation(ContextImpl& context) {
79
    _gpuContext* gpu = data.gpu;
80
81
82
83
    if (data.nonbondedMethod != NO_CUTOFF && data.stepCount%100 == 0)
        gpuReorderAtoms(gpu);
    data.stepCount++;
    kClearEnergy(gpu);
84
85
    if (gpu->bIncludeGBSA || gpu->bIncludeGBVI)
        kClearBornSumAndForces(gpu);
86
87
88
89
}

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

108
void CudaUpdateStateDataKernel::initialize(const System& system) {
109
110
}

111
double CudaUpdateStateDataKernel::getTime(const ContextImpl& context) const {
112
113
114
    return data.time;
}

115
void CudaUpdateStateDataKernel::setTime(ContextImpl& context, double time) {
116
117
118
    data.time = time;
}

119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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]];
139
140
141
        pos.x = (float) p[0];
        pos.y = (float) p[1];
        pos.z = (float) p[2];
142
143
    }
    gpu->psPosq4->Upload();
144
    for (int i = 0; i < (int) gpu->posCellOffsets.size(); i++)
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
        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]];
167
168
169
        vel.x = (float) v[0];
        vel.y = (float) v[1];
        vel.z = (float) v[2];
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
    }
    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);
    }
}

186
187
188
189
190
CudaCalcHarmonicBondForceKernel::~CudaCalcHarmonicBondForceKernel() {
}

void CudaCalcHarmonicBondForceKernel::initialize(const System& system, const HarmonicBondForce& force) {
    data.hasBonds = true;
191
    numBonds = force.getNumBonds();
Peter Eastman's avatar
Peter Eastman committed
192
193
    vector<int> particle1(numBonds);
    vector<int> particle2(numBonds);
194
195
196
197
    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
198
        force.getBondParameters(i, particle1[i], particle2[i], lengthValue, kValue);
199
200
201
        length[i] = (float) lengthValue;
        k[i] = (float) kValue;
    }
Peter Eastman's avatar
Peter Eastman committed
202
    gpuSetBondParameters(data.gpu, particle1, particle2, length, k);
203
204
}

205
void CudaCalcHarmonicBondForceKernel::executeForces(ContextImpl& context) {
206
207
}

208
double CudaCalcHarmonicBondForceKernel::executeEnergy(ContextImpl& context) {
209
210
211
    return 0.0;
}

212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
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
233
        SetCustomBondGlobalParams(globalParamValues);
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
}

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
256
        SetCustomBondGlobalParams(globalParamValues);
257
258
}

259
260
261
262
263
CudaCalcHarmonicAngleForceKernel::~CudaCalcHarmonicAngleForceKernel() {
}

void CudaCalcHarmonicAngleForceKernel::initialize(const System& system, const HarmonicAngleForce& force) {
    data.hasAngles = true;
264
    numAngles = force.getNumAngles();
265
    const float RadiansToDegrees = (float) (180.0/3.14159265);
Peter Eastman's avatar
Peter Eastman committed
266
267
268
    vector<int> particle1(numAngles);
    vector<int> particle2(numAngles);
    vector<int> particle3(numAngles);
269
270
271
272
    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
273
        force.getAngleParameters(i, particle1[i], particle2[i], particle3[i], angleValue, kValue);
274
275
        angle[i] = (float) (angleValue*RadiansToDegrees);
        k[i] = (float) kValue;
276
    }
Peter Eastman's avatar
Peter Eastman committed
277
    gpuSetBondAngleParameters(data.gpu, particle1, particle2, particle3, angle, k);
278
}
279

280
void CudaCalcHarmonicAngleForceKernel::executeForces(ContextImpl& context) {
281
282
}

283
double CudaCalcHarmonicAngleForceKernel::executeEnergy(ContextImpl& context) {
284
285
286
    return 0.0;
}

287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
CudaCalcCustomAngleForceKernel::~CudaCalcCustomAngleForceKernel() {
}

void CudaCalcCustomAngleForceKernel::initialize(const System& system, const CustomAngleForce& force) {
    numAngles = force.getNumAngles();
    vector<int> particle1(numAngles);
    vector<int> particle2(numAngles);
    vector<int> particle3(numAngles);
    vector<vector<double> > params(numAngles);
    for (int i = 0; i < numAngles; i++)
        force.getAngleParameters(i, particle1[i], particle2[i], particle3[i], params[i]);
    vector<string> paramNames;
    for (int i = 0; i < force.getNumPerAngleParameters(); i++)
        paramNames.push_back(force.getPerAngleParameterName(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);
    }
    gpuSetCustomAngleParameters(data.gpu, particle1, particle2, particle3, params, force.getEnergyFunction(), paramNames, globalParamNames);
    if (globalParamValues.size() > 0)
        SetCustomAngleGlobalParams(globalParamValues);
}

void CudaCalcCustomAngleForceKernel::executeForces(ContextImpl& context) {
    updateGlobalParams(context);
    kCalculateCustomAngleForces(data.gpu);
}

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

void CudaCalcCustomAngleForceKernel::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)
        SetCustomAngleGlobalParams(globalParamValues);
}

335
336
337
338
339
340
CudaCalcPeriodicTorsionForceKernel::~CudaCalcPeriodicTorsionForceKernel() {
}

void CudaCalcPeriodicTorsionForceKernel::initialize(const System& system, const PeriodicTorsionForce& force) {
    data.hasPeriodicTorsions = true;
    numTorsions = force.getNumTorsions();
341
    const float RadiansToDegrees = (float)(180.0/3.14159265);
Peter Eastman's avatar
Peter Eastman committed
342
343
344
345
    vector<int> particle1(numTorsions);
    vector<int> particle2(numTorsions);
    vector<int> particle3(numTorsions);
    vector<int> particle4(numTorsions);
346
347
348
349
350
    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
351
        force.getTorsionParameters(i, particle1[i], particle2[i], particle3[i], particle4[i], periodicity[i], phaseValue, kValue);
352
353
        k[i] = (float) kValue;
        phase[i] = (float) (phaseValue*RadiansToDegrees);
354
    }
Peter Eastman's avatar
Peter Eastman committed
355
    gpuSetDihedralParameters(data.gpu, particle1, particle2, particle3, particle4, k, phase, periodicity);
356
357
}

358
void CudaCalcPeriodicTorsionForceKernel::executeForces(ContextImpl& context) {
359
360
}

361
double CudaCalcPeriodicTorsionForceKernel::executeEnergy(ContextImpl& context) {
362
363
364
365
366
367
368
369
370
    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
371
372
373
374
    vector<int> particle1(numTorsions);
    vector<int> particle2(numTorsions);
    vector<int> particle3(numTorsions);
    vector<int> particle4(numTorsions);
375
376
377
378
379
380
381
382
    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
383
        force.getTorsionParameters(i, particle1[i], particle2[i], particle3[i], particle4[i], c[0], c[1], c[2], c[3], c[4], c[5]);
384
385
386
387
388
389
        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];
390
    }
Peter Eastman's avatar
Peter Eastman committed
391
    gpuSetRbDihedralParameters(data.gpu, particle1, particle2, particle3, particle4, c0, c1, c2, c3, c4, c5);
392
393
}

394
void CudaCalcRBTorsionForceKernel::executeForces(ContextImpl& context) {
395
396
}

397
double CudaCalcRBTorsionForceKernel::executeEnergy(ContextImpl& context) {
398
399
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
CudaCalcCustomTorsionForceKernel::~CudaCalcCustomTorsionForceKernel() {
}

void CudaCalcCustomTorsionForceKernel::initialize(const System& system, const CustomTorsionForce& force) {
    numTorsions = force.getNumTorsions();
    vector<int> particle1(numTorsions);
    vector<int> particle2(numTorsions);
    vector<int> particle3(numTorsions);
    vector<int> particle4(numTorsions);
    vector<vector<double> > params(numTorsions);
    for (int i = 0; i < numTorsions; i++)
        force.getTorsionParameters(i, particle1[i], particle2[i], particle3[i], particle4[i], params[i]);
    vector<string> paramNames;
    for (int i = 0; i < force.getNumPerTorsionParameters(); i++)
        paramNames.push_back(force.getPerTorsionParameterName(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);
    }
    gpuSetCustomTorsionParameters(data.gpu, particle1, particle2, particle3, particle4, params, force.getEnergyFunction(), paramNames, globalParamNames);
    if (globalParamValues.size() > 0)
        SetCustomTorsionGlobalParams(globalParamValues);
}

void CudaCalcCustomTorsionForceKernel::executeForces(ContextImpl& context) {
    updateGlobalParams(context);
    kCalculateCustomTorsionForces(data.gpu);
}

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

void CudaCalcCustomTorsionForceKernel::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)
        SetCustomTorsionGlobalParams(globalParamValues);
}

450
451
452
CudaCalcNonbondedForceKernel::~CudaCalcNonbondedForceKernel() {
}

453
void CudaCalcNonbondedForceKernel::initialize(const System& system, const NonbondedForce& force) {
454
    data.hasNonbonded = true;
Peter Eastman's avatar
Peter Eastman committed
455
    numParticles = force.getNumParticles();
456
    _gpuContext* gpu = data.gpu;
457
458
459
460

    // Identify which exceptions are 1-4 interactions.

    vector<pair<int, int> > exclusions;
461
    vector<int> exceptions;
462
463
464
465
466
467
    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)
468
            exceptions.push_back(i);
469
470
    }

471
472
    // Initialize nonbonded interactions.
    
473
    {
Peter Eastman's avatar
Peter Eastman committed
474
475
476
477
        vector<int> particle(numParticles);
        vector<float> c6(numParticles);
        vector<float> c12(numParticles);
        vector<float> q(numParticles);
478
        vector<char> symbol;
Peter Eastman's avatar
Peter Eastman committed
479
480
        vector<vector<int> > exclusionList(numParticles);
        for (int i = 0; i < numParticles; i++) {
481
            double charge, radius, depth;
Peter Eastman's avatar
Peter Eastman committed
482
483
            force.getParticleParameters(i, charge, radius, depth);
            particle[i] = i;
484
485
486
            q[i] = (float) charge;
            c6[i] = (float) (4*depth*pow(radius, 6.0));
            c12[i] = (float) (4*depth*pow(radius, 12.0));
487
488
            exclusionList[i].push_back(i);
        }
489
        for (int i = 0; i < (int)exclusions.size(); i++) {
490
491
492
            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
493
        Vec3 boxVectors[3];
494
        system.getPeriodicBoxVectors(boxVectors[0], boxVectors[1], boxVectors[2]);
Peter Eastman's avatar
Peter Eastman committed
495
        gpuSetPeriodicBoxSize(gpu, (float)boxVectors[0][0], (float)boxVectors[1][1], (float)boxVectors[2][2]);
496
497
        CudaNonbondedMethod method = NO_CUTOFF;
        if (force.getNonbondedMethod() != NonbondedForce::NoCutoff) {
498
            gpuSetNonbondedCutoff(gpu, (float) force.getCutoffDistance(), (float) force.getReactionFieldDielectric());
499
500
501
502
503
            method = CUTOFF;
        }
        if (force.getNonbondedMethod() == NonbondedForce::CutoffPeriodic) {
            method = PERIODIC;
        }
504
505
        if (force.getNonbondedMethod() == NonbondedForce::Ewald || force.getNonbondedMethod() == NonbondedForce::PME) {
            if (force.getNonbondedMethod() == NonbondedForce::Ewald) {
506
507
508
                double alpha;
                int kmaxx, kmaxy, kmaxz;
                NonbondedForceImpl::calcEwaldParameters(system, force, alpha, kmaxx, kmaxy, kmaxz);
509
510
511
512
                gpuSetEwaldParameters(gpu, (float) alpha, kmaxx, kmaxy, kmaxz);
                method = EWALD;
            }
            else {
513
514
515
                double alpha;
                int gridSizeX, gridSizeY, gridSizeZ;
                NonbondedForceImpl::calcPMEParameters(system, force, alpha, gridSizeX, gridSizeY, gridSizeZ);
Peter Eastman's avatar
Peter Eastman committed
516
                gpuSetPMEParameters(gpu, (float) alpha, gridSizeX, gridSizeY, gridSizeZ);
517
518
                method = PARTICLE_MESH_EWALD;
            }
519
        }
520
        data.nonbondedMethod = method;
521
        gpuSetCoulombParameters(gpu, (float) ONE_4PI_EPS0, particle, c6, c12, q, symbol, exclusionList, method);
522
523
524
525

        // Compute the Ewald self energy.

        data.ewaldSelfEnergy = 0.0;
526
527
528
529
530
        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];
        }
531
532
533
534
    }

    // Initialize 1-4 nonbonded interactions.
    
535
    {
536
537
538
539
540
541
542
543
        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++) {
544
            double charge, sig, eps;
545
            force.getExceptionParameters(exceptions[i], particle1[i], particle2[i], charge, sig, eps);
546
547
            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
548
549
            q1[i] = (float) charge;
            q2[i] = 1.0f;
550
        }
551
        gpuSetLJ14Parameters(gpu, (float) ONE_4PI_EPS0, 1.0f, particle1, particle2, c6, c12, q1, q2);
552
553
554
    }
}

555
void CudaCalcNonbondedForceKernel::executeForces(ContextImpl& context) {
556
557
}

558
double CudaCalcNonbondedForceKernel::executeEnergy(ContextImpl& context) {
559
    return 0.0;
560
561
}

562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
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);
    }
580
581
582
583
584
    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);
585
    }
586
587
588
    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]);
589
590
591
592
593
594
595
596
    CudaNonbondedMethod method = NO_CUTOFF;
    if (force.getNonbondedMethod() != CustomNonbondedForce::NoCutoff)
        method = CUTOFF;
    if (force.getNonbondedMethod() == CustomNonbondedForce::CutoffPeriodic) {
        method = PERIODIC;
    }
    data.customNonbondedMethod = method;

597
598
599
600
601
602
603
604
605
606
607
    // 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);
    }

608
609
610
    // Record information for the expressions.

    vector<string> paramNames;
611
612
    for (int i = 0; i < force.getNumPerParticleParameters(); i++)
        paramNames.push_back(force.getPerParticleParameterName(i));
613
614
615
616
    globalParamNames.resize(force.getNumGlobalParameters());
    globalParamValues.resize(force.getNumGlobalParameters());
    for (int i = 0; i < force.getNumGlobalParameters(); i++) {
        globalParamNames[i] = force.getGlobalParameterName(i);
617
        globalParamValues[i] = (float) force.getGlobalParameterDefaultValue(i);
618
    }
619
    gpuSetCustomNonbondedParameters(gpu, parameters, exclusionList, method, (float) force.getCutoffDistance(), force.getEnergyFunction(), paramNames, globalParamNames);
620
    if (globalParamValues.size() > 0)
Peter Eastman's avatar
Peter Eastman committed
621
        SetCustomNonbondedGlobalParams(globalParamValues);
622
623
624
}

void CudaCalcCustomNonbondedForceKernel::executeForces(ContextImpl& context) {
625
    updateGlobalParams(context);
626
627
628
}

double CudaCalcCustomNonbondedForceKernel::executeEnergy(ContextImpl& context) {
629
    updateGlobalParams(context);
630
631
632
    return 0.0;
}

633
634
void CudaCalcCustomNonbondedForceKernel::updateGlobalParams(ContextImpl& context) {
    bool changed = false;
635
    for (int i = 0; i < (int) globalParamNames.size(); i++) {
636
637
638
639
640
641
        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
642
        SetCustomNonbondedGlobalParams(globalParamValues);
643
644
}

645
CudaCalcGBSAOBCForceKernel::~CudaCalcGBSAOBCForceKernel() {
646
647
}

648
void CudaCalcGBSAOBCForceKernel::initialize(const System& system, const GBSAOBCForce& force) {
649

Peter Eastman's avatar
Peter Eastman committed
650
    int numParticles = system.getNumParticles();
651
    _gpuContext* gpu = data.gpu;
Peter Eastman's avatar
Peter Eastman committed
652
653
    vector<float> radius(numParticles);
    vector<float> scale(numParticles);
654
    vector<float> charge(numParticles);
Peter Eastman's avatar
Peter Eastman committed
655
    for (int i = 0; i < numParticles; i++) {
656
657
        double particleCharge, particleRadius, scalingFactor;
        force.getParticleParameters(i, particleCharge, particleRadius, scalingFactor);
Peter Eastman's avatar
Peter Eastman committed
658
        radius[i] = (float) particleRadius;
659
        scale[i] = (float) scalingFactor;
660
        charge[i] = (float) particleCharge;
661
    }
662
    gpuSetObcParameters(gpu, (float) force.getSoluteDielectric(), (float) force.getSolventDielectric(), radius, scale, charge);
663
664
}

665
void CudaCalcGBSAOBCForceKernel::executeForces(ContextImpl& context) {
666
667
}

Mark Friedrichs's avatar
Mark Friedrichs committed
668
669
670
671
672
673
674
675
676
677
678
679
680
681
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++) {
682
        double charge, particleRadius, gamma;
Mark Friedrichs's avatar
Mark Friedrichs committed
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
        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;
}

700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
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
720
        SetCustomExternalGlobalParams(globalParamValues);
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
}

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
743
        SetCustomExternalGlobalParams(globalParamValues);
744
745
}

746
void OPENMMCUDA_EXPORT OpenMM::cudaOpenMMInitializeIntegration(const System& system, CudaPlatform::PlatformData& data, const Integrator& integrator) {
747
748
749
750
751
752
753
754
755
756
757
758
759
760

    // 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) {
761
762
        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>());
763
764
        if (gpu->bIncludeGBSA || gpu->bIncludeGBVI)
            throw OpenMMException("CudaPlatform requires GBSAOBCForce and GBVIForce to be used with a NonbondedForce");
765
    }
766
767
768
    
    // Set masses.
    
Peter Eastman's avatar
Peter Eastman committed
769
770
771
772
    int numParticles = system.getNumParticles();
    vector<float> mass(numParticles);
    for (int i = 0; i < numParticles; i++)
        mass[i] = (float) system.getParticleMass(i);
773
774
775
776
    gpuSetMass(gpu, mass);
    
    // Set constraints.
    
777
    int numConstraints = system.getNumConstraints();
Peter Eastman's avatar
Peter Eastman committed
778
779
    vector<int> particle1(numConstraints);
    vector<int> particle2(numConstraints);
780
781
782
783
    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
784
        int particle1Index, particle2Index;
785
        double constraintDistance;
Peter Eastman's avatar
Peter Eastman committed
786
787
788
        system.getConstraintParameters(i, particle1Index, particle2Index, constraintDistance);
        particle1[i] = particle1Index;
        particle2[i] = particle2Index;
789
        distance[i] = (float) constraintDistance;
Peter Eastman's avatar
Peter Eastman committed
790
791
        invMass1[i] = 1.0f/mass[particle1Index];
        invMass2[i] = 1.0f/mass[particle2Index];
792
    }
793
    gpuSetConstraintParameters(gpu, particle1, particle2, distance, invMass1, invMass2, (float)integrator.getConstraintTolerance());
794
795
    
    // Finish initialization.
796

797
798
799
    gpuBuildThreadBlockWorkList(gpu);
    gpuBuildExclusionList(gpu);
    gpuBuildOutputBuffers(gpu);
800
    gpuSetConstants(gpu);
801
802
803
804
    if (gpu->bIncludeGBSA || gpu->bIncludeGBVI)
        kClearBornSumAndForces(gpu);
    else
        kClearForces(gpu);
805
    cudaThreadSynchronize();
806
807
}

808
double CudaCalcGBSAOBCForceKernel::executeEnergy(ContextImpl& context) {
809
	return 0.0;
810
811
812
813
814
815
}

CudaIntegrateVerletStepKernel::~CudaIntegrateVerletStepKernel() {
}

void CudaIntegrateVerletStepKernel::initialize(const System& system, const VerletIntegrator& integrator) {
816
    cudaOpenMMInitializeIntegration(system, data, integrator);
817
818
819
    prevStepSize = -1.0;
}

820
void CudaIntegrateVerletStepKernel::execute(ContextImpl& context, const VerletIntegrator& integrator) {
821
822
823
824
825
    _gpuContext* gpu = data.gpu;
    double stepSize = integrator.getStepSize();
    if (stepSize != prevStepSize) {
        // Initialize the GPU parameters.
        
826
        gpuSetVerletIntegrationParameters(gpu, (float) stepSize, 0.0f);
827
828
829
830
831
        gpuSetConstants(gpu);
        prevStepSize = stepSize;
    }
    kVerletUpdatePart1(gpu);
    kApplyFirstShake(gpu);
832
    kApplyFirstSettle(gpu);
833
    kApplyFirstCCMA(gpu);
834
835
    if (data.removeCM)
        if (data.stepCount%data.cmMotionFrequency == 0)
836
837
            gpu->bCalculateCM = true;
    kVerletUpdatePart2(gpu);
838
    data.time += stepSize;
839
    data.stepCount++;
840
841
842
843
844
845
}

CudaIntegrateLangevinStepKernel::~CudaIntegrateLangevinStepKernel() {
}

void CudaIntegrateLangevinStepKernel::initialize(const System& system, const LangevinIntegrator& integrator) {
846
    cudaOpenMMInitializeIntegration(system, data, integrator);
847
848
849
    _gpuContext* gpu = data.gpu;
    gpu->seed = (unsigned long) integrator.getRandomNumberSeed();
    gpuInitializeRandoms(gpu);
850
851
    prevTemp = -1.0;
    prevFriction = -1.0;
852
853
854
    prevStepSize = -1.0;
}

855
void CudaIntegrateLangevinStepKernel::execute(ContextImpl& context, const LangevinIntegrator& integrator) {
856
    _gpuContext* gpu = data.gpu;
857
858
859
    double temperature = integrator.getTemperature();
    double friction = integrator.getFriction();
    double stepSize = integrator.getStepSize();
860
861
    if (temperature != prevTemp || friction != prevFriction || stepSize != prevStepSize) {
        // Initialize the GPU parameters.
862
        
863
        double tau = (friction == 0.0 ? 0.0 : 1.0/friction);
864
        gpuSetLangevinIntegrationParameters(gpu, (float) tau, (float) stepSize, (float) temperature, 0.0f);
865
866
867
868
869
870
        gpuSetConstants(gpu);
        kGenerateRandoms(gpu);
        prevTemp = temperature;
        prevFriction = friction;
        prevStepSize = stepSize;
    }
871
    kLangevinUpdatePart1(gpu);
872
    kApplyFirstShake(gpu);
873
    kApplyFirstSettle(gpu);
874
    kApplyFirstCCMA(gpu);
875
876
    if (data.removeCM)
        if (data.stepCount%data.cmMotionFrequency == 0)
877
            gpu->bCalculateCM = true;
878
    kLangevinUpdatePart2(gpu);
879
    kApplySecondShake(gpu);
880
    kApplySecondSettle(gpu);
881
    kApplySecondCCMA(gpu);
882
    data.time += stepSize;
883
    data.stepCount++;
884
}
885
886
887
888
889

CudaIntegrateBrownianStepKernel::~CudaIntegrateBrownianStepKernel() {
}

void CudaIntegrateBrownianStepKernel::initialize(const System& system, const BrownianIntegrator& integrator) {
890
    cudaOpenMMInitializeIntegration(system, data, integrator);
891
892
893
    _gpuContext* gpu = data.gpu;
    gpu->seed = (unsigned long) integrator.getRandomNumberSeed();
    gpuInitializeRandoms(gpu);
894
895
    prevTemp = -1.0;
    prevFriction = -1.0;
896
897
898
    prevStepSize = -1.0;
}

899
void CudaIntegrateBrownianStepKernel::execute(ContextImpl& context, const BrownianIntegrator& integrator) {
900
901
902
903
904
905
906
907
    _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);
908
        gpuSetBrownianIntegrationParameters(gpu, (float) tau, (float) stepSize, (float) temperature);
909
910
911
912
913
914
915
916
        gpuSetConstants(gpu);
        kGenerateRandoms(gpu);
        prevTemp = temperature;
        prevFriction = friction;
        prevStepSize = stepSize;
    }
    kBrownianUpdatePart1(gpu);
    kApplyFirstShake(gpu);
917
    kApplyFirstSettle(gpu);
918
    kApplyFirstCCMA(gpu);
919
920
    if (data.removeCM)
        if (data.stepCount%data.cmMotionFrequency == 0)
921
922
            gpu->bCalculateCM = true;
    kBrownianUpdatePart2(gpu);
923
    data.time += stepSize;
924
925
926
927
928
929
930
    data.stepCount++;
}

CudaIntegrateVariableVerletStepKernel::~CudaIntegrateVariableVerletStepKernel() {
}

void CudaIntegrateVariableVerletStepKernel::initialize(const System& system, const VariableVerletIntegrator& integrator) {
931
    cudaOpenMMInitializeIntegration(system, data, integrator);
932
933
934
    prevErrorTol = -1.0;
}

935
void CudaIntegrateVariableVerletStepKernel::execute(ContextImpl& context, const VariableVerletIntegrator& integrator, double maxTime) {
936
937
938
939
940
941
942
943
944
    _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;
    }
945
    float maxStepSize = (float)(maxTime-data.time);
946
    kSelectVerletStepSize(gpu, maxStepSize);
947
948
949
950
951
952
953
954
955
956
    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;
957
958
    if ((*gpu->psStepSize)[0].y == maxStepSize)
        data.time = maxTime; // Avoid round-off error
959
    data.stepCount++;
960
}
961

962
963
964
965
CudaIntegrateVariableLangevinStepKernel::~CudaIntegrateVariableLangevinStepKernel() {
}

void CudaIntegrateVariableLangevinStepKernel::initialize(const System& system, const VariableLangevinIntegrator& integrator) {
966
    cudaOpenMMInitializeIntegration(system, data, integrator);
967
968
969
    _gpuContext* gpu = data.gpu;
    gpu->seed = (unsigned long) integrator.getRandomNumberSeed();
    gpuInitializeRandoms(gpu);
970
971
    prevTemp = -1.0;
    prevFriction = -1.0;
972
973
974
975
976
977
978
979
980
981
982
983
    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);
984
        gpuSetLangevinIntegrationParameters(gpu, (float) tau, 0.0f, (float) temperature, (float) errorTol);
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
        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++;
}

1011
1012
1013
1014
CudaApplyAndersenThermostatKernel::~CudaApplyAndersenThermostatKernel() {
}

void CudaApplyAndersenThermostatKernel::initialize(const System& system, const AndersenThermostat& thermostat) {
1015
1016
1017
    _gpuContext* gpu = data.gpu;
    gpu->seed = (unsigned long) thermostat.getRandomNumberSeed();
    gpuInitializeRandoms(gpu);
1018
1019
    prevTemp = -1.0;
    prevFrequency = -1.0;
1020
1021
1022
    prevStepSize = -1.0;
}

1023
void CudaApplyAndersenThermostatKernel::execute(ContextImpl& context) {
1024
    _gpuContext* gpu = data.gpu;
1025
1026
    double temperature = context.getParameter(AndersenThermostat::Temperature());
    double frequency = context.getParameter(AndersenThermostat::CollisionFrequency());
1027
1028
1029
1030
    double stepSize = context.getIntegrator().getStepSize();
    if (temperature != prevTemp || frequency != prevFrequency || stepSize != prevStepSize) {
        // Initialize the GPU parameters.
        
1031
        gpuSetAndersenThermostatParameters(gpu, (float) temperature, (float) frequency);
1032
1033
1034
1035
1036
1037
1038
1039
        gpuSetConstants(gpu);
        kGenerateRandoms(gpu);
        prevTemp = temperature;
        prevFrequency = frequency;
        prevStepSize = stepSize;
    }
    kCalculateAndersenThermostat(gpu);
}
1040

1041
void CudaCalcKineticEnergyKernel::initialize(const System& system) {
Peter Eastman's avatar
Peter Eastman committed
1042
1043
    int numParticles = system.getNumParticles();
    masses.resize(numParticles);
1044
    for (int i = 0; i < numParticles; ++i)
Peter Eastman's avatar
Peter Eastman committed
1045
        masses[i] = system.getParticleMass(i);
1046
1047
}

1048
double CudaCalcKineticEnergyKernel::execute(ContextImpl& context) {
1049
1050
1051
    // We don't currently have a GPU kernel to do this, so we retrieve the velocities and calculate the energy
    // on the CPU.
    
1052
1053
    _gpuContext* gpu = data.gpu;
    gpu->psVelm4->Download();
1054
    double energy = 0.0;
1055
1056
1057
1058
    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);
    }
1059
1060
    return 0.5*energy;
}
1061

1062
void CudaRemoveCMMotionKernel::initialize(const System& system, const CMMotionRemover& force) {
1063
    data.removeCM = true;
1064
    data.cmMotionFrequency = force.getFrequency();
1065
1066
}

1067
void CudaRemoveCMMotionKernel::execute(ContextImpl& context) {
1068
}