AmoebaReferenceKernels.cpp 60.2 KB
Newer Older
1
/* -------------------------------------------------------------------------- *
2
 *                               OpenMMAmoeba                                 *
3
4
5
6
7
8
 * -------------------------------------------------------------------------- *
 * 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.               *
 *                                                                            *
peastman's avatar
peastman committed
9
 * Portions copyright (c) 2008-2016 Stanford University and the Authors.      *
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 * Authors:                                                                   *
 * Contributors:                                                              *
 *                                                                            *
 * 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.                                        *
 *                                                                            *
 * 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.                        *
 *                                                                            *
 * 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/>.      *
 * -------------------------------------------------------------------------- */

#include "AmoebaReferenceKernels.h"
28
29
30
#include "AmoebaReferenceBondForce.h"
#include "AmoebaReferenceAngleForce.h"
#include "AmoebaReferenceInPlaneAngleForce.h"
31
#include "AmoebaReferencePiTorsionForce.h"
32
#include "AmoebaReferenceStretchBendForce.h"
33
#include "AmoebaReferenceOutOfPlaneBendForce.h"
34
#include "AmoebaReferenceTorsionTorsionForce.h"
Mark Friedrichs's avatar
Mark Friedrichs committed
35
#include "AmoebaReferenceVdwForce.h"
Mark Friedrichs's avatar
Mark Friedrichs committed
36
#include "AmoebaReferenceWcaDispersionForce.h"
37
#include "AmoebaReferenceGeneralizedKirkwoodForce.h"
38
#include "openmm/internal/AmoebaTorsionTorsionForceImpl.h"
39
#include "openmm/internal/AmoebaWcaDispersionForceImpl.h"
40
41
#include "ReferencePlatform.h"
#include "openmm/internal/ContextImpl.h"
42
#include "openmm/AmoebaMultipoleForce.h"
peastman's avatar
peastman committed
43
#include "openmm/HippoNonbondedForce.h"
44
#include "openmm/internal/AmoebaMultipoleForceImpl.h"
45
#include "openmm/internal/AmoebaVdwForceImpl.h"
46
#include "openmm/internal/AmoebaGeneralizedKirkwoodForceImpl.h"
47
48
#include "openmm/NonbondedForce.h"
#include "openmm/internal/NonbondedForceImpl.h"
peastman's avatar
peastman committed
49
#include "SimTKReference/AmoebaReferenceHippoNonbondedForce.h"
50
51
52
53
54
55
56
57
58

#include <cmath>
#ifdef _MSC_VER
#include <windows.h>
#endif

using namespace OpenMM;
using namespace std;

peastman's avatar
peastman committed
59
static vector<Vec3>& extractPositions(ContextImpl& context) {
60
    ReferencePlatform::PlatformData* data = reinterpret_cast<ReferencePlatform::PlatformData*>(context.getPlatformData());
peastman's avatar
peastman committed
61
    return *((vector<Vec3>*) data->positions);
62
}
63

peastman's avatar
peastman committed
64
static vector<Vec3>& extractVelocities(ContextImpl& context) {
65
    ReferencePlatform::PlatformData* data = reinterpret_cast<ReferencePlatform::PlatformData*>(context.getPlatformData());
peastman's avatar
peastman committed
66
    return *((vector<Vec3>*) data->velocities);
67
}
68

peastman's avatar
peastman committed
69
static vector<Vec3>& extractForces(ContextImpl& context) {
70
    ReferencePlatform::PlatformData* data = reinterpret_cast<ReferencePlatform::PlatformData*>(context.getPlatformData());
peastman's avatar
peastman committed
71
    return *((vector<Vec3>*) data->forces);
72
}
73

peastman's avatar
peastman committed
74
static Vec3& extractBoxSize(ContextImpl& context) {
75
    ReferencePlatform::PlatformData* data = reinterpret_cast<ReferencePlatform::PlatformData*>(context.getPlatformData());
peastman's avatar
peastman committed
76
    return *(Vec3*) data->periodicBoxSize;
77
78
}

peastman's avatar
peastman committed
79
static Vec3* extractBoxVectors(ContextImpl& context) {
80
    ReferencePlatform::PlatformData* data = reinterpret_cast<ReferencePlatform::PlatformData*>(context.getPlatformData());
peastman's avatar
peastman committed
81
    return (Vec3*) data->periodicBoxVectors;
82
83
}

84
85
// ***************************************************************************

86
ReferenceCalcAmoebaBondForceKernel::ReferenceCalcAmoebaBondForceKernel(std::string name, const Platform& platform, const System& system) : 
87
                CalcAmoebaBondForceKernel(name, platform), system(system) {
88
89
}

90
ReferenceCalcAmoebaBondForceKernel::~ReferenceCalcAmoebaBondForceKernel() {
91
92
}

93
void ReferenceCalcAmoebaBondForceKernel::initialize(const System& system, const AmoebaBondForce& force) {
94
95

    numBonds = force.getNumBonds();
96
    for (int ii = 0; ii < numBonds; ii++) {
97
98
99

        int particle1Index, particle2Index;
        double lengthValue, kValue;
100
        force.getBondParameters(ii, particle1Index, particle2Index, lengthValue, kValue);
101

102
103
        particle1.push_back(particle1Index); 
        particle2.push_back(particle2Index); 
peastman's avatar
peastman committed
104
105
        length.push_back(static_cast<double>(lengthValue));
        kQuadratic.push_back(kValue);
106
    } 
peastman's avatar
peastman committed
107
108
    globalBondCubic   = force.getAmoebaGlobalBondCubic();
    globalBondQuartic = force.getAmoebaGlobalBondQuartic();
109
    usePeriodic = force.usesPeriodicBoundaryConditions();
110
111
}

112
double ReferenceCalcAmoebaBondForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
peastman's avatar
peastman committed
113
114
    vector<Vec3>& posData = extractPositions(context);
    vector<Vec3>& forceData = extractForces(context);
115
    AmoebaReferenceBondForce amoebaReferenceBondForce;
116
117
    if (usePeriodic)
        amoebaReferenceBondForce.setPeriodic(extractBoxVectors(context));
peastman's avatar
peastman committed
118
119
120
    double energy = amoebaReferenceBondForce.calculateForceAndEnergy(numBonds, posData, particle1, particle2, length, kQuadratic,
                                                                     globalBondCubic, globalBondQuartic,
                                                                     forceData);
121
122
123
    return static_cast<double>(energy);
}

124
125
126
127
128
129
130
131
132
133
134
135
void ReferenceCalcAmoebaBondForceKernel::copyParametersToContext(ContextImpl& context, const AmoebaBondForce& force) {
    if (numBonds != force.getNumBonds())
        throw OpenMMException("updateParametersInContext: The number of bonds has changed");

    // Record the values.

    for (int i = 0; i < numBonds; ++i) {
        int particle1Index, particle2Index;
        double lengthValue, kValue;
        force.getBondParameters(i, particle1Index, particle2Index, lengthValue, kValue);
        if (particle1Index != particle1[i] || particle2Index != particle2[i])
            throw OpenMMException("updateParametersInContext: The set of particles in a bond has changed");
peastman's avatar
peastman committed
136
137
        length[i] = lengthValue;
        kQuadratic[i] = kValue;
138
139
140
    }
}

141
142
// ***************************************************************************

143
ReferenceCalcAmoebaAngleForceKernel::ReferenceCalcAmoebaAngleForceKernel(std::string name, const Platform& platform, const System& system) :
144
            CalcAmoebaAngleForceKernel(name, platform), system(system) {
145
146
}

147
ReferenceCalcAmoebaAngleForceKernel::~ReferenceCalcAmoebaAngleForceKernel() {
148
149
}

150
void ReferenceCalcAmoebaAngleForceKernel::initialize(const System& system, const AmoebaAngleForce& force) {
151
152
153
154
155
156
157

    numAngles = force.getNumAngles();

    for (int ii = 0; ii < numAngles; ii++) {
        int particle1Index, particle2Index, particle3Index;
        double angleValue, k;
        force.getAngleParameters(ii, particle1Index, particle2Index, particle3Index, angleValue, k);
158
159
160
        particle1.push_back(particle1Index); 
        particle2.push_back(particle2Index); 
        particle3.push_back(particle3Index); 
peastman's avatar
peastman committed
161
162
        angle.push_back(angleValue);
        kQuadratic.push_back(k);
163
    }
peastman's avatar
peastman committed
164
165
166
167
    globalAngleCubic    = force.getAmoebaGlobalAngleCubic();
    globalAngleQuartic  = force.getAmoebaGlobalAngleQuartic();
    globalAnglePentic   = force.getAmoebaGlobalAnglePentic();
    globalAngleSextic   = force.getAmoebaGlobalAngleSextic();
168
    usePeriodic = force.usesPeriodicBoundaryConditions();
169
170
}

171
double ReferenceCalcAmoebaAngleForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
peastman's avatar
peastman committed
172
173
    vector<Vec3>& posData = extractPositions(context);
    vector<Vec3>& forceData = extractForces(context);
