"vscode:/vscode.git/clone" did not exist on "830124e15c7301f3b1db5de9a7ec0973f6cbec8f"
ReferenceKernels.cpp 27.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/* -------------------------------------------------------------------------- *
 *                                   OpenMM                                   *
 * -------------------------------------------------------------------------- *
 * This is part of the OpenMM molecular simulation toolkit originating from   *
 * Simbios, the NIH National Center for Physics-Based Simulation of           *
 * Biological Structures at Stanford, funded under the NIH Roadmap for        *
 * Medical Research, grant U54 GM072970. See https://simtk.org.               *
 *                                                                            *
 * Portions copyright (c) 2008 Stanford University and the Authors.           *
 * Authors: Peter Eastman                                                     *
 * Contributors:                                                              *
 *                                                                            *
 * Permission is hereby granted, free of charge, to any person obtaining a    *
 * copy of this software and associated documentation files (the "Software"), *
 * to deal in the Software without restriction, including without limitation  *
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
 * and/or sell copies of the Software, and to permit persons to whom the      *
 * Software is furnished to do so, subject to the following conditions:       *
 *                                                                            *
 * The above copyright notice and this permission notice shall be included in *
 * all copies or substantial portions of the Software.                        *
 *                                                                            *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
 * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,    *
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR      *
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  *
 * USE OR OTHER DEALINGS IN THE SOFTWARE.                                     *
 * -------------------------------------------------------------------------- */

32
33
34
#include "System.h"


35
#include "ReferenceKernels.h"
36
#include "ReferenceFloatStreamImpl.h"
37
#include "gbsa/CpuObc.h"
38
#include "SimTKReference/ReferenceAndersenThermostat.h"
39
40
#include "SimTKReference/ReferenceAngleBondIxn.h"
#include "SimTKReference/ReferenceBondForce.h"
41
#include "SimTKReference/ReferenceBrownianDynamics.h"
42
43
44
45
46
#include "SimTKReference/ReferenceHarmonicBondIxn.h"
#include "SimTKReference/ReferenceLJCoulomb14.h"
#include "SimTKReference/ReferenceLJCoulombIxn.h"
#include "SimTKReference/ReferenceProperDihedralBond.h"
#include "SimTKReference/ReferenceRbDihedralBond.h"
47
48
#include "SimTKReference/ReferenceStochasticDynamics.h"
#include "SimTKReference/ReferenceShakeAlgorithm.h"
49
#include "SimTKReference/ReferenceVerletDynamics.h"
50
51
52
53
#include "CMMotionRemover.h"
#include "System.h"
#include "internal/OpenMMContextImpl.h"
#include "Integrator.h"
54
#include <cmath>
55
#include <limits>
56
57
58
59

using namespace OpenMM;
using namespace std;

60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
int** allocateIntArray(int length, int width) {
    int** array = new int*[length];
    for (int i = 0; i < length; ++i)
        array[i] = new int[width];
    return array;
}

RealOpenMM** allocateRealArray(int length, int width) {
    RealOpenMM** array = new RealOpenMM*[length];
    for (int i = 0; i < length; ++i)
        array[i] = new RealOpenMM[width];
    return array;
}

int** copyToArray(const vector<vector<int> > vec) {
    if (vec.size() == 0)
        return new int*[0];
    int** array = allocateIntArray(vec.size(), vec[0].size());
78
79
    for (size_t i = 0; i < vec.size(); ++i)
        for (size_t j = 0; j < vec[i].size(); ++j)
80
81
82
83
84
85
86
87
            array[i][j] = vec[i][j];
    return array;
}

RealOpenMM** copyToArray(const vector<vector<double> > vec) {
    if (vec.size() == 0)
        return new RealOpenMM*[0];
    RealOpenMM** array = allocateRealArray(vec.size(), vec[0].size());
88
89
90
    for (size_t i = 0; i < vec.size(); ++i)
        for (size_t j = 0; j < vec[i].size(); ++j)
            array[i][j] = static_cast<RealOpenMM>(vec[i][j]);
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
    return array;
}

void disposeIntArray(int** array, int size) {
    if (array) {
        for (int i = 0; i < size; ++i)
            delete[] array[i];
        delete[] array;
    }
}

