"plugins/amoeba/serialization/vscode:/vscode.git/clone" did not exist on "8c8256762b036b4541464e55cfc3a44328a5c1b5"
AmoebaReferenceKernels.cpp 54.9 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
43
#include "openmm/AmoebaMultipoleForce.h"
#include "openmm/internal/AmoebaMultipoleForceImpl.h"
44
#include "openmm/internal/AmoebaVdwForceImpl.h"
45
#include "openmm/internal/AmoebaGeneralizedKirkwoodForceImpl.h"
46
47
#include "openmm/NonbondedForce.h"
#include "openmm/internal/NonbondedForceImpl.h"
48
49
50
51
52
53
54
55
56

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

using namespace OpenMM;
using namespace std;

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

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

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

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

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

82
83
// ***************************************************************************

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

88
ReferenceCalcAmoebaBondForceKernel::~ReferenceCalcAmoebaBondForceKernel() {
89
90
}

91
void ReferenceCalcAmoebaBondForceKernel::initialize(const System& system, const AmoebaBondForce& force) {
92
93

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

        int particle1Index, particle2Index;
        double lengthValue, kValue;
98
        force.getBondParameters(ii, particle1Index, particle2Index, lengthValue, kValue);
99

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

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

122
123
124
125
126
127
128
129
130
131
132
133
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
134
135
        length[i] = lengthValue;
        kQuadratic[i] = kValue;
136
137
138
    }
}

139
140
// ***************************************************************************

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

145
ReferenceCalcAmoebaAngleForceKernel::~ReferenceCalcAmoebaAngleForceKernel() {
146
147
}

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

    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);
156
157
158
        particle1.push_back(particle1Index); 
        particle2.push_back(particle2Index); 
        particle3.push_back(particle3Index); 
peastman's avatar
peastman committed
159
160
        angle.push_back(angleValue);
        kQuadratic.push_back(k);
161
    }
peastman's avatar
peastman committed
162
163
164
165
    globalAngleCubic    = force.getAmoebaGlobalAngleCubic();
    globalAngleQuartic  = force.getAmoebaGlobalAngleQuartic();
    globalAnglePentic   = force.getAmoebaGlobalAnglePentic();
    globalAngleSextic   = force.getAmoebaGlobalAngleSextic();
166
    usePeriodic = force.usesPeriodicBoundaryConditions();
167
168
}

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

180
181
182
183
184
185
186
187
188
189
190
191
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
192
193
        angle[i] = angleValue;
        kQuadratic[i] = k;
194
195
196
    }
}

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

201
ReferenceCalcAmoebaInPlaneAngleForceKernel::~ReferenceCalcAmoebaInPlaneAngleForceKernel() {
202
203
}

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

    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);
211
212
213
214
        particle1.push_back(particle1Index); 
        particle2.push_back(particle2Index); 
        particle3.push_back(particle3Index); 
        particle4.push_back(particle4Index); 
peastman's avatar
peastman committed
215
216
        angle.push_back(angleValue);
        kQuadratic.push_back(k);
217
    }
peastman's avatar
peastman committed
218
219
220
221
    globalInPlaneAngleCubic    = force.getAmoebaGlobalInPlaneAngleCubic();
    globalInPlaneAngleQuartic  = force.getAmoebaGlobalInPlaneAngleQuartic();
    globalInPlaneAnglePentic   = force.getAmoebaGlobalInPlaneAnglePentic();
    globalInPlaneAngleSextic   = force.getAmoebaGlobalInPlaneAngleSextic();
222
    usePeriodic = force.usesPeriodicBoundaryConditions();
223
224
}

225
double ReferenceCalcAmoebaInPlaneAngleForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
226

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

238
239
240
241
242
243
244
245
246
247
248
249
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
250
251
        angle[i] = angleValue;
        kQuadratic[i] = k;
252
253
254
    }
}

255
ReferenceCalcAmoebaPiTorsionForceKernel::ReferenceCalcAmoebaPiTorsionForceKernel(std::string name, const Platform& platform, const System& system) :
256
257
258
259
260
261
262
263
264
265
266
267
268
         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;