174
    AmoebaReferenceAngleForce amoebaReferenceAngleForce;
175
176
    if (usePeriodic)
        amoebaReferenceAngleForce.setPeriodic(extractBoxVectors(context));
peastman's avatar
peastman committed
177
    double energy = amoebaReferenceAngleForce.calculateForceAndEnergy(numAngles, 
178
                                       posData, particle1, particle2, particle3, angle, kQuadratic, globalAngleCubic, globalAngleQuartic, globalAnglePentic, globalAngleSextic, forceData);
179
180
181
    return static_cast<double>(energy);
}

182
183
184
185
186
187
188
189
190
191
192
193
void ReferenceCalcAmoebaAngleForceKernel::copyParametersToContext(ContextImpl& context, const AmoebaAngleForce& force) {
    if (numAngles != force.getNumAngles())
        throw OpenMMException("updateParametersInContext: The number of angles has changed");

    // Record the values.

    for (int i = 0; i < numAngles; ++i) {
        int particle1Index, particle2Index, particle3Index;
        double angleValue, k;
        force.getAngleParameters(i, particle1Index, particle2Index, particle3Index, angleValue, k);
        if (particle1Index != particle1[i] || particle2Index != particle2[i] || particle3Index != particle3[i])
            throw OpenMMException("updateParametersInContext: The set of particles in an angle has changed");
peastman's avatar
peastman committed
194
195
        angle[i] = angleValue;
        kQuadratic[i] = k;
196
197
198
    }
}

199
ReferenceCalcAmoebaInPlaneAngleForceKernel::ReferenceCalcAmoebaInPlaneAngleForceKernel(std::string name, const Platform& platform, const System& system) : 
200
          CalcAmoebaInPlaneAngleForceKernel(name, platform), system(system) {
201
202
}

203
ReferenceCalcAmoebaInPlaneAngleForceKernel::~ReferenceCalcAmoebaInPlaneAngleForceKernel() {
204
205
}

206
void ReferenceCalcAmoebaInPlaneAngleForceKernel::initialize(const System& system, const AmoebaInPlaneAngleForce& force) {
207
208
209
210
211
212

    numAngles = force.getNumAngles();
    for (int ii = 0; ii < numAngles; ii++) {
        int particle1Index, particle2Index, particle3Index, particle4Index;
        double angleValue, k;
        force.getAngleParameters(ii, particle1Index, particle2Index, particle3Index, particle4Index, angleValue, k);
213
214
215
216
        particle1.push_back(particle1Index); 
        particle2.push_back(particle2Index); 
        particle3.push_back(particle3Index); 
        particle4.push_back(particle4Index); 
peastman's avatar
peastman committed
217
218
        angle.push_back(angleValue);
        kQuadratic.push_back(k);
219
    }
peastman's avatar
peastman committed
220
221
222
223
    globalInPlaneAngleCubic    = force.getAmoebaGlobalInPlaneAngleCubic();
    globalInPlaneAngleQuartic  = force.getAmoebaGlobalInPlaneAngleQuartic();
    globalInPlaneAnglePentic   = force.getAmoebaGlobalInPlaneAnglePentic();
    globalInPlaneAngleSextic   = force.getAmoebaGlobalInPlaneAngleSextic();
224
    usePeriodic = force.usesPeriodicBoundaryConditions();
225
226
}

227
double ReferenceCalcAmoebaInPlaneAngleForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
228

peastman's avatar
peastman committed
229
230
    vector<Vec3>& posData = extractPositions(context);
    vector<Vec3>& forceData = extractForces(context);
231
    AmoebaReferenceInPlaneAngleForce amoebaReferenceInPlaneAngleForce;
232
233
    if (usePeriodic)
        amoebaReferenceInPlaneAngleForce.setPeriodic(extractBoxVectors(context));
peastman's avatar
peastman committed
234
235
236
    double energy = amoebaReferenceInPlaneAngleForce.calculateForceAndEnergy(numAngles, posData, particle1, particle2, particle3, particle4, 
                                                                             angle, kQuadratic, globalInPlaneAngleCubic, globalInPlaneAngleQuartic,
                                                                             globalInPlaneAnglePentic, globalInPlaneAngleSextic, forceData);
237
238
239
    return static_cast<double>(energy);
}

240
241
242
243
244
245
246
247
248
249
250
251
void ReferenceCalcAmoebaInPlaneAngleForceKernel::copyParametersToContext(ContextImpl& context, const AmoebaInPlaneAngleForce& force) {
    if (numAngles != force.getNumAngles())
        throw OpenMMException("updateParametersInContext: The number of angles has changed");

    // Record the values.

    for (int i = 0; i < numAngles; ++i) {
        int particle1Index, particle2Index, particle3Index, particle4Index;
        double angleValue, k;
        force.getAngleParameters(i, particle1Index, particle2Index, particle3Index, particle4Index, angleValue, k);
        if (particle1Index != particle1[i] || particle2Index != particle2[i] || particle3Index != particle3[i] || particle4Index != particle4[i])
            throw OpenMMException("updateParametersInContext: The set of particles in an angle has changed");
peastman's avatar
peastman committed
252
253
        angle[i] = angleValue;
        kQuadratic[i] = k;
254
255
256
    }
}

257
ReferenceCalcAmoebaPiTorsionForceKernel::ReferenceCalcAmoebaPiTorsionForceKernel(std::string name, const Platform& platform, const System& system) :
258
259
260
261
262
263
264
265
266
267
268
269
270
         CalcAmoebaPiTorsionForceKernel(name, platform), system(system) {
}

ReferenceCalcAmoebaPiTorsionForceKernel::~ReferenceCalcAmoebaPiTorsionForceKernel() {
}

void ReferenceCalcAmoebaPiTorsionForceKernel::initialize(const System& system, const AmoebaPiTorsionForce& force) {

    numPiTorsions                     = force.getNumPiTorsions();
    for (int ii = 0; ii < numPiTorsions; ii++) {

        int particle1Index, particle2Index, particle3Index, particle4Index, particle5Index, particle6Index;
        double kTorsionParameter;
271
272
273
274
275
276
277
        force.getPiTorsionParameters(ii, particle1Index, particle2Index, particle3Index, particle4Index, particle5Index, particle6Index, kTorsionParameter);
        particle1.push_back(particle1Index); 
        particle2.push_back(particle2Index); 
        particle3.push_back(particle3Index); 
        particle4.push_back(particle4Index); 
        particle5.push_back(particle5Index); 
        particle6.push_back(particle6Index); 
peastman's avatar
peastman committed
278
        kTorsion.push_back(kTorsionParameter);
279
    }
280
    usePeriodic = force.usesPeriodicBoundaryConditions();
281
282
283
}

double ReferenceCalcAmoebaPiTorsionForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
peastman's avatar
peastman committed
284
285
    vector<Vec3>& posData = extractPositions(context);
    vector<Vec3>& forceData = extractForces(context);
286
    AmoebaReferencePiTorsionForce amoebaReferencePiTorsionForce;
287
288
    if (usePeriodic)
        amoebaReferencePiTorsionForce.setPeriodic(extractBoxVectors(context));
peastman's avatar
peastman committed
289
    double energy = amoebaReferencePiTorsionForce.calculateForceAndEnergy(numPiTorsions, posData, particle1, particle2,
290
                                                                                    particle3, particle4, particle5, particle6,
291
                                                                                    kTorsion, forceData);
292
293
294
    return static_cast<double>(energy);
}

295
296
297
298
299
300
301
302
303
304
305
306
307
void ReferenceCalcAmoebaPiTorsionForceKernel::copyParametersToContext(ContextImpl& context, const AmoebaPiTorsionForce& force) {
    if (numPiTorsions != force.getNumPiTorsions())
        throw OpenMMException("updateParametersInContext: The number of torsions has changed");

    // Record the values.

    for (int i = 0; i < numPiTorsions; ++i) {
        int particle1Index, particle2Index, particle3Index, particle4Index, particle5Index, particle6Index;
        double kTorsionParameter;
        force.getPiTorsionParameters(i, particle1Index, particle2Index, particle3Index, particle4Index, particle5Index, particle6Index, kTorsionParameter);
        if (particle1Index != particle1[i] || particle2Index != particle2[i] || particle3Index != particle3[i] ||
            particle4Index != particle4[i] || particle5Index != particle5[i] || particle6Index != particle6[i])
            throw OpenMMException("updateParametersInContext: The set of particles in a torsion has changed");
peastman's avatar
peastman committed
308
        kTorsion[i] = kTorsionParameter;
309
310
311
    }
}

312
ReferenceCalcAmoebaStretchBendForceKernel::ReferenceCalcAmoebaStretchBendForceKernel(std::string name, const Platform& platform, const System& system) :
313
314
315
316
317
318
319
320
321
                   CalcAmoebaStretchBendForceKernel(name, platform), system(system) {
}

ReferenceCalcAmoebaStretchBendForceKernel::~ReferenceCalcAmoebaStretchBendForceKernel() {
}