void disposeRealArray(RealOpenMM** array, int size) {
    if (array) {
        for (int i = 0; i < size; ++i)
            delete[] array[i];
        delete[] array;
    }
}

110
ReferenceCalcStandardMMForceFieldKernel::~ReferenceCalcStandardMMForceFieldKernel() {
111
112
113
114
115
116
117
118
    disposeIntArray(bondIndexArray, numBonds);
    disposeRealArray(bondParamArray, numBonds);
    disposeIntArray(angleIndexArray, numAngles);
    disposeRealArray(angleParamArray, numAngles);
    disposeIntArray(periodicTorsionIndexArray, numPeriodicTorsions);
    disposeRealArray(periodicTorsionParamArray, numPeriodicTorsions);
    disposeIntArray(rbTorsionIndexArray, numRBTorsions);
    disposeRealArray(rbTorsionParamArray, numRBTorsions);
119
120
121
122
    disposeRealArray(atomParamArray, numAtoms);
    disposeIntArray(exclusionArray, numAtoms);
    disposeIntArray(bonded14IndexArray, num14);
    disposeRealArray(bonded14ParamArray, num14);
123
124
    if (neighborList != NULL)
        delete neighborList;
125
126
}

127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
void ReferenceCalcStandardMMForceFieldKernel::initialize(const System& system, const StandardMMForceField& force, const std::vector<std::set<int> >& exclusions) {
    numAtoms = force.getNumAtoms();
    numBonds = force.getNumBonds();
    numAngles = force.getNumAngles();
    numPeriodicTorsions = force.getNumPeriodicTorsions();
    numRBTorsions = force.getNumRBTorsions();
    num14 = force.getNumNonbonded14();
    bondIndexArray = allocateIntArray(numBonds, 2);
    bondParamArray = allocateRealArray(numBonds, 2);
    angleIndexArray = allocateIntArray(numAngles, 3);
    angleParamArray = allocateRealArray(numAngles, 2);
    periodicTorsionIndexArray = allocateIntArray(numPeriodicTorsions, 4);
    periodicTorsionParamArray = allocateRealArray(numPeriodicTorsions, 3);
    rbTorsionIndexArray = allocateIntArray(numRBTorsions, 4);
    rbTorsionParamArray = allocateRealArray(numRBTorsions, 6);
    bonded14IndexArray = allocateIntArray(num14, 2);
    bonded14ParamArray = allocateRealArray(num14, 3);
144
    atomParamArray = allocateRealArray(numAtoms, 3);
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
    for (int i = 0; i < force.getNumBonds(); ++i) {
        int atom1, atom2;
        double length, k;
        force.getBondParameters(i, atom1, atom2, length, k);
        bondIndexArray[i][0] = atom1;
        bondIndexArray[i][1] = atom2;
        bondParamArray[i][0] = length;
        bondParamArray[i][1] = k;
    }
    for (int i = 0; i < force.getNumAngles(); ++i) {
        int atom1, atom2, atom3;
        double angle, k;
        force.getAngleParameters(i, atom1, atom2, atom3, angle, k);
        angleIndexArray[i][0] = atom1;
        angleIndexArray[i][1] = atom2;
        angleIndexArray[i][2] = atom3;
        angleParamArray[i][0] = angle;
        angleParamArray[i][1] = k;
    }
    for (int i = 0; i < force.getNumPeriodicTorsions(); ++i) {
        int atom1, atom2, atom3, atom4, periodicity;
        double phase, k;
        force.getPeriodicTorsionParameters(i, atom1, atom2, atom3, atom4, periodicity, phase, k);
        periodicTorsionIndexArray[i][0] = atom1;
        periodicTorsionIndexArray[i][1] = atom2;
        periodicTorsionIndexArray[i][2] = atom3;
        periodicTorsionIndexArray[i][3] = atom4;
        periodicTorsionParamArray[i][0] = k;
        periodicTorsionParamArray[i][1] = phase;
        periodicTorsionParamArray[i][2] = periodicity;
    }
    for (int i = 0; i < force.getNumRBTorsions(); ++i) {
        int atom1, atom2, atom3, atom4;
        double c0, c1, c2, c3, c4, c5;
        force.getRBTorsionParameters(i, atom1, atom2, atom3, atom4, c0, c1, c2, c3, c4, c5);
        rbTorsionIndexArray[i][0] = atom1;
        rbTorsionIndexArray[i][1] = atom2;
        rbTorsionIndexArray[i][2] = atom3;
        rbTorsionIndexArray[i][3] = atom4;
        rbTorsionParamArray[i][0] = c0;
        rbTorsionParamArray[i][1] = c1;
        rbTorsionParamArray[i][2] = c2;
        rbTorsionParamArray[i][3] = c3;
        rbTorsionParamArray[i][4] = c4;
        rbTorsionParamArray[i][5] = c5;
    }
191
    RealOpenMM sqrtEps = static_cast<RealOpenMM>( std::sqrt(138.935485) );
192
    for (int i = 0; i < numAtoms; ++i) {
193
194
195
196
197
        double charge, radius, depth;
        force.getAtomParameters(i, charge, radius, depth);
        atomParamArray[i][0] = static_cast<RealOpenMM>(0.5*radius);
        atomParamArray[i][1] = static_cast<RealOpenMM>(2.0*sqrt(depth));
        atomParamArray[i][2] = static_cast<RealOpenMM>(charge*sqrtEps);
198
    }
199
    this->exclusions = exclusions;
200
201
202
203
204
205
206
207
208
    exclusionArray = new int*[numAtoms];
    for (int i = 0; i < numAtoms; ++i) {
        exclusionArray[i] = new int[exclusions[i].size()+1];
        exclusionArray[i][0] = exclusions[i].size();
        int index = 0;
        for (set<int>::const_iterator iter = exclusions[i].begin(); iter != exclusions[i].end(); ++iter)
            exclusionArray[i][++index] = *iter;
    }
    for (int i = 0; i < num14; ++i) {
209
210
211
212
213
214
215
216
        int atom1, atom2;
        double charge, radius, depth;
        force.getNonbonded14Parameters(i, atom1, atom2, charge, radius, depth);
        bonded14IndexArray[i][0] = atom1;
        bonded14IndexArray[i][1] = atom2;
        bonded14ParamArray[i][0] = static_cast<RealOpenMM>(radius);
        bonded14ParamArray[i][1] = static_cast<RealOpenMM>(4.0*depth);
        bonded14ParamArray[i][2] = static_cast<RealOpenMM>(charge*sqrtEps*sqrtEps);
217
    }
218
219
    nonbondedMethod = CalcStandardMMForceFieldKernel::NonbondedMethod(force.getNonbondedMethod());
    nonbondedCutoff = (RealOpenMM) force.getCutoffDistance();
220
221
222
223
224
    Vec3 boxVectors[3];
    force.getPeriodicBoxVectors(boxVectors[0], boxVectors[1], boxVectors[2]);
    periodicBoxSize[0] = (RealOpenMM) boxVectors[0][0];
    periodicBoxSize[1] = (RealOpenMM) boxVectors[1][1];
    periodicBoxSize[2] = (RealOpenMM) boxVectors[2][2];
225
226
227
228
229
    if (nonbondedMethod == NoCutoff)
        neighborList = NULL;
    else
        neighborList = new NeighborList();
        
230
231
}