269
270
271
272
273
274
275
        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
276
        kTorsion.push_back(kTorsionParameter);
277
    }
278
    usePeriodic = force.usesPeriodicBoundaryConditions();
279
280
281
}

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

293
294
295
296
297
298
299
300
301
302
303
304
305
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
306
        kTorsion[i] = kTorsionParameter;
307
308
309
    }
}

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

ReferenceCalcAmoebaStretchBendForceKernel::~ReferenceCalcAmoebaStretchBendForceKernel() {
}

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

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

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

348
349
350
351
352
353
354
355
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;
356
357
        double lengthAB, lengthCB, angle, k1, k2;
        force.getStretchBendParameters(i, particle1Index, particle2Index, particle3Index, lengthAB, lengthCB, angle, k1, k2);
358
359
        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
360
361
362
363
364
        lengthABParameters[i] = lengthAB;
        lengthCBParameters[i] = lengthCB;
        angleParameters[i] = angle;
        k1Parameters[i] = k1;
        k2Parameters[i] = k2;
365
366
367
    }
}

368
ReferenceCalcAmoebaOutOfPlaneBendForceKernel::ReferenceCalcAmoebaOutOfPlaneBendForceKernel(std::string name, const Platform& platform, const System& system) :
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
          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);
384
385
386
387
        particle1.push_back(particle1Index); 
        particle2.push_back(particle2Index); 
        particle3.push_back(particle3Index); 
        particle4.push_back(particle4Index); 
peastman's avatar
peastman committed
388
        kParameters.push_back(k);
389
    }
peastman's avatar
peastman committed
390
391
392
393
    globalOutOfPlaneBendAngleCubic   = force.getAmoebaGlobalOutOfPlaneBendCubic();
    globalOutOfPlaneBendAngleQuartic = force.getAmoebaGlobalOutOfPlaneBendQuartic();
    globalOutOfPlaneBendAnglePentic  = force.getAmoebaGlobalOutOfPlaneBendPentic();
    globalOutOfPlaneBendAngleSextic  = force.getAmoebaGlobalOutOfPlaneBendSextic();
394
    usePeriodic = force.usesPeriodicBoundaryConditions();
395
396
397
}

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

413
414
415
416
417
418
419
420
421
422
423
424
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
425
        kParameters[i] = k;
426
427
428
    }
}

429
ReferenceCalcAmoebaTorsionTorsionForceKernel::ReferenceCalcAmoebaTorsionTorsionForceKernel(std::string name, const Platform& platform, const System& system) :
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
                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);
446
447
448
449
450
451
452
        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); 
453
    }
454
    usePeriodic = force.usesPeriodicBoundaryConditions();
455
456
457
458
459
460
461

    // torsion-torsion grids

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

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

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

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

474
475
        for (unsigned int kk = 0; kk < grid.size(); kk++) {

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

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

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

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

507
508
509
510
/* -------------------------------------------------------------------------- *
 *                             AmoebaMultipole                                *
 * -------------------------------------------------------------------------- */

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

515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
}

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);
531
532
533
    multipoleAtomZs.resize(numMultipoles);
    multipoleAtomXs.resize(numMultipoles);
    multipoleAtomYs.resize(numMultipoles);
534
535
536
537
538
    multipoleAtomCovalentInfo.resize(numMultipoles);

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

        // multipoles

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

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

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

peastman's avatar
peastman committed
561
562
563
        dipoles[dipoleIndex++]             = dipolesD[0];
        dipoles[dipoleIndex++]             = dipolesD[1];
        dipoles[dipoleIndex++]             = dipolesD[2];
564
        
peastman's avatar
peastman committed
565
566
567
568
569
570
571
572
573
        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];
574
575
576
577

        // covalent info

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

    }

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

591
592
593
    // PME

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