void ReferenceCalcAmoebaStretchBendForceKernel::initialize(const System& system, const AmoebaStretchBendForce& force) {

    numStretchBends = force.getNumStretchBends();
322
    for (int ii = 0; ii < numStretchBends; ii++) {
323
        int particle1Index, particle2Index, particle3Index;
324
325
        double lengthAB, lengthCB, angle, k1, k2;
        force.getStretchBendParameters(ii, particle1Index, particle2Index, particle3Index, lengthAB, lengthCB, angle, k1, k2);
326
327
328
        particle1.push_back(particle1Index); 
        particle2.push_back(particle2Index); 
        particle3.push_back(particle3Index); 
peastman's avatar
peastman committed
329
330
331
332
333
        lengthABParameters.push_back(lengthAB);
        lengthCBParameters.push_back(lengthCB);
        angleParameters.push_back(angle);
        k1Parameters.push_back(k1);
        k2Parameters.push_back(k2);
334
    }
335
    usePeriodic = force.usesPeriodicBoundaryConditions();
336
337
338
}

double ReferenceCalcAmoebaStretchBendForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
peastman's avatar
peastman committed
339
340
    vector<Vec3>& posData = extractPositions(context);
    vector<Vec3>& forceData = extractForces(context);
341
    AmoebaReferenceStretchBendForce amoebaReferenceStretchBendForce;
342
343
    if (usePeriodic)
        amoebaReferenceStretchBendForce.setPeriodic(extractBoxVectors(context));
peastman's avatar
peastman committed
344
    double energy = amoebaReferenceStretchBendForce.calculateForceAndEnergy(numStretchBends, posData, particle1, particle2, particle3,
345
                                                                                      lengthABParameters, lengthCBParameters, angleParameters, k1Parameters,
346
                                                                                      k2Parameters, forceData);
347
348
349
    return static_cast<double>(energy);
}

350
351
352
353
354
355
356
357
void ReferenceCalcAmoebaStretchBendForceKernel::copyParametersToContext(ContextImpl& context, const AmoebaStretchBendForce& force) {
    if (numStretchBends != force.getNumStretchBends())
        throw OpenMMException("updateParametersInContext: The number of stretch-bends has changed");

    // Record the values.

    for (int i = 0; i < numStretchBends; ++i) {
        int particle1Index, particle2Index, particle3Index;
358
359
        double lengthAB, lengthCB, angle, k1, k2;
        force.getStretchBendParameters(i, particle1Index, particle2Index, particle3Index, lengthAB, lengthCB, angle, k1, k2);
360
361
        if (particle1Index != particle1[i] || particle2Index != particle2[i] || particle3Index != particle3[i])
            throw OpenMMException("updateParametersInContext: The set of particles in a stretch-bend has changed");
peastman's avatar
peastman committed
362
363
364
365
366
        lengthABParameters[i] = lengthAB;
        lengthCBParameters[i] = lengthCB;
        angleParameters[i] = angle;
        k1Parameters[i] = k1;
        k2Parameters[i] = k2;
367
368
369
    }
}

370
ReferenceCalcAmoebaOutOfPlaneBendForceKernel::ReferenceCalcAmoebaOutOfPlaneBendForceKernel(std::string name, const Platform& platform, const System& system) :
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
          CalcAmoebaOutOfPlaneBendForceKernel(name, platform), system(system) {
}

ReferenceCalcAmoebaOutOfPlaneBendForceKernel::~ReferenceCalcAmoebaOutOfPlaneBendForceKernel() {
}

void ReferenceCalcAmoebaOutOfPlaneBendForceKernel::initialize(const System& system, const AmoebaOutOfPlaneBendForce& force) {

    numOutOfPlaneBends = force.getNumOutOfPlaneBends();
    for (int ii = 0; ii < numOutOfPlaneBends; ii++) {

        int particle1Index, particle2Index, particle3Index, particle4Index;
        double k;

        force.getOutOfPlaneBendParameters(ii, particle1Index, particle2Index, particle3Index, particle4Index, k);
386
387
388
389
        particle1.push_back(particle1Index); 
        particle2.push_back(particle2Index); 
        particle3.push_back(particle3Index); 
        particle4.push_back(particle4Index); 
peastman's avatar
peastman committed
390
        kParameters.push_back(k);
391
    }
peastman's avatar
peastman committed
392
393
394
395
    globalOutOfPlaneBendAngleCubic   = force.getAmoebaGlobalOutOfPlaneBendCubic();
    globalOutOfPlaneBendAngleQuartic = force.getAmoebaGlobalOutOfPlaneBendQuartic();
    globalOutOfPlaneBendAnglePentic  = force.getAmoebaGlobalOutOfPlaneBendPentic();
    globalOutOfPlaneBendAngleSextic  = force.getAmoebaGlobalOutOfPlaneBendSextic();
396
    usePeriodic = force.usesPeriodicBoundaryConditions();
397
398
399
}

double ReferenceCalcAmoebaOutOfPlaneBendForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
peastman's avatar
peastman committed
400
401
    vector<Vec3>& posData = extractPositions(context);
    vector<Vec3>& forceData = extractForces(context);
402
    AmoebaReferenceOutOfPlaneBendForce amoebaReferenceOutOfPlaneBendForce;
403
404
    if (usePeriodic)
        amoebaReferenceOutOfPlaneBendForce.setPeriodic(extractBoxVectors(context));
peastman's avatar
peastman committed
405
406
407
408
409
410
411
    double energy = amoebaReferenceOutOfPlaneBendForce.calculateForceAndEnergy(numOutOfPlaneBends, posData,
                                                                               particle1, particle2, particle3, particle4,
                                                                               kParameters, 
                                                                               globalOutOfPlaneBendAngleCubic,
                                                                               globalOutOfPlaneBendAngleQuartic,
                                                                               globalOutOfPlaneBendAnglePentic,
                                                                               globalOutOfPlaneBendAngleSextic, forceData); 
412
413
414
    return static_cast<double>(energy);
}

415
416
417
418
419
420
421
422
423
424
425
426
void ReferenceCalcAmoebaOutOfPlaneBendForceKernel::copyParametersToContext(ContextImpl& context, const AmoebaOutOfPlaneBendForce& force) {
    if (numOutOfPlaneBends != force.getNumOutOfPlaneBends())
        throw OpenMMException("updateParametersInContext: The number of out-of-plane bends has changed");

    // Record the values.

    for (int i = 0; i < numOutOfPlaneBends; ++i) {
        int particle1Index, particle2Index, particle3Index, particle4Index;
        double k;
        force.getOutOfPlaneBendParameters(i, particle1Index, particle2Index, particle3Index, particle4Index, k);
        if (particle1Index != particle1[i] || particle2Index != particle2[i] || particle3Index != particle3[i] || particle4Index != particle4[i])
            throw OpenMMException("updateParametersInContext: The set of particles in an out-of-plane bend has changed");
peastman's avatar
peastman committed
427
        kParameters[i] = k;
428
429
430
    }
}

431
ReferenceCalcAmoebaTorsionTorsionForceKernel::ReferenceCalcAmoebaTorsionTorsionForceKernel(std::string name, const Platform& platform, const System& system) :
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
                CalcAmoebaTorsionTorsionForceKernel(name, platform), system(system) {
}

ReferenceCalcAmoebaTorsionTorsionForceKernel::~ReferenceCalcAmoebaTorsionTorsionForceKernel() {
}

void ReferenceCalcAmoebaTorsionTorsionForceKernel::initialize(const System& system, const AmoebaTorsionTorsionForce& force) {

    numTorsionTorsions = force.getNumTorsionTorsions();

    // torsion-torsion parameters

    for (int ii = 0; ii < numTorsionTorsions; ii++) {
        int particle1Index, particle2Index, particle3Index, particle4Index, particle5Index, chiralCheckAtomIndex, gridIndex;
        force.getTorsionTorsionParameters(ii, particle1Index, particle2Index, particle3Index,
                                          particle4Index, particle5Index, chiralCheckAtomIndex, gridIndex);
448
449
450
451
452
453
454
        particle1.push_back(particle1Index); 
        particle2.push_back(particle2Index); 
        particle3.push_back(particle3Index); 
        particle4.push_back(particle4Index); 
        particle5.push_back(particle5Index); 
        chiralCheckAtom.push_back(chiralCheckAtomIndex); 
        gridIndices.push_back(gridIndex); 
455
    }
456
    usePeriodic = force.usesPeriodicBoundaryConditions();
457
458
459
460
461
462
463

    // torsion-torsion grids

    numTorsionTorsionGrids = force.getNumTorsionTorsionGrids();
    torsionTorsionGrids.resize(numTorsionTorsionGrids);
    for (int ii = 0; ii < numTorsionTorsionGrids; ii++) {

464
465
        const TorsionTorsionGrid grid = force.getTorsionTorsionGrid(ii);
        torsionTorsionGrids[ii].resize(grid.size());
466
467
468
469
470

        // check if grid needs to be reordered: x-angle should be 'slow' index

        TorsionTorsionGrid reorderedGrid;
        int reorder = 0; 
471
472
        if (grid[0][0][0] != grid[0][1][0]) {
            AmoebaTorsionTorsionForceImpl::reorderGrid(grid, reorderedGrid);
473
474
475
            reorder = 1; 
        }    

476
477
        for (unsigned int kk = 0; kk < grid.size(); kk++) {

478
            torsionTorsionGrids[ii][kk].resize(grid[kk].size());
479
480
            for (unsigned int jj = 0; jj < grid[kk].size(); jj++) {

481
482
                torsionTorsionGrids[ii][kk][jj].resize(grid[kk][jj].size());
                if (reorder) {
483
                    for (unsigned int ll = 0; ll < grid[ll][jj].size(); ll++) {
peastman's avatar
peastman committed
484
                        torsionTorsionGrids[ii][kk][jj][ll] = reorderedGrid[kk][jj][ll];
485
486
487
                    }
                } else {
                    for (unsigned int ll = 0; ll < grid[ll][jj].size(); ll++) {
peastman's avatar
peastman committed
488
                        torsionTorsionGrids[ii][kk][jj][ll] = grid[kk][jj][ll];
489
                    }
490
491
492
493
494
495
496
497
                }
            }
        }
    }
}