232
233
234
void ReferenceCalcStandardMMForceFieldKernel::executeForces(OpenMMContextImpl& context) {
    RealOpenMM** posData = const_cast<RealOpenMM**>(((ReferenceFloatStreamImpl&) context.getPositions().getImpl()).getData()); // Reference code needs to be made const correct
    RealOpenMM** forceData = ((ReferenceFloatStreamImpl&) context.getForces().getImpl()).getData();
235
236
237
238
239
240
241
242
243
244
    ReferenceBondForce refBondForce;
    ReferenceHarmonicBondIxn harmonicBond;
    refBondForce.calculateForce(numBonds, bondIndexArray, posData, bondParamArray, forceData, 0, 0, 0, harmonicBond);
    ReferenceAngleBondIxn angleBond;
    refBondForce.calculateForce(numAngles, angleIndexArray, posData, angleParamArray, forceData, 0, 0, 0, angleBond);
    ReferenceProperDihedralBond periodicTorsionBond;
    refBondForce.calculateForce(numPeriodicTorsions, periodicTorsionIndexArray, posData, periodicTorsionParamArray, forceData, 0, 0, 0, periodicTorsionBond);
    ReferenceRbDihedralBond rbTorsionBond;
    refBondForce.calculateForce(numRBTorsions, rbTorsionIndexArray, posData, rbTorsionParamArray, forceData, 0, 0, 0, rbTorsionBond);
    ReferenceLJCoulombIxn clj;
245
246
247
    bool periodic = (nonbondedMethod == CutoffPeriodic);
    if (nonbondedMethod != NoCutoff) {
        computeNeighborListVoxelHash(*neighborList, numAtoms, posData, exclusions, periodic ? periodicBoxSize : NULL, nonbondedCutoff, 0.0);
248
        clj.setUseCutoff(nonbondedCutoff, *neighborList, 78.3f);
249
250
251
    }
    if (periodic)
        clj.setPeriodic(periodicBoxSize);
252
253
    clj.calculatePairIxn(numAtoms, posData, atomParamArray, exclusionArray, 0, forceData, 0, 0);
    ReferenceLJCoulomb14 nonbonded14;
254
    if (nonbondedMethod != NoCutoff)
255
        nonbonded14.setUseCutoff(nonbondedCutoff, 78.3f);
256
257
258
    refBondForce.calculateForce(num14, bonded14IndexArray, posData, bonded14ParamArray, forceData, 0, 0, 0, nonbonded14);
}