615
AmoebaReferenceMultipoleForce* ReferenceCalcAmoebaMultipoleForceKernel::setupAmoebaReferenceMultipoleForce(ContextImpl& context)
616
{
617

618
619
620
621
622
    // 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 
623

624
625
626
627
628
629
630
631
632
    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;
633
    if (gkKernel) {
634
635
636
637
638

        // amoebaReferenceGeneralizedKirkwoodForce is deleted in AmoebaReferenceGeneralizedKirkwoodMultipoleForce
        // destructor

        AmoebaReferenceGeneralizedKirkwoodForce* amoebaReferenceGeneralizedKirkwoodForce = new AmoebaReferenceGeneralizedKirkwoodForce();
639
640
641
642
643
644
645
646
        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());
647

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

652
653
        gkKernel->getScaleFactors(parameters);
        amoebaReferenceGeneralizedKirkwoodForce->setScaleFactors(parameters);
654

655
656
        gkKernel->getCharges(parameters);
        amoebaReferenceGeneralizedKirkwoodForce->setCharges(parameters);
657
658
659

        // calculate Grycuk Born radii

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

663
        amoebaReferenceMultipoleForce = new AmoebaReferenceGeneralizedKirkwoodMultipoleForce(amoebaReferenceGeneralizedKirkwoodForce);
664

665
    } else if (usePme) {
666

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

679
    } else {
680
         amoebaReferenceMultipoleForce = new AmoebaReferenceMultipoleForce(AmoebaReferenceMultipoleForce::NoCutoff);
681
682
    }

683
684
    // set polarization type

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

698
699
700
701
702
703
    return amoebaReferenceMultipoleForce;

}

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

704
    AmoebaReferenceMultipoleForce* amoebaReferenceMultipoleForce = setupAmoebaReferenceMultipoleForce(context);
705

peastman's avatar
peastman committed
706
707
708
709
710
711
    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);
712

713
    delete amoebaReferenceMultipoleForce;
714
715
716
717

    return static_cast<double>(energy);
}

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

    // Create an AmoebaReferenceMultipoleForce to do the calculation.
    
724
    AmoebaReferenceMultipoleForce* amoebaReferenceMultipoleForce = setupAmoebaReferenceMultipoleForce(context);
peastman's avatar
peastman committed
725
    vector<Vec3>& posData = extractPositions(context);
726
727
728
    
    // Retrieve the induced dipoles.
    
peastman's avatar
peastman committed
729
    vector<Vec3> inducedDipoles;
730
731
732
733
734
735
736
    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;
}

737
738
739
740
741
742
743
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
744
    vector<Vec3>& posData = extractPositions(context);
745
746
747
    
    // Retrieve the permanent dipoles in the lab frame.
    
peastman's avatar
peastman committed
748
    vector<Vec3> labFramePermanentDipoles;
749
750
751
752
753
754
    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;
}
755
756


757
758
759
760
761
762
763
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
764
    vector<Vec3>& posData = extractPositions(context);
765
766
767
    
    // Retrieve the permanent dipoles in the lab frame.
    
peastman's avatar
peastman committed
768
    vector<Vec3> totalDipoles;
769
    amoebaReferenceMultipoleForce->calculateTotalDipoles(posData, charges, dipoles, quadrupoles, tholes,
770
            dampingFactors, polarity, axisTypes, multipoleAtomZs, multipoleAtomXs, multipoleAtomYs, multipoleAtomCovalentInfo, totalDipoles);
771
772
773
774
775
776
777

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


778

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

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

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

    delete amoebaReferenceMultipoleForce;
800
801
}

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

    // retrieve masses

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

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

    delete amoebaReferenceMultipoleForce;
820
821
}

822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
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
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
        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];
856
857
858
    }
}

859
860
861
862
863
864
865
866
867
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];
}

868
869
870
871
/* -------------------------------------------------------------------------- *
 *                       AmoebaGeneralizedKirkwood                            *
 * -------------------------------------------------------------------------- */

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

ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::~ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel() {
}

879
int ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getNumParticles() const {
880
881
882
    return numParticles;
}

883
int ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getIncludeCavityTerm() const {
884
885
886
    return includeCavityTerm;
}