double ReferenceCalcAmoebaTorsionTorsionForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {

peastman's avatar
peastman committed
498
499
    vector<Vec3>& posData   = extractPositions(context);
    vector<Vec3>& forceData = extractForces(context);
500
    AmoebaReferenceTorsionTorsionForce amoebaReferenceTorsionTorsionForce;
501
502
    if (usePeriodic)
        amoebaReferenceTorsionTorsionForce.setPeriodic(extractBoxVectors(context));
peastman's avatar
peastman committed
503
    double energy = amoebaReferenceTorsionTorsionForce.calculateForceAndEnergy(numTorsionTorsions, posData,
504
                                                                                         particle1, particle2, particle3, particle4, particle5,
505
                                                                                         chiralCheckAtom, gridIndices, torsionTorsionGrids, forceData);
506
507
508
    return static_cast<double>(energy);
}

509
510
511
512
/* -------------------------------------------------------------------------- *
 *                             AmoebaMultipole                                *
 * -------------------------------------------------------------------------- */

513
ReferenceCalcAmoebaMultipoleForceKernel::ReferenceCalcAmoebaMultipoleForceKernel(std::string name, const Platform& platform, const System& system) : 
514
515
         CalcAmoebaMultipoleForceKernel(name, platform), system(system), numMultipoles(0), mutualInducedMaxIterations(60), mutualInducedTargetEpsilon(1.0e-03),
                                                         usePme(false),alphaEwald(0.0), cutoffDistance(1.0) {  
516

517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
}

ReferenceCalcAmoebaMultipoleForceKernel::~ReferenceCalcAmoebaMultipoleForceKernel() {
}

void ReferenceCalcAmoebaMultipoleForceKernel::initialize(const System& system, const AmoebaMultipoleForce& force) {

    numMultipoles   = force.getNumMultipoles();

    charges.resize(numMultipoles);
    dipoles.resize(3*numMultipoles);
    quadrupoles.resize(9*numMultipoles);
    tholes.resize(numMultipoles);
    dampingFactors.resize(numMultipoles);
    polarity.resize(numMultipoles);
    axisTypes.resize(numMultipoles);
533
534
535
    multipoleAtomZs.resize(numMultipoles);
    multipoleAtomXs.resize(numMultipoles);
    multipoleAtomYs.resize(numMultipoles);
536
537
538
539
540
    multipoleAtomCovalentInfo.resize(numMultipoles);

    int dipoleIndex      = 0;
    int quadrupoleIndex  = 0;
    double totalCharge   = 0.0;
541
    for (int ii = 0; ii < numMultipoles; ii++) {
542
543
544

        // multipoles

545
        int axisType, multipoleAtomZ, multipoleAtomX, multipoleAtomY;
546
547
548
        double charge, tholeD, dampingFactorD, polarityD;
        std::vector<double> dipolesD;
        std::vector<double> quadrupolesD;
549
        force.getMultipoleParameters(ii, charge, dipolesD, quadrupolesD, axisType, multipoleAtomZ, multipoleAtomX, multipoleAtomY,
550
                                     tholeD, dampingFactorD, polarityD);
551
552
553

        totalCharge                       += charge;
        axisTypes[ii]                      = axisType;
554
555
556
        multipoleAtomZs[ii]                = multipoleAtomZ;
        multipoleAtomXs[ii]                = multipoleAtomX;
        multipoleAtomYs[ii]                = multipoleAtomY;
557

peastman's avatar
peastman committed
558
559
560
561
        charges[ii]                        = charge;
        tholes[ii]                         = tholeD;
        dampingFactors[ii]                 = dampingFactorD;
        polarity[ii]                       = polarityD;
562

peastman's avatar
peastman committed
563
564
565
        dipoles[dipoleIndex++]             = dipolesD[0];
        dipoles[dipoleIndex++]             = dipolesD[1];
        dipoles[dipoleIndex++]             = dipolesD[2];
566
        
peastman's avatar
peastman committed
567
568
569
570
571
572
573
574
575
        quadrupoles[quadrupoleIndex++]     = quadrupolesD[0];
        quadrupoles[quadrupoleIndex++]     = quadrupolesD[1];
        quadrupoles[quadrupoleIndex++]     = quadrupolesD[2];
        quadrupoles[quadrupoleIndex++]     = quadrupolesD[3];
        quadrupoles[quadrupoleIndex++]     = quadrupolesD[4];
        quadrupoles[quadrupoleIndex++]     = quadrupolesD[5];
        quadrupoles[quadrupoleIndex++]     = quadrupolesD[6];
        quadrupoles[quadrupoleIndex++]     = quadrupolesD[7];
        quadrupoles[quadrupoleIndex++]     = quadrupolesD[8];
576
577
578
579

        // covalent info

        std::vector< std::vector<int> > covalentLists;
580
        force.getCovalentMaps(ii, covalentLists);
581
582
583
584
        multipoleAtomCovalentInfo[ii] = covalentLists;

    }

585
    polarizationType = force.getPolarizationType();
586
    if (polarizationType == AmoebaMultipoleForce::Mutual) {
587
588
        mutualInducedMaxIterations = force.getMutualInducedMaxIterations();
        mutualInducedTargetEpsilon = force.getMutualInducedTargetEpsilon();
589
590
    } else if (polarizationType == AmoebaMultipoleForce::Extrapolated) {
        extrapolationCoefficients = force.getExtrapolationCoefficients();
591
    }
592

593
594
595
    // PME

    nonbondedMethod  = force.getNonbondedMethod();
596
    if (nonbondedMethod == AmoebaMultipoleForce::PME) {
597
        usePme     = true;
peastman's avatar
peastman committed
598
599
        pmeGridDimension.resize(3);
        force.getPMEParameters(alphaEwald, pmeGridDimension[0], pmeGridDimension[1], pmeGridDimension[2]);
600
601
602
603
604
605
        cutoffDistance = force.getCutoffDistance();
        if (pmeGridDimension[0] == 0 || alphaEwald == 0.0) {
            NonbondedForce nb;
            nb.setEwaldErrorTolerance(force.getEwaldErrorTolerance());
            nb.setCutoffDistance(force.getCutoffDistance());
            int gridSizeX, gridSizeY, gridSizeZ;
606
            NonbondedForceImpl::calcPMEParameters(system, nb, alphaEwald, gridSizeX, gridSizeY, gridSizeZ, false);
607
608
609
610
611
612
613
614
            pmeGridDimension[0] = gridSizeX;
            pmeGridDimension[1] = gridSizeY;
            pmeGridDimension[2] = gridSizeZ;
        }    
    } else {
        usePme = false;
    }
    return;
615
616
}