259
260
double ReferenceCalcStandardMMForceFieldKernel::executeEnergy(OpenMMContextImpl& context) {
    RealOpenMM** posData = const_cast<RealOpenMM**>(((ReferenceFloatStreamImpl&) context.getPositions().getImpl()).getData()); // Reference code needs to be made const correct
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
    RealOpenMM** forceData = allocateRealArray(numAtoms, 3);
    int arraySize = max(max(max(max(numAtoms, numBonds), numAngles), numPeriodicTorsions), numRBTorsions);
    RealOpenMM* energyArray = new RealOpenMM[arraySize];
    RealOpenMM energy = 0;
    ReferenceBondForce refBondForce;
    ReferenceHarmonicBondIxn harmonicBond;
    for (int i = 0; i < arraySize; ++i)
        energyArray[i] = 0;
    refBondForce.calculateForce(numBonds, bondIndexArray, posData, bondParamArray, forceData, energyArray, 0, &energy, harmonicBond);
    ReferenceAngleBondIxn angleBond;
    for (int i = 0; i < arraySize; ++i)
        energyArray[i] = 0;
    refBondForce.calculateForce(numAngles, angleIndexArray, posData, angleParamArray, forceData, energyArray, 0, &energy, angleBond);
    ReferenceProperDihedralBond periodicTorsionBond;
    for (int i = 0; i < arraySize; ++i)
        energyArray[i] = 0;
    refBondForce.calculateForce(numPeriodicTorsions, periodicTorsionIndexArray, posData, periodicTorsionParamArray, forceData, energyArray, 0, &energy, periodicTorsionBond);
    ReferenceRbDihedralBond rbTorsionBond;
    for (int i = 0; i < arraySize; ++i)
        energyArray[i] = 0;
    refBondForce.calculateForce(numRBTorsions, rbTorsionIndexArray, posData, rbTorsionParamArray, forceData, energyArray, 0, &energy, rbTorsionBond);
    ReferenceLJCoulombIxn clj;
283
284
285
    bool periodic = (nonbondedMethod == CutoffPeriodic);
    if (nonbondedMethod != NoCutoff) {
        computeNeighborListVoxelHash(*neighborList, numAtoms, posData, exclusions, periodic ? periodicBoxSize : NULL, nonbondedCutoff, 0.0);
286
        clj.setUseCutoff(nonbondedCutoff, *neighborList, 78.3f);
287
288
289
    }
    if (periodic)
        clj.setPeriodic(periodicBoxSize);
290
291
    clj.calculatePairIxn(numAtoms, posData, atomParamArray, exclusionArray, 0, forceData, 0, &energy);
    ReferenceLJCoulomb14 nonbonded14;
292
    if (nonbondedMethod != NoCutoff)
293
        nonbonded14.setUseCutoff(nonbondedCutoff, 78.3f);
294
295
296
297
298
299
300
301
    for (int i = 0; i < arraySize; ++i)
        energyArray[i] = 0;
    refBondForce.calculateForce(num14, bonded14IndexArray, posData, bonded14ParamArray, forceData, energyArray, 0, &energy, nonbonded14);
    disposeRealArray(forceData, numAtoms);
    delete[] energyArray;
    return energy;
}