887
int ReferenceCalcAmoebaGeneralizedKirkwoodForceKernel::getDirectPolarization() const {
888
889
890
    return directPolarization;
}

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

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

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

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

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

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

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

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

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.");
    }

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

    numParticles = system.getNumParticles();

945
    for (int ii = 0; ii < numParticles; ii++) {
946
947
948

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

        // 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;
958
959
        amoebaMultipoleForce->getMultipoleParameters(ii, charge2, dipole, quadrupole, axisType, atomZ, atomX, atomY, thole, damping, polarity);
        if (particleCharge != charge2) {
960
961
962
963
964
            throw OpenMMException("AmoebaGeneralizedKirkwoodForce and AmoebaMultipoleForce must specify the same charge for every atom.");
        }

    }   
    includeCavityTerm  = force.getIncludeCavityTerm();
peastman's avatar
peastman committed
965
966
967
968
969
    soluteDielectric   = force.getSoluteDielectric();
    solventDielectric  = force.getSolventDielectric();
    dielectricOffset   = 0.009;
    probeRadius        = force.getProbeRadius(), 
    surfaceAreaFactor  = force.getSurfaceAreaFactor(); 
970
971
972
973
974
975
976
    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
977

978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
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;
    }
}

993
ReferenceCalcAmoebaVdwForceKernel::ReferenceCalcAmoebaVdwForceKernel(std::string name, const Platform& platform, const System& system) :
Mark Friedrichs's avatar
Mark Friedrichs committed
994
       CalcAmoebaVdwForceKernel(name, platform), system(system) {
995
    useCutoff = 0;
996
997
    usePBC = 0;
    cutoff = 1.0e+10;
998
    neighborList = NULL;
Mark Friedrichs's avatar
Mark Friedrichs committed
999
1000
1001
}

ReferenceCalcAmoebaVdwForceKernel::~ReferenceCalcAmoebaVdwForceKernel() {
1002
    if (neighborList) {
1003
1004
        delete neighborList;
    } 
Mark Friedrichs's avatar
Mark Friedrichs committed
1005
1006
1007
1008
1009
1010
1011
1012
}

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

    // per-particle parameters

    numParticles = system.getNumParticles();

1013
1014
1015
1016
1017
    indexIVs.resize(numParticles);
    allExclusions.resize(numParticles);
    sigmas.resize(numParticles);
    epsilons.resize(numParticles);
    reductions.resize(numParticles);
Mark Friedrichs's avatar
Mark Friedrichs committed
1018

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

1021
        int indexIV;
Mark Friedrichs's avatar
Mark Friedrichs committed
1022
1023
1024
        double sigma, epsilon, reduction;
        std::vector<int> exclusions;

1025
1026
1027
1028
        force.getParticleParameters(ii, indexIV, sigma, epsilon, reduction);
        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
1029
1030
1031
        }

        indexIVs[ii]      = indexIV;
peastman's avatar
peastman committed
1032
1033
1034
        sigmas[ii]        = sigma;
        epsilons[ii]      = epsilon;
        reductions[ii]    = reduction;
Mark Friedrichs's avatar
Mark Friedrichs committed
1035
    }   
1036
1037
1038
1039
    sigmaCombiningRule     = force.getSigmaCombiningRule();
    epsilonCombiningRule   = force.getEpsilonCombiningRule();
    useCutoff              = (force.getNonbondedMethod() != AmoebaVdwForce::NoCutoff);
    usePBC                 = (force.getNonbondedMethod() == AmoebaVdwForce::CutoffPeriodic);
peastman's avatar
peastman committed
1040
    cutoff                 = force.getCutoffDistance();
1041
1042
1043
    neighborList           = useCutoff ? new NeighborList() : NULL;
    dispersionCoefficient  = force.getUseDispersionCorrection() ?  AmoebaVdwForceImpl::calcDispersionCorrection(system, force) : 0.0;

Mark Friedrichs's avatar
Mark Friedrichs committed
1044
1045
1046
1047
}

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

peastman's avatar
peastman committed
1048
1049
    vector<Vec3>& posData   = extractPositions(context);
    vector<Vec3>& forceData = extractForces(context);