617
AmoebaReferenceMultipoleForce* ReferenceCalcAmoebaMultipoleForceKernel::setupAmoebaReferenceMultipoleForce(ContextImpl& context)
618
{
619

620
621
622
623
624
    // amoebaReferenceMultipoleForce is set to AmoebaReferenceGeneralizedKirkwoodForce if AmoebaGeneralizedKirkwoodForce is present
    // amoebaReferenceMultipoleForce is set to AmoebaReferencePmeMultipoleForce if 'usePme' is set
    // amoebaReferenceMultipoleForce is set to AmoebaReferenceMultipoleForce otherwise

    // check if AmoebaGeneralizedKirkwoodForce is present 
625

626
627
628
629
630
631
632
633
634
    ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel* gkKernel = NULL;
    for (unsigned int ii = 0; ii < context.getForceImpls().size() && gkKernel == NULL; ii++) {
        AmoebaGeneralizedKirkwoodForceImpl* gkImpl = dynamic_cast<AmoebaGeneralizedKirkwoodForceImpl*>(context.getForceImpls()[ii]);
        if (gkImpl != NULL) {
            gkKernel = dynamic_cast<ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel*>(&gkImpl->getKernel().getImpl());
        }
    }    

    AmoebaReferenceMultipoleForce* amoebaReferenceMultipoleForce = NULL;
635
    if (gkKernel) {
636
637
638
639
640

        // amoebaReferenceGeneralizedKirkwoodForce is deleted in AmoebaReferenceGeneralizedKirkwoodMultipoleForce
        // destructor

        AmoebaReferenceGeneralizedKirkwoodForce* amoebaReferenceGeneralizedKirkwoodForce = new AmoebaReferenceGeneralizedKirkwoodForce();
641
642
643
644
645
646
647
648
        amoebaReferenceGeneralizedKirkwoodForce->setNumParticles(gkKernel->getNumParticles());
        amoebaReferenceGeneralizedKirkwoodForce->setSoluteDielectric(gkKernel->getSoluteDielectric());
        amoebaReferenceGeneralizedKirkwoodForce->setSolventDielectric(gkKernel->getSolventDielectric());
        amoebaReferenceGeneralizedKirkwoodForce->setDielectricOffset(gkKernel->getDielectricOffset());
        amoebaReferenceGeneralizedKirkwoodForce->setProbeRadius(gkKernel->getProbeRadius());
        amoebaReferenceGeneralizedKirkwoodForce->setSurfaceAreaFactor(gkKernel->getSurfaceAreaFactor());
        amoebaReferenceGeneralizedKirkwoodForce->setIncludeCavityTerm(gkKernel->getIncludeCavityTerm());
        amoebaReferenceGeneralizedKirkwoodForce->setDirectPolarization(gkKernel->getDirectPolarization());
649

peastman's avatar
peastman committed
650
        vector<double> parameters; 
651
652
        gkKernel->getAtomicRadii(parameters);
        amoebaReferenceGeneralizedKirkwoodForce->setAtomicRadii(parameters);
653

654
655
        gkKernel->getScaleFactors(parameters);
        amoebaReferenceGeneralizedKirkwoodForce->setScaleFactors(parameters);
656

657
658
        gkKernel->getCharges(parameters);
        amoebaReferenceGeneralizedKirkwoodForce->setCharges(parameters);
659
660
661

        // calculate Grycuk Born radii

peastman's avatar
peastman committed
662
        vector<Vec3>& posData   = extractPositions(context);
663
        amoebaReferenceGeneralizedKirkwoodForce->calculateGrycukBornRadii(posData);
664

665
        amoebaReferenceMultipoleForce = new AmoebaReferenceGeneralizedKirkwoodMultipoleForce(amoebaReferenceGeneralizedKirkwoodForce);
666

667
    } else if (usePme) {
668

669
670
671
672
        AmoebaReferencePmeMultipoleForce* amoebaReferencePmeMultipoleForce = new AmoebaReferencePmeMultipoleForce();
        amoebaReferencePmeMultipoleForce->setAlphaEwald(alphaEwald);
        amoebaReferencePmeMultipoleForce->setCutoffDistance(cutoffDistance);
        amoebaReferencePmeMultipoleForce->setPmeGridDimensions(pmeGridDimension);
peastman's avatar
peastman committed
673
        Vec3* boxVectors = extractBoxVectors(context);
674
        double minAllowedSize = 1.999999*cutoffDistance;
675
        if (boxVectors[0][0] < minAllowedSize || boxVectors[1][1] < minAllowedSize || boxVectors[2][2] < minAllowedSize) {
676
            throw OpenMMException("The periodic box size has decreased to less than twice the nonbonded cutoff.");
677
678
679
        }
        amoebaReferencePmeMultipoleForce->setPeriodicBoxSize(boxVectors);
        amoebaReferenceMultipoleForce = static_cast<AmoebaReferenceMultipoleForce*>(amoebaReferencePmeMultipoleForce);
680

681
    } else {
682
         amoebaReferenceMultipoleForce = new AmoebaReferenceMultipoleForce(AmoebaReferenceMultipoleForce::NoCutoff);
683
684
    }

685
686
    // set polarization type

687
688
689
690
691
692
    if (polarizationType == AmoebaMultipoleForce::Mutual) {
        amoebaReferenceMultipoleForce->setPolarizationType(AmoebaReferenceMultipoleForce::Mutual);
        amoebaReferenceMultipoleForce->setMutualInducedDipoleTargetEpsilon(mutualInducedTargetEpsilon);
        amoebaReferenceMultipoleForce->setMaximumMutualInducedDipoleIterations(mutualInducedMaxIterations);
    } else if (polarizationType == AmoebaMultipoleForce::Direct) {
        amoebaReferenceMultipoleForce->setPolarizationType(AmoebaReferenceMultipoleForce::Direct);
693
694
695
    } else if (polarizationType == AmoebaMultipoleForce::Extrapolated) {
        amoebaReferenceMultipoleForce->setPolarizationType(AmoebaReferenceMultipoleForce::Extrapolated);
        amoebaReferenceMultipoleForce->setExtrapolationCoefficients(extrapolationCoefficients);
696
    } else {
697
        throw OpenMMException("Polarization type not recognzied.");
698
699
    }

700
701
702
703
704
705
    return amoebaReferenceMultipoleForce;

}

double ReferenceCalcAmoebaMultipoleForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {

706
    AmoebaReferenceMultipoleForce* amoebaReferenceMultipoleForce = setupAmoebaReferenceMultipoleForce(context);
707

peastman's avatar
peastman committed
708
709
710
711
712
713
    vector<Vec3>& posData = extractPositions(context);
    vector<Vec3>& forceData = extractForces(context);
    double energy = amoebaReferenceMultipoleForce->calculateForceAndEnergy(posData, charges, dipoles, quadrupoles, tholes,
                                                                           dampingFactors, polarity, axisTypes, 
                                                                           multipoleAtomZs, multipoleAtomXs, multipoleAtomYs,
                                                                           multipoleAtomCovalentInfo, forceData);
714

715
    delete amoebaReferenceMultipoleForce;
716
717
718
719

    return static_cast<double>(energy);
}

720
721
722
723
724
725
void ReferenceCalcAmoebaMultipoleForceKernel::getInducedDipoles(ContextImpl& context, vector<Vec3>& outputDipoles) {
    int numParticles = context.getSystem().getNumParticles();
    outputDipoles.resize(numParticles);

    // Create an AmoebaReferenceMultipoleForce to do the calculation.
    
726
    AmoebaReferenceMultipoleForce* amoebaReferenceMultipoleForce = setupAmoebaReferenceMultipoleForce(context);
peastman's avatar
peastman committed
727
    vector<Vec3>& posData = extractPositions(context);
728
729
730
    
    // Retrieve the induced dipoles.
    
peastman's avatar
peastman committed
731
    vector<Vec3> inducedDipoles;
732
733
734
735
736
737
738
    amoebaReferenceMultipoleForce->calculateInducedDipoles(posData, charges, dipoles, quadrupoles, tholes,
            dampingFactors, polarity, axisTypes, multipoleAtomZs, multipoleAtomXs, multipoleAtomYs, multipoleAtomCovalentInfo, inducedDipoles);
    for (int i = 0; i < numParticles; i++)
        outputDipoles[i] = inducedDipoles[i];
    delete amoebaReferenceMultipoleForce;
}

739
740
741
742
743
744
745
void ReferenceCalcAmoebaMultipoleForceKernel::getLabFramePermanentDipoles(ContextImpl& context, vector<Vec3>& outputDipoles) {
    int numParticles = context.getSystem().getNumParticles();
    outputDipoles.resize(numParticles);

    // Create an AmoebaReferenceMultipoleForce to do the calculation.
    
    AmoebaReferenceMultipoleForce* amoebaReferenceMultipoleForce = setupAmoebaReferenceMultipoleForce(context);
peastman's avatar
peastman committed
746
    vector<Vec3>& posData = extractPositions(context);
747
748
749
    
    // Retrieve the permanent dipoles in the lab frame.
    
peastman's avatar
peastman committed
750
    vector<Vec3> labFramePermanentDipoles;
751
752
753
754
755
756
    amoebaReferenceMultipoleForce->calculateLabFramePermanentDipoles(posData, charges, dipoles, quadrupoles, tholes, 
            dampingFactors, polarity, axisTypes, multipoleAtomZs, multipoleAtomXs, multipoleAtomYs, multipoleAtomCovalentInfo, labFramePermanentDipoles);
    for (int i = 0; i < numParticles; i++)
        outputDipoles[i] = labFramePermanentDipoles[i];
    delete amoebaReferenceMultipoleForce;
}
757
758


759
760
761
762
763
764
765
void ReferenceCalcAmoebaMultipoleForceKernel::getTotalDipoles(ContextImpl& context, vector<Vec3>& outputDipoles) {
    int numParticles = context.getSystem().getNumParticles();
    outputDipoles.resize(numParticles);

    // Create an AmoebaReferenceMultipoleForce to do the calculation.
    
    AmoebaReferenceMultipoleForce* amoebaReferenceMultipoleForce = setupAmoebaReferenceMultipoleForce(context);
peastman's avatar
peastman committed
766
    vector<Vec3>& posData = extractPositions(context);
767
768
769
    
    // Retrieve the permanent dipoles in the lab frame.
    
peastman's avatar
peastman committed
770
    vector<Vec3> totalDipoles;
771
    amoebaReferenceMultipoleForce->calculateTotalDipoles(posData, charges, dipoles, quadrupoles, tholes,
772
            dampingFactors, polarity, axisTypes, multipoleAtomZs, multipoleAtomXs, multipoleAtomYs, multipoleAtomCovalentInfo, totalDipoles);
773
774
775
776
777
778
779

    for (int i = 0; i < numParticles; i++)
        outputDipoles[i] = totalDipoles[i];
    delete amoebaReferenceMultipoleForce;
}