302
303
ReferenceCalcGBSAOBCForceFieldKernel::~ReferenceCalcGBSAOBCForceFieldKernel() {
    if (obc) {
304
        // delete obc->getObcParameters();
305
306
307
308
        delete obc;
    }
}

309
310
void ReferenceCalcGBSAOBCForceFieldKernel::initialize(const System& system, const GBSAOBCForceField& force) {
    int numAtoms = system.getNumAtoms();
311
312
313
314
    charges.resize(numAtoms);
    vector<RealOpenMM> atomicRadii(numAtoms);
    vector<RealOpenMM> scaleFactors(numAtoms);
    for (int i = 0; i < numAtoms; ++i) {
315
316
317
318
319
        double charge, radius, scalingFactor;
        force.getAtomParameters(i, charge, radius, scalingFactor);
        charges[i] = static_cast<RealOpenMM>(charge);
        atomicRadii[i] = static_cast<RealOpenMM>(radius);
        scaleFactors[i] = static_cast<RealOpenMM>(scalingFactor);
320
321
    }
    ObcParameters* obcParameters  = new ObcParameters(numAtoms, ObcParameters::ObcTypeII);
322
    obcParameters->setAtomicRadii(atomicRadii);
323
    obcParameters->setScaledRadiusFactors(scaleFactors);
324
325
    obcParameters->setSolventDielectric( static_cast<RealOpenMM>(force.getSolventDielectric()) );
    obcParameters->setSoluteDielectric( static_cast<RealOpenMM>(force.getSoluteDielectric()) );
326
327
    obc = new CpuObc(obcParameters);
    obc->setIncludeAceApproximation(true);
328
329
}

330
331
332
void ReferenceCalcGBSAOBCForceFieldKernel::executeForces(OpenMMContextImpl& context) {
    RealOpenMM** posData = const_cast<RealOpenMM**>(((ReferenceFloatStreamImpl&) context.getPositions().getImpl()).getData()); // Reference code needs to be made const correct
    RealOpenMM** forceData = ((ReferenceFloatStreamImpl&) context.getForces().getImpl()).getData();
333
    obc->computeImplicitSolventForces(posData, &charges[0], forceData, 0);
334
335
}

336
337
338
double ReferenceCalcGBSAOBCForceFieldKernel::executeEnergy(OpenMMContextImpl& context) {
    RealOpenMM** posData = const_cast<RealOpenMM**>(((ReferenceFloatStreamImpl&) context.getPositions().getImpl()).getData()); // Reference code needs to be made const correct
    RealOpenMM** forceData = allocateRealArray(context.getSystem().getNumAtoms(), 3);
339
    obc->computeImplicitSolventForces(posData, &charges[0], forceData, 1);
340
    disposeRealArray(forceData, context.getSystem().getNumAtoms());
341
    return obc->getEnergy();
342
343
}

344
345
346
347
348
349
350
351
352
353
354
355
356
ReferenceIntegrateVerletStepKernel::~ReferenceIntegrateVerletStepKernel() {
    if (dynamics)
        delete dynamics;
    if (shake)
        delete shake;
    if (masses)
        delete[] masses;
    if (constraintIndices)
        disposeIntArray(constraintIndices, numConstraints);
    if (shakeParameters)
        disposeRealArray(shakeParameters, numConstraints);
}