1050
    AmoebaReferenceVdwForce vdwForce(sigmaCombiningRule, epsilonCombiningRule);
peastman's avatar
peastman committed
1051
    double energy;
1052
1053
1054
1055
1056
    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
1057
            Vec3* boxVectors = extractBoxVectors(context);
1058
            double minAllowedSize = 1.999999*cutoff;
1059
            if (boxVectors[0][0] < minAllowedSize || boxVectors[1][1] < minAllowedSize || boxVectors[2][2] < minAllowedSize) {
1060
1061
                throw OpenMMException("The periodic box size has decreased to less than twice the cutoff.");
            }
1062
            vdwForce.setPeriodicBox(boxVectors);
1063
            energy  = vdwForce.calculateForceAndEnergy(numParticles, posData, indexIVs, sigmas, epsilons, reductions, *neighborList, forceData);
1064
            energy += dispersionCoefficient/(boxVectors[0][0]*boxVectors[1][1]*boxVectors[2][2]);
1065
        } else {
1066
            vdwForce.setNonbondedMethod(AmoebaReferenceVdwForce::CutoffNonPeriodic);
1067
1068
        }
    } else {
1069
1070
        vdwForce.setNonbondedMethod(AmoebaReferenceVdwForce::NoCutoff);
        energy = vdwForce.calculateForceAndEnergy(numParticles, posData, indexIVs, sigmas, epsilons, reductions, allExclusions, forceData);
1071
    }
Mark Friedrichs's avatar
Mark Friedrichs committed
1072
1073
1074
    return static_cast<double>(energy);
}

1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
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;
        force.getParticleParameters(i, indexIV, sigma, epsilon, reduction);
        indexIVs[i] = indexIV;
peastman's avatar
peastman committed
1086
1087
1088
        sigmas[i] = sigma;
        epsilons[i] = epsilon;
        reductions[i]= reduction;
1089
1090
1091
    }
}

Mark Friedrichs's avatar
Mark Friedrichs committed
1092
1093
1094
1095
/* -------------------------------------------------------------------------- *
 *                           AmoebaWcaDispersion                              *
 * -------------------------------------------------------------------------- */

1096
ReferenceCalcAmoebaWcaDispersionForceKernel::ReferenceCalcAmoebaWcaDispersionForceKernel(std::string name, const Platform& platform, const System& system) : 
Mark Friedrichs's avatar
Mark Friedrichs committed
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
           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);
1110
    for (int ii = 0; ii < numParticles; ii++) {
Mark Friedrichs's avatar
Mark Friedrichs committed
1111
1112

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

peastman's avatar
peastman committed
1115
1116
        radii[ii] = radius;
        epsilons[ii] = epsilon;
Mark Friedrichs's avatar
Mark Friedrichs committed
1117
1118
    }   

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

peastman's avatar
peastman committed
1121
1122
1123
1124
1125
1126
1127
1128
    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
1129
1130
1131
}

double ReferenceCalcAmoebaWcaDispersionForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
peastman's avatar
peastman committed
1132
1133
    vector<Vec3>& posData = extractPositions(context);
    vector<Vec3>& forceData = extractForces(context);
1134
    AmoebaReferenceWcaDispersionForce amoebaReferenceWcaDispersionForce(epso, epsh, rmino, rminh, awater, shctd, dispoff, slevy);
peastman's avatar
peastman committed
1135
    double energy = amoebaReferenceWcaDispersionForce.calculateForceAndEnergy(numParticles, posData, radii, epsilons, totalMaximumDispersionEnergy, forceData);
Mark Friedrichs's avatar
Mark Friedrichs committed
1136
1137
    return static_cast<double>(energy);
}
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147

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
1148
1149
        radii[i] = radius;
        epsilons[i] = epsilon;
1150
    }
peastman's avatar
peastman committed
1151
    totalMaximumDispersionEnergy = AmoebaWcaDispersionForceImpl::getTotalMaximumDispersionEnergy(force);
1152
}