780

781
void ReferenceCalcAmoebaMultipoleForceKernel::getElectrostaticPotential(ContextImpl& context, const std::vector< Vec3 >& inputGrid,
782
                                                                        std::vector< double >& outputElectrostaticPotential) {
783

784
    AmoebaReferenceMultipoleForce* amoebaReferenceMultipoleForce = setupAmoebaReferenceMultipoleForce(context);
peastman's avatar
peastman committed
785
786
787
    vector<Vec3>& posData                                     = extractPositions(context);
    vector<Vec3> grid(inputGrid.size());
    vector<double> potential(inputGrid.size());
788
    for (unsigned int ii = 0; ii < inputGrid.size(); ii++) {
789
790
        grid[ii] = inputGrid[ii];
    }
791
792
793
794
    amoebaReferenceMultipoleForce->calculateElectrostaticPotential(posData, charges, dipoles, quadrupoles, tholes,
                                                                   dampingFactors, polarity, axisTypes, 
                                                                   multipoleAtomZs, multipoleAtomXs, multipoleAtomYs,
                                                                   multipoleAtomCovalentInfo, grid, potential);
795

796
797
    outputElectrostaticPotential.resize(inputGrid.size());
    for (unsigned int ii = 0; ii < inputGrid.size(); ii++) {
798
799
800
801
        outputElectrostaticPotential[ii] = potential[ii];
    }

    delete amoebaReferenceMultipoleForce;
802
803
}

804
void ReferenceCalcAmoebaMultipoleForceKernel::getSystemMultipoleMoments(ContextImpl& context, std::vector< double >& outputMultipoleMoments) {
805
806
807

    // retrieve masses

808
    const System& system             = context.getSystem();
peastman's avatar
peastman committed
809
    vector<double> masses;
810
    for (int i = 0; i <  system.getNumParticles(); ++i) {
peastman's avatar
peastman committed
811
        masses.push_back(system.getParticleMass(i));
812
813
    }    

814
    AmoebaReferenceMultipoleForce* amoebaReferenceMultipoleForce = setupAmoebaReferenceMultipoleForce(context);
peastman's avatar
peastman committed
815
    vector<Vec3>& posData                                     = extractPositions(context);
816
817
818
819
    amoebaReferenceMultipoleForce->calculateAmoebaSystemMultipoleMoments(masses, posData, charges, dipoles, quadrupoles, tholes,
                                                                         dampingFactors, polarity, axisTypes, 
                                                                         multipoleAtomZs, multipoleAtomXs, multipoleAtomYs,
                                                                         multipoleAtomCovalentInfo, outputMultipoleMoments);
820
821

    delete amoebaReferenceMultipoleForce;
822
823
}

824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
void ReferenceCalcAmoebaMultipoleForceKernel::copyParametersToContext(ContextImpl& context, const AmoebaMultipoleForce& force) {
    if (numMultipoles != force.getNumMultipoles())
        throw OpenMMException("updateParametersInContext: The number of multipoles has changed");

    // Record the values.

    int dipoleIndex = 0;
    int quadrupoleIndex = 0;
    for (int i = 0; i < numMultipoles; ++i) {
        int axisType, multipoleAtomZ, multipoleAtomX, multipoleAtomY;
        double charge, tholeD, dampingFactorD, polarityD;
        std::vector<double> dipolesD;
        std::vector<double> quadrupolesD;
        force.getMultipoleParameters(i, charge, dipolesD, quadrupolesD, axisType, multipoleAtomZ, multipoleAtomX, multipoleAtomY, tholeD, dampingFactorD, polarityD);
        axisTypes[i] = axisType;
        multipoleAtomZs[i] = multipoleAtomZ;
        multipoleAtomXs[i] = multipoleAtomX;
        multipoleAtomYs[i] = multipoleAtomY;
peastman's avatar
peastman committed
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
        charges[i] = charge;
        tholes[i] = tholeD;
        dampingFactors[i] = dampingFactorD;
        polarity[i] = polarityD;
        dipoles[dipoleIndex++] = dipolesD[0];
        dipoles[dipoleIndex++] = dipolesD[1];
        dipoles[dipoleIndex++] = dipolesD[2];
        quadrupoles[quadrupoleIndex++] = quadrupolesD[0];
        quadrupoles[quadrupoleIndex++] = quadrupolesD[1];
        quadrupoles[quadrupoleIndex++] = quadrupolesD[2];
        quadrupoles[quadrupoleIndex++] = quadrupolesD[3];
        quadrupoles[quadrupoleIndex++] = quadrupolesD[4];
        quadrupoles[quadrupoleIndex++] = quadrupolesD[5];
        quadrupoles[quadrupoleIndex++] = quadrupolesD[6];
        quadrupoles[quadrupoleIndex++] = quadrupolesD[7];
        quadrupoles[quadrupoleIndex++] = quadrupolesD[8];
858
859
860
    }
}

861
862
863
864
865
866
867
868
869
void ReferenceCalcAmoebaMultipoleForceKernel::getPMEParameters(double& alpha, int& nx, int& ny, int& nz) const {
    if (!usePme)
        throw OpenMMException("getPMEParametersInContext: This Context is not using PME");
    alpha = alphaEwald;
    nx = pmeGridDimension[0];
    ny = pmeGridDimension[1];
    nz = pmeGridDimension[2];
}

870
871
872
873
/* -------------------------------------------------------------------------- *
 *                       AmoebaGeneralizedKirkwood                            *
 * -------------------------------------------------------------------------- */

874
ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel(std::string name, const Platform& platform, const System& system) : 
875
876
877
878
879
880
           CalcAmoebaGeneralizedKirkwoodForceKernel(name, platform), system(system) {
}

ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::~ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel() {
}

881
int ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getNumParticles() const {
882
883
884
    return numParticles;
}

885
int ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getIncludeCavityTerm() const {
886
887
888
    return includeCavityTerm;
}

889
int ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getDirectPolarization() const {
890
891
892
    return directPolarization;
}

peastman's avatar
peastman committed
893
double ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getSoluteDielectric() const {
894
895
896
    return soluteDielectric;
}

peastman's avatar
peastman committed
897
double ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getSolventDielectric() const {
898
899
900
    return solventDielectric;
}

peastman's avatar
peastman committed
901
double ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getDielectricOffset() const {
902
903
904
    return dielectricOffset;
}

peastman's avatar
peastman committed
905
double ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getProbeRadius() const {
906
907
908
    return probeRadius;
}

peastman's avatar
peastman committed
909
double ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getSurfaceAreaFactor() const {
910
911
912
    return surfaceAreaFactor;
}

peastman's avatar
peastman committed
913
void ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getAtomicRadii(vector<double>& outputAtomicRadii) const {
914
915
    outputAtomicRadii.resize(atomicRadii.size());
    copy(atomicRadii.begin(), atomicRadii.end(), outputAtomicRadii.begin());
916
917
}

peastman's avatar
peastman committed
918
void ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getScaleFactors(vector<double>& outputScaleFactors) const {
919
920
    outputScaleFactors.resize(scaleFactors.size());
    copy(scaleFactors.begin(), scaleFactors.end(), outputScaleFactors.begin());
921
922
}

peastman's avatar
peastman committed
923
void ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getCharges(vector<double>& outputCharges) const {
924
925
    outputCharges.resize(charges.size());
    copy(charges.begin(), charges.end(), outputCharges.begin());
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
}

void ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::initialize(const System& system, const AmoebaGeneralizedKirkwoodForce& force) {

    // check that AmoebaMultipoleForce is present

    const AmoebaMultipoleForce* amoebaMultipoleForce = NULL;
    for (int ii = 0; ii < system.getNumForces() && amoebaMultipoleForce == NULL; ii++) {
        amoebaMultipoleForce = dynamic_cast<const AmoebaMultipoleForce*>(&system.getForce(ii));
    }

    if (amoebaMultipoleForce == NULL) {
        throw OpenMMException("AmoebaGeneralizedKirkwoodForce requires the System to also contain an AmoebaMultipoleForce.");
    }

941
    if (amoebaMultipoleForce->getNonbondedMethod() != AmoebaMultipoleForce::NoCutoff) {
942
943
944
945
946
        throw OpenMMException("AmoebaGeneralizedKirkwoodForce requires the AmoebaMultipoleForce use the NoCutoff nonbonded method.");
    }

    numParticles = system.getNumParticles();

947
    for (int ii = 0; ii < numParticles; ii++) {
948
949
950

        double particleCharge, particleRadius, scalingFactor;
        force.getParticleParameters(ii, particleCharge, particleRadius, scalingFactor);
peastman's avatar
peastman committed
951
952
953
        atomicRadii.push_back(particleRadius);
        scaleFactors.push_back(scalingFactor);
        charges.push_back(particleCharge);
954
955
956
957
958
959

        // Make sure the charge matches the one specified by the AmoebaMultipoleForce.

        double charge2, thole, damping, polarity;
        int axisType, atomX, atomY, atomZ;
        vector<double> dipole, quadrupole;
960
961
        amoebaMultipoleForce->getMultipoleParameters(ii, charge2, dipole, quadrupole, axisType, atomZ, atomX, atomY, thole, damping, polarity);
        if (particleCharge != charge2) {
962
963
964
965
966
            throw OpenMMException("AmoebaGeneralizedKirkwoodForce and AmoebaMultipoleForce must specify the same charge for every atom.");
        }

    }   
    includeCavityTerm  = force.getIncludeCavityTerm();
peastman's avatar
peastman committed
967
968
969
970
971
    soluteDielectric   = force.getSoluteDielectric();
    solventDielectric  = force.getSolventDielectric();
    dielectricOffset   = 0.009;
    probeRadius        = force.getProbeRadius(), 
    surfaceAreaFactor  = force.getSurfaceAreaFactor(); 
972
973
974
975
976
977
978
    directPolarization = amoebaMultipoleForce->getPolarizationType() == AmoebaMultipoleForce::Direct ? 1 : 0;
}

double ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
    // handled in AmoebaReferenceGeneralizedKirkwoodMultipoleForce, a derived class of the class AmoebaReferenceMultipoleForce
    return 0.0;
}
Mark Friedrichs's avatar
Mark Friedrichs committed
979

980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
void ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::copyParametersToContext(ContextImpl& context, const AmoebaGeneralizedKirkwoodForce& force) {
    if (numParticles != force.getNumParticles())
        throw OpenMMException("updateParametersInContext: The number of particles has changed");

    // Record the values.

    for (int i = 0; i < numParticles; ++i) {
        double particleCharge, particleRadius, scalingFactor;
        force.getParticleParameters(i, particleCharge, particleRadius, scalingFactor);
        atomicRadii[i] = particleRadius;
        scaleFactors[i] = scalingFactor;
        charges[i] = particleCharge;
    }
}

995
ReferenceCalcAmoebaVdwForceKernel::ReferenceCalcAmoebaVdwForceKernel(std::string name, const Platform& platform, const System& system) :
Mark Friedrichs's avatar
Mark Friedrichs committed
996
       CalcAmoebaVdwForceKernel(name, platform), system(system) {
997
    useCutoff = 0;
998
    usePBC = 0;
999
1000
1001
    alchemicalMethod = 0;
    n = 5;
    alpha = 0.7;
1002
    cutoff = 1.0e+10;
1003
    neighborList = NULL;
Mark Friedrichs's avatar
Mark Friedrichs committed
1004
1005
1006
}

ReferenceCalcAmoebaVdwForceKernel::~ReferenceCalcAmoebaVdwForceKernel() {
1007
    if (neighborList) {
1008
1009
        delete neighborList;
    } 
Mark Friedrichs's avatar
Mark Friedrichs committed
1010
1011
1012
1013
1014
1015
1016
1017
}

void ReferenceCalcAmoebaVdwForceKernel::initialize(const System& system, const AmoebaVdwForce& force) {

    // per-particle parameters

    numParticles = system.getNumParticles();

1018
1019
1020
1021
1022
    indexIVs.resize(numParticles);
    allExclusions.resize(numParticles);
    sigmas.resize(numParticles);
    epsilons.resize(numParticles);
    reductions.resize(numParticles);
1023
    isAlchemical.resize(numParticles);
Mark Friedrichs's avatar
Mark Friedrichs committed
1024

1025
    for (int ii = 0; ii < numParticles; ii++) {
Mark Friedrichs's avatar
Mark Friedrichs committed
1026

1027
        int indexIV;
Mark Friedrichs's avatar
Mark Friedrichs committed
1028
        double sigma, epsilon, reduction;
1029
        bool alchemical;
Mark Friedrichs's avatar
Mark Friedrichs committed
1030
1031
        std::vector<int> exclusions;

1032
        force.getParticleParameters(ii, indexIV, sigma, epsilon, reduction, alchemical);
1033
1034
1035
        force.getParticleExclusions(ii, exclusions);
        for (unsigned int jj = 0; jj < exclusions.size(); jj++) {
           allExclusions[ii].insert(exclusions[jj]);
Mark Friedrichs's avatar
Mark Friedrichs committed
1036
1037
1038
        }

        indexIVs[ii]      = indexIV;
peastman's avatar
peastman committed
1039
1040
1041
        sigmas[ii]        = sigma;
        epsilons[ii]      = epsilon;
        reductions[ii]    = reduction;
1042
        isAlchemical[ii]  = alchemical;
Mark Friedrichs's avatar
Mark Friedrichs committed
1043
    }   
1044
1045
1046
1047
    sigmaCombiningRule     = force.getSigmaCombiningRule();
    epsilonCombiningRule   = force.getEpsilonCombiningRule();
    useCutoff              = (force.getNonbondedMethod() != AmoebaVdwForce::NoCutoff);
    usePBC                 = (force.getNonbondedMethod() == AmoebaVdwForce::CutoffPeriodic);
peastman's avatar
peastman committed
1048
    cutoff                 = force.getCutoffDistance();
1049
1050
    neighborList           = useCutoff ? new NeighborList() : NULL;
    dispersionCoefficient  = force.getUseDispersionCorrection() ?  AmoebaVdwForceImpl::calcDispersionCorrection(system, force) : 0.0;
1051
1052
1053
    alchemicalMethod       = (int) force.getAlchemicalMethod();
    n                      = force.getSoftcorePower();
    alpha                  = force.getSoftcoreAlpha();
Mark Friedrichs's avatar
Mark Friedrichs committed
1054
1055
1056
1057
}

double ReferenceCalcAmoebaVdwForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {

peastman's avatar
peastman committed
1058
1059
    vector<Vec3>& posData   = extractPositions(context);
    vector<Vec3>& forceData = extractForces(context);
1060
    AmoebaReferenceVdwForce vdwForce(sigmaCombiningRule, epsilonCombiningRule);
peastman's avatar
peastman committed
1061
    double energy;
1062
    double lambda = context.getParameter(AmoebaVdwForce::Lambda());
1063
1064
1065
1066
1067
    if (useCutoff) {
        vdwForce.setCutoff(cutoff);
        computeNeighborListVoxelHash(*neighborList, numParticles, posData, allExclusions, extractBoxVectors(context), usePBC, cutoff, 0.0);
        if (usePBC) {
            vdwForce.setNonbondedMethod(AmoebaReferenceVdwForce::CutoffPeriodic);
peastman's avatar
peastman committed
1068
            Vec3* boxVectors = extractBoxVectors(context);
1069
            double minAllowedSize = 1.999999*cutoff;
1070
            if (boxVectors[0][0] < minAllowedSize || boxVectors[1][1] < minAllowedSize || boxVectors[2][2] < minAllowedSize) {
1071
1072
                throw OpenMMException("The periodic box size has decreased to less than twice the cutoff.");
            }
1073
            vdwForce.setPeriodicBox(boxVectors);
1074
1075
            energy  = vdwForce.calculateForceAndEnergy(numParticles, lambda, posData, indexIVs, sigmas, epsilons, 
                                                       reductions, isAlchemical, *neighborList, forceData);
1076
            energy += dispersionCoefficient/(boxVectors[0][0]*boxVectors[1][1]*boxVectors[2][2]);
1077
        } else {
1078
            vdwForce.setNonbondedMethod(AmoebaReferenceVdwForce::CutoffNonPeriodic);
1079
1080
        }
    } else {
1081
        vdwForce.setNonbondedMethod(AmoebaReferenceVdwForce::NoCutoff);
1082
1083
        energy = vdwForce.calculateForceAndEnergy(numParticles, lambda, posData, indexIVs, sigmas, epsilons, 
                                                  reductions, isAlchemical, allExclusions, forceData);
1084
    }
Mark Friedrichs's avatar
Mark Friedrichs committed
1085
1086
1087
    return static_cast<double>(energy);
}

1088
1089
1090
1091
1092
1093
1094
1095
1096
void ReferenceCalcAmoebaVdwForceKernel::copyParametersToContext(ContextImpl& context, const AmoebaVdwForce& force) {
    if (numParticles != force.getNumParticles())
        throw OpenMMException("updateParametersInContext: The number of particles has changed");

    // Record the values.

    for (int i = 0; i < numParticles; ++i) {
        int indexIV;
        double sigma, epsilon, reduction;
1097
1098
        bool alchemical;
        force.getParticleParameters(i, indexIV, sigma, epsilon, reduction, alchemical);
1099
        indexIVs[i] = indexIV;
peastman's avatar
peastman committed
1100
1101
1102
        sigmas[i] = sigma;
        epsilons[i] = epsilon;
        reductions[i]= reduction;
1103
        isAlchemical[i]= alchemical;
1104
1105
1106
    }
}