357
358
359
360
361
362
363
364
void ReferenceIntegrateVerletStepKernel::initialize(const System& system, const VerletIntegrator& integrator) {
    int numAtoms = system.getNumAtoms();
    masses = new RealOpenMM[numAtoms];
    for (size_t i = 0; i < numAtoms; ++i)
        masses[i] = static_cast<RealOpenMM>(system.getAtomMass(i));
    numConstraints = system.getNumConstraints();
    constraintIndices = allocateIntArray(numConstraints, 2);
    shakeParameters = allocateRealArray(numConstraints, 1);
365
    for (int i = 0; i < numConstraints; ++i) {
366
367
368
369
370
371
        int atom1, atom2;
        double distance;
        system.getConstraintParameters(i, atom1, atom2, distance);
        constraintIndices[i][0] = atom1;
        constraintIndices[i][1] = atom2;
        shakeParameters[i][0] = static_cast<RealOpenMM>(distance);
372
    }
373
374
}

375
376
377
378
379
void ReferenceIntegrateVerletStepKernel::execute(OpenMMContextImpl& context, const VerletIntegrator& integrator) {
    double stepSize = integrator.getStepSize();
    RealOpenMM** posData = ((ReferenceFloatStreamImpl&) context.getPositions().getImpl()).getData();
    RealOpenMM** velData = ((ReferenceFloatStreamImpl&) context.getVelocities().getImpl()).getData();
    RealOpenMM** forceData = const_cast<RealOpenMM**>(((ReferenceFloatStreamImpl&) context.getForces().getImpl()).getData()); // Reference code needs to be made const correct
380
381
382
383
384
385
386
    if (dynamics == 0 || stepSize != prevStepSize) {
        // Recreate the computation objects with the new parameters.
        
        if (dynamics) {
            delete dynamics;
            delete shake;
        }
387
        dynamics = new ReferenceVerletDynamics(context.getSystem().getNumAtoms(), static_cast<RealOpenMM>(stepSize) );
388
389
390
391
        shake = new ReferenceShakeAlgorithm(numConstraints, constraintIndices, shakeParameters);
        dynamics->setReferenceShakeAlgorithm(shake);
        prevStepSize = stepSize;
    }
392
    dynamics->update(context.getSystem().getNumAtoms(), posData, velData, forceData, masses);
393
}
394

395
396
397
398
399
400
401
402
403
404
405
406
ReferenceIntegrateLangevinStepKernel::~ReferenceIntegrateLangevinStepKernel() {
    if (dynamics)
        delete dynamics;
    if (shake)
        delete shake;
    if (masses)
        delete[] masses;
    if (constraintIndices)
        disposeIntArray(constraintIndices, numConstraints);
    if (shakeParameters)
        disposeRealArray(shakeParameters, numConstraints);
}
407

408
409
410
411
412
413
414
415
void ReferenceIntegrateLangevinStepKernel::initialize(const System& system, const LangevinIntegrator& integrator) {
    int numAtoms = system.getNumAtoms();
    masses = new RealOpenMM[numAtoms];
    for (size_t i = 0; i < numAtoms; ++i)
        masses[i] = static_cast<RealOpenMM>(system.getAtomMass(i));
    numConstraints = system.getNumConstraints();
    constraintIndices = allocateIntArray(numConstraints, 2);
    shakeParameters = allocateRealArray(numConstraints, 1);
416
    for (int i = 0; i < numConstraints; ++i) {
417
418
419
420
421
422
        int atom1, atom2;
        double distance;
        system.getConstraintParameters(i, atom1, atom2, distance);
        constraintIndices[i][0] = atom1;
        constraintIndices[i][1] = atom2;
        shakeParameters[i][0] = static_cast<RealOpenMM>(distance);
423
    }
424
425
}

426
427
428
429
430
431
432
void ReferenceIntegrateLangevinStepKernel::execute(OpenMMContextImpl& context, const LangevinIntegrator& integrator) {
    double temperature = integrator.getTemperature();
    double friction = integrator.getFriction();
    double stepSize = integrator.getStepSize();
    RealOpenMM** posData = ((ReferenceFloatStreamImpl&) context.getPositions().getImpl()).getData();
    RealOpenMM** velData = ((ReferenceFloatStreamImpl&) context.getVelocities().getImpl()).getData();
    RealOpenMM** forceData = const_cast<RealOpenMM**>(((ReferenceFloatStreamImpl&) context.getForces().getImpl()).getData()); // Reference code needs to be made const correct
433
434
435
436
437
438
439
    if (dynamics == 0 || temperature != prevTemp || friction != prevFriction || stepSize != prevStepSize) {
        // Recreate the computation objects with the new parameters.
        
        if (dynamics) {
            delete dynamics;
            delete shake;
        }
440
441
        RealOpenMM tau = static_cast<RealOpenMM>( friction == 0.0 ? 0.0 : 1.0/friction );
        dynamics = new ReferenceStochasticDynamics(
442
				context.getSystem().getNumAtoms(), 
443
444
445
				static_cast<RealOpenMM>(stepSize), 
				static_cast<RealOpenMM>(tau), 
				static_cast<RealOpenMM>(temperature) );
446
447
448
449
450
451
        shake = new ReferenceShakeAlgorithm(numConstraints, constraintIndices, shakeParameters);
        dynamics->setReferenceShakeAlgorithm(shake);
        prevTemp = temperature;
        prevFriction = friction;
        prevStepSize = stepSize;
    }
452
    dynamics->update(context.getSystem().getNumAtoms(), posData, velData, forceData, masses);
453
454
}

455
456
457
458
459
460
461
462
463
464
465
466
467
ReferenceIntegrateBrownianStepKernel::~ReferenceIntegrateBrownianStepKernel() {
    if (dynamics)
        delete dynamics;
    if (shake)
        delete shake;
    if (masses)
        delete[] masses;
    if (constraintIndices)
        disposeIntArray(constraintIndices, numConstraints);
    if (shakeParameters)
        disposeRealArray(shakeParameters, numConstraints);
}

468
469
470
471
472
473
474
475
void ReferenceIntegrateBrownianStepKernel::initialize(const System& system, const BrownianIntegrator& integrator) {
    int numAtoms = system.getNumAtoms();
    masses = new RealOpenMM[numAtoms];
    for (size_t i = 0; i < numAtoms; ++i)
        masses[i] = static_cast<RealOpenMM>(system.getAtomMass(i));
    numConstraints = system.getNumConstraints();
    constraintIndices = allocateIntArray(numConstraints, 2);
    shakeParameters = allocateRealArray(numConstraints, 1);
476
    for (int i = 0; i < numConstraints; ++i) {
477
478
479
480
481
482
        int atom1, atom2;
        double distance;
        system.getConstraintParameters(i, atom1, atom2, distance);
        constraintIndices[i][0] = atom1;
        constraintIndices[i][1] = atom2;
        shakeParameters[i][0] = static_cast<RealOpenMM>(distance);
483
    }
484
485
}

486
487
488
489
490
491
492
void ReferenceIntegrateBrownianStepKernel::execute(OpenMMContextImpl& context, const BrownianIntegrator& integrator) {
    double temperature = integrator.getTemperature();
    double friction = integrator.getFriction();
    double stepSize = integrator.getStepSize();
    RealOpenMM** posData = ((ReferenceFloatStreamImpl&) context.getPositions().getImpl()).getData();
    RealOpenMM** velData = ((ReferenceFloatStreamImpl&) context.getVelocities().getImpl()).getData();
    RealOpenMM** forceData = const_cast<RealOpenMM**>(((ReferenceFloatStreamImpl&) context.getForces().getImpl()).getData()); // Reference code needs to be made const correct
493
494
495
496
497
498
499
    if (dynamics == 0 || temperature != prevTemp || friction != prevFriction || stepSize != prevStepSize) {
        // Recreate the computation objects with the new parameters.
        
        if (dynamics) {
            delete dynamics;
            delete shake;
        }
500
        dynamics = new ReferenceBrownianDynamics(
501
				context.getSystem().getNumAtoms(), 
502
503
504
				static_cast<RealOpenMM>(stepSize), 
				static_cast<RealOpenMM>(friction), 
				static_cast<RealOpenMM>(temperature) );
505
506
507
508
509
510
        shake = new ReferenceShakeAlgorithm(numConstraints, constraintIndices, shakeParameters);
        dynamics->setReferenceShakeAlgorithm(shake);
        prevTemp = temperature;
        prevFriction = friction;
        prevStepSize = stepSize;
    }
511
    dynamics->update(context.getSystem().getNumAtoms(), posData, velData, forceData, masses);
512
513
}