Mark Friedrichs's avatar
Mark Friedrichs committed
1107
1108
1109
1110
/* -------------------------------------------------------------------------- *
 *                           AmoebaWcaDispersion                              *
 * -------------------------------------------------------------------------- */

1111
ReferenceCalcAmoebaWcaDispersionForceKernel::ReferenceCalcAmoebaWcaDispersionForceKernel(std::string name, const Platform& platform, const System& system) : 
Mark Friedrichs's avatar
Mark Friedrichs committed
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
           CalcAmoebaWcaDispersionForceKernel(name, platform), system(system) {
}

ReferenceCalcAmoebaWcaDispersionForceKernel::~ReferenceCalcAmoebaWcaDispersionForceKernel() {
}

void ReferenceCalcAmoebaWcaDispersionForceKernel::initialize(const System& system, const AmoebaWcaDispersionForce& force) {

    // per-particle parameters

    numParticles = system.getNumParticles();
    radii.resize(numParticles);
    epsilons.resize(numParticles);
1125
    for (int ii = 0; ii < numParticles; ii++) {
Mark Friedrichs's avatar
Mark Friedrichs committed
1126
1127

        double radius, epsilon;
1128
        force.getParticleParameters(ii, radius, epsilon);
Mark Friedrichs's avatar
Mark Friedrichs committed
1129

peastman's avatar
peastman committed
1130
1131
        radii[ii] = radius;
        epsilons[ii] = epsilon;
Mark Friedrichs's avatar
Mark Friedrichs committed
1132
1133
    }   

peastman's avatar
peastman committed
1134
    totalMaximumDispersionEnergy = AmoebaWcaDispersionForceImpl::getTotalMaximumDispersionEnergy(force);
Mark Friedrichs's avatar
Mark Friedrichs committed
1135

peastman's avatar
peastman committed
1136
1137
1138
1139
1140
1141
1142
1143
    epso    = force.getEpso();
    epsh    = force.getEpsh();
    rmino   = force.getRmino();
    rminh   = force.getRminh();
    awater  = force.getAwater();
    shctd   = force.getShctd();
    dispoff = force.getDispoff();
    slevy   = force.getSlevy();
Mark Friedrichs's avatar
Mark Friedrichs committed
1144
1145
1146
}

double ReferenceCalcAmoebaWcaDispersionForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
peastman's avatar
peastman committed
1147
1148
    vector<Vec3>& posData = extractPositions(context);
    vector<Vec3>& forceData = extractForces(context);
1149
    AmoebaReferenceWcaDispersionForce amoebaReferenceWcaDispersionForce(epso, epsh, rmino, rminh, awater, shctd, dispoff, slevy);
peastman's avatar
peastman committed
1150
    double energy = amoebaReferenceWcaDispersionForce.calculateForceAndEnergy(numParticles, posData, radii, epsilons, totalMaximumDispersionEnergy, forceData);
Mark Friedrichs's avatar
Mark Friedrichs committed
1151
1152
    return static_cast<double>(energy);
}
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162

void ReferenceCalcAmoebaWcaDispersionForceKernel::copyParametersToContext(ContextImpl& context, const AmoebaWcaDispersionForce& force) {
    if (numParticles != force.getNumParticles())
        throw OpenMMException("updateParametersInContext: The number of particles has changed");

    // Record the values.

    for (int i = 0; i < numParticles; ++i) {
        double radius, epsilon;
        force.getParticleParameters(i, radius, epsilon);
peastman's avatar
peastman committed
1163
1164
        radii[i] = radius;
        epsilons[i] = epsilon;
1165
    }
peastman's avatar
peastman committed
1166
    totalMaximumDispersionEnergy = AmoebaWcaDispersionForceImpl::getTotalMaximumDispersionEnergy(force);
1167
}
peastman's avatar
peastman committed
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270


/* -------------------------------------------------------------------------- *
 *                              HippoNonbonded                                *
 * -------------------------------------------------------------------------- */

ReferenceCalcHippoNonbondedForceKernel::ReferenceCalcHippoNonbondedForceKernel(std::string name, const Platform& platform, const System& system) : 
         CalcHippoNonbondedForceKernel(name, platform), ixn(NULL) {
}

ReferenceCalcHippoNonbondedForceKernel::~ReferenceCalcHippoNonbondedForceKernel() {
    if (ixn != NULL)
        delete ixn;
}

void ReferenceCalcHippoNonbondedForceKernel::initialize(const System& system, const HippoNonbondedForce& force) {
    numParticles = force.getNumParticles();
    if (force.getNonbondedMethod() == HippoNonbondedForce::PME)
        ixn = new AmoebaReferencePmeHippoNonbondedForce(force, system);
    else
        ixn = new AmoebaReferenceHippoNonbondedForce(force);
}

void ReferenceCalcHippoNonbondedForceKernel::setupAmoebaReferenceHippoNonbondedForce(ContextImpl& context) {
    if (ixn->getNonbondedMethod() == HippoNonbondedForce::PME) {
        AmoebaReferencePmeHippoNonbondedForce* force = dynamic_cast<AmoebaReferencePmeHippoNonbondedForce*>(ixn);
        Vec3* boxVectors = extractBoxVectors(context);
        double minAllowedSize = 1.999999*force->getCutoffDistance();
        if (boxVectors[0][0] < minAllowedSize || boxVectors[1][1] < minAllowedSize || boxVectors[2][2] < minAllowedSize)
            throw OpenMMException("The periodic box size has decreased to less than twice the nonbonded cutoff.");
        force->setPeriodicBoxSize(boxVectors);
    }
}

double ReferenceCalcHippoNonbondedForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {

    setupAmoebaReferenceHippoNonbondedForce(context);

    vector<Vec3>& posData = extractPositions(context);
    vector<Vec3>& forceData = extractForces(context);
    return ixn->calculateForceAndEnergy(posData, forceData);
}

void ReferenceCalcHippoNonbondedForceKernel::getInducedDipoles(ContextImpl& context, vector<Vec3>& outputDipoles) {
    outputDipoles.resize(numParticles);
    setupAmoebaReferenceHippoNonbondedForce(context);
    vector<Vec3>& posData = extractPositions(context);
    
    // Retrieve the induced dipoles.
    
    vector<Vec3> inducedDipoles;
    ixn->calculateInducedDipoles(posData, inducedDipoles);
    for (int i = 0; i < numParticles; i++)
        outputDipoles[i] = inducedDipoles[i];
}

void ReferenceCalcHippoNonbondedForceKernel::getLabFramePermanentDipoles(ContextImpl& context, vector<Vec3>& outputDipoles) {
    outputDipoles.resize(numParticles);
    setupAmoebaReferenceHippoNonbondedForce(context);
    vector<Vec3>& posData = extractPositions(context);
    
    // Retrieve the permanent dipoles in the lab frame.
    
    vector<Vec3> labFramePermanentDipoles;
    ixn->calculateLabFramePermanentDipoles(posData, labFramePermanentDipoles);
    for (int i = 0; i < numParticles; i++)
        outputDipoles[i] = labFramePermanentDipoles[i];
}

void ReferenceCalcHippoNonbondedForceKernel::copyParametersToContext(ContextImpl& context, const HippoNonbondedForce& force) {
    if (numParticles != force.getNumParticles())
        throw OpenMMException("updateParametersInContext: The number of multipoles has changed");
    delete ixn;
    ixn = NULL;
    if (force.getNonbondedMethod() == HippoNonbondedForce::PME)
        ixn = new AmoebaReferencePmeHippoNonbondedForce(force, context.getSystem());
    else
        ixn = new AmoebaReferenceHippoNonbondedForce(force);
}

void ReferenceCalcHippoNonbondedForceKernel::getPMEParameters(double& alpha, int& nx, int& ny, int& nz) const {
    if (ixn->getNonbondedMethod() != HippoNonbondedForce::PME)
        throw OpenMMException("getPMEParametersInContext: This Context is not using PME");
    AmoebaReferencePmeHippoNonbondedForce* force = dynamic_cast<AmoebaReferencePmeHippoNonbondedForce*>(ixn);
    alpha = force->getAlphaEwald();
    vector<int> dim;
    force->getPmeGridDimensions(dim);
    nx = dim[0];
    ny = dim[1];
    nz = dim[2];
}

void ReferenceCalcHippoNonbondedForceKernel::getDPMEParameters(double& alpha, int& nx, int& ny, int& nz) const {
    if (ixn->getNonbondedMethod() != HippoNonbondedForce::PME)
        throw OpenMMException("getDPMEParametersInContext: This Context is not using PME");
    AmoebaReferencePmeHippoNonbondedForce* force = dynamic_cast<AmoebaReferencePmeHippoNonbondedForce*>(ixn);
    alpha = force->getDispersionAlphaEwald();
    vector<int> dim;
    force->getDispersionPmeGridDimensions(dim);
    nx = dim[0];
    ny = dim[1];
    nz = dim[2];
}