514
515
516
517
518
519
520
ReferenceApplyAndersenThermostatKernel::~ReferenceApplyAndersenThermostatKernel() {
    if (thermostat)
        delete thermostat;
    if (masses)
        delete[] masses;
}

521
522
523
524
525
526
void ReferenceApplyAndersenThermostatKernel::initialize(const System& system, const AndersenThermostat& thermostat) {
    int numAtoms = system.getNumAtoms();
    masses = new RealOpenMM[numAtoms];
    for (size_t i = 0; i < numAtoms; ++i)
        masses[i] = static_cast<RealOpenMM>(system.getAtomMass(i));
    this->thermostat = new ReferenceAndersenThermostat();
527
528
}

529
530
void ReferenceApplyAndersenThermostatKernel::execute(OpenMMContextImpl& context) {
    RealOpenMM** velData = ((ReferenceFloatStreamImpl&) context.getVelocities().getImpl()).getData();
531
    thermostat->applyThermostat(
532
			context.getVelocities().getSize(), 
533
534
			velData, 
			masses, 
535
536
537
			static_cast<RealOpenMM>(context.getParameter(AndersenThermostat::Temperature)), 
			static_cast<RealOpenMM>(context.getParameter(AndersenThermostat::CollisionFrequency)), 
			static_cast<RealOpenMM>(context.getIntegrator().getStepSize()) );
538
539
}

540
541
542
543
544
void ReferenceCalcKineticEnergyKernel::initialize(const System& system) {
    int numAtoms = system.getNumAtoms();
    masses.resize(numAtoms);
    for (size_t i = 0; i < numAtoms; ++i)
        masses[i] = system.getAtomMass(i);
545
546
}

547
548
double ReferenceCalcKineticEnergyKernel::execute(OpenMMContextImpl& context) {
    RealOpenMM** velData = const_cast<RealOpenMM**>(((ReferenceFloatStreamImpl&) context.getVelocities().getImpl()).getData()); // Reference code needs to be made const correct
549
    double energy = 0.0;
550
    for (size_t i = 0; i < masses.size(); ++i)
551
552
        energy += masses[i]*(velData[i][0]*velData[i][0]+velData[i][1]*velData[i][1]+velData[i][2]*velData[i][2]);
    return 0.5*energy;
553
}
554

555
556
557
void ReferenceRemoveCMMotionKernel::initialize(const System& system, const CMMotionRemover& force) {
    frequency = force.getFrequency();
    masses.resize(system.getNumAtoms());
558
    for (size_t i = 0; i < masses.size(); ++i)
559
        masses[i] = system.getAtomMass(i);
560
561
}

562
563
564
565
566
void ReferenceRemoveCMMotionKernel::execute(OpenMMContextImpl& context) {
    int step = std::floor(context.getTime()/context.getIntegrator().getStepSize());
    if (step%frequency != 0)
        return;
    RealOpenMM** velData = ((ReferenceFloatStreamImpl&) context.getVelocities().getImpl()).getData();
567
568
569
570
    
    // Calculate the center of mass momentum.
    
    RealOpenMM momentum[] = {0.0, 0.0, 0.0};
571
572
573
574
    for (size_t i = 0; i < masses.size(); ++i) {
        momentum[0] += static_cast<RealOpenMM>( masses[i]*velData[i][0] );
        momentum[1] += static_cast<RealOpenMM>( masses[i]*velData[i][1] );
        momentum[2] += static_cast<RealOpenMM>( masses[i]*velData[i][2] );
575
576
577
578
    }
    
    // Adjust the atom velocities.
    
579
580
581
582
583
584
585
    momentum[0] /= static_cast<RealOpenMM>( masses.size() );
    momentum[1] /= static_cast<RealOpenMM>( masses.size() );
    momentum[2] /= static_cast<RealOpenMM>( masses.size() );
    for (size_t i = 0; i < masses.size(); ++i) {
        velData[i][0] -= static_cast<RealOpenMM>( momentum[0]/masses[i] );
        velData[i][1] -= static_cast<RealOpenMM>( momentum[1]/masses[i] );
        velData[i][2] -= static_cast<RealOpenMM>( momentum[2]/masses[i] );
586
587
    }
}