"vscode:/vscode.git/clone" did not exist on "dae88c4861183a272b810831f5e74b29d7a36ba2"
ReferenceGBVI.cpp 34.9 KB
Newer Older
Mark Friedrichs's avatar
Mark Friedrichs committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* Portions copyright (c) 2006-2009 Stanford University and Simbios.
 * Contributors: Pande Group
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject
 * to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <string.h>
Mark Friedrichs's avatar
Mark Friedrichs committed
25
#include <math.h>
Mark Friedrichs's avatar
Mark Friedrichs committed
26
#include <sstream>
Mark Friedrichs's avatar
Mark Friedrichs committed
27
#include <stdio.h>
Mark Friedrichs's avatar
Mark Friedrichs committed
28

29
#include "ReferenceForce.h"
30
#include "ReferenceGBVI.h"
Mark Friedrichs's avatar
Mark Friedrichs committed
31

32
33
34
using namespace std;
using namespace OpenMM;

Mark Friedrichs's avatar
Mark Friedrichs committed
35
36
/**---------------------------------------------------------------------------------------

37
    ReferenceGBVI constructor
Mark Friedrichs's avatar
Mark Friedrichs committed
38

Mark Friedrichs's avatar
Mark Friedrichs committed
39
40
41
    gbviParameters      gbviParameters object
    
    --------------------------------------------------------------------------------------- */
Mark Friedrichs's avatar
Mark Friedrichs committed
42

43
ReferenceGBVI::ReferenceGBVI(GBVIParameters* gbviParameters) : _gbviParameters(gbviParameters) {
44
    _switchDeriviative.resize(gbviParameters->getNumberOfAtoms());
Mark Friedrichs's avatar
Mark Friedrichs committed
45
46
47
48
}

/**---------------------------------------------------------------------------------------

49
    ReferenceGBVI destructor
Mark Friedrichs's avatar
Mark Friedrichs committed
50

Mark Friedrichs's avatar
Mark Friedrichs committed
51
    --------------------------------------------------------------------------------------- */
Mark Friedrichs's avatar
Mark Friedrichs committed
52

53
ReferenceGBVI::~ReferenceGBVI() {
Mark Friedrichs's avatar
Mark Friedrichs committed
54
55
56
57
}

/**---------------------------------------------------------------------------------------

Mark Friedrichs's avatar
Mark Friedrichs committed
58
    Get GBVIParameters reference
Mark Friedrichs's avatar
Mark Friedrichs committed
59

Mark Friedrichs's avatar
Mark Friedrichs committed
60
    @return GBVIParameters reference
Mark Friedrichs's avatar
Mark Friedrichs committed
61

Mark Friedrichs's avatar
Mark Friedrichs committed
62
    --------------------------------------------------------------------------------------- */
Mark Friedrichs's avatar
Mark Friedrichs committed
63

64
GBVIParameters* ReferenceGBVI::getGBVIParameters() const {
Mark Friedrichs's avatar
Mark Friedrichs committed
65
    return _gbviParameters;
Mark Friedrichs's avatar
Mark Friedrichs committed
66
67
68
69
}

/**---------------------------------------------------------------------------------------

Mark Friedrichs's avatar
Mark Friedrichs committed
70
    Set GBVIParameters reference
Mark Friedrichs's avatar
Mark Friedrichs committed
71

Mark Friedrichs's avatar
Mark Friedrichs committed
72
    @param GBVIParameters reference
Mark Friedrichs's avatar
Mark Friedrichs committed
73

Mark Friedrichs's avatar
Mark Friedrichs committed
74
    --------------------------------------------------------------------------------------- */
Mark Friedrichs's avatar
Mark Friedrichs committed
75

76
void ReferenceGBVI::setGBVIParameters(GBVIParameters* gbviParameters) {
Mark Friedrichs's avatar
Mark Friedrichs committed
77
    _gbviParameters = gbviParameters;
78
79
80
81
}

/**---------------------------------------------------------------------------------------

Mark Friedrichs's avatar
Mark Friedrichs committed
82
    Return OBC chain derivative: size = _obcParameters->getNumberOfAtoms()
83

Mark Friedrichs's avatar
Mark Friedrichs committed
84
    @return array
85

Mark Friedrichs's avatar
Mark Friedrichs committed
86
    --------------------------------------------------------------------------------------- */
87

88
vector<RealOpenMM>& ReferenceGBVI::getSwitchDeriviative() {
Mark Friedrichs's avatar
Mark Friedrichs committed
89
    return _switchDeriviative;
90
91
92
93
}

/**---------------------------------------------------------------------------------------

Mark Friedrichs's avatar
Mark Friedrichs committed
94
    Compute quintic spline value and associated derviative
95

Mark Friedrichs's avatar
Mark Friedrichs committed
96
97
98
99
100
    @param x                   value to compute spline at
    @param rl                  lower cutoff value
    @param ru                  upper cutoff value
    @param outValue            value of spline at x
    @param outDerivative       value of derivative of spline at x
101

Mark Friedrichs's avatar
Mark Friedrichs committed
102
    --------------------------------------------------------------------------------------- */
103

104
void ReferenceGBVI::quinticSpline(RealOpenMM x, RealOpenMM rl, RealOpenMM ru,
105
                            RealOpenMM* outValue, RealOpenMM* outDerivative) {
106

Mark Friedrichs's avatar
Mark Friedrichs committed
107
    // ---------------------------------------------------------------------------------------
108

109
110
111
112
113
114
    static const RealOpenMM one           = static_cast<RealOpenMM>(  1.0);
    static const RealOpenMM minusSix      = static_cast<RealOpenMM>( -6.0);
    static const RealOpenMM minusTen      = static_cast<RealOpenMM>(-10.0);
    static const RealOpenMM minusThirty   = static_cast<RealOpenMM>(-30.0);
    static const RealOpenMM fifteen       = static_cast<RealOpenMM>( 15.0);
    static const RealOpenMM sixty         = static_cast<RealOpenMM>( 60.0);
115

Mark Friedrichs's avatar
Mark Friedrichs committed
116
    // ---------------------------------------------------------------------------------------
117

Mark Friedrichs's avatar
Mark Friedrichs committed
118
119
120
121
122
    RealOpenMM numerator    = x  - rl;
    RealOpenMM denominator  = ru - rl;
    RealOpenMM ratio        = numerator/denominator;
    RealOpenMM ratio2       = ratio*ratio;
    RealOpenMM ratio3       = ratio2*ratio;
123

Mark Friedrichs's avatar
Mark Friedrichs committed
124
125
    *outValue               = one + ratio3*(minusTen + fifteen*ratio + minusSix*ratio2);
    *outDerivative          = ratio2*(minusThirty + sixty*ratio + minusThirty*ratio2)/denominator;
126
127
128
129
}

/**---------------------------------------------------------------------------------------

Mark Friedrichs's avatar
Mark Friedrichs committed
130
131
    Compute Born radii based on Eq. 3 of Labute paper [JCC 29 p. 1693-1698 2008])
    and quintic splice switching function
132

Mark Friedrichs's avatar
Mark Friedrichs committed
133
134
135
136
137
138
    @param atomicRadius3       atomic radius cubed
    @param bornSum             Born sum (volume integral)
    @param gbviParameters      Gbvi parameters (parameters used in spline
                               QuinticLowerLimitFactor & QuinticUpperBornRadiusLimit)
    @param bornRadius          output Born radius
    @param switchDeriviative   output switching function deriviative
139

Mark Friedrichs's avatar
Mark Friedrichs committed
140
    --------------------------------------------------------------------------------------- */
141

142
void ReferenceGBVI::computeBornRadiiUsingQuinticSpline(RealOpenMM atomicRadius3, RealOpenMM bornSum,
143
144
                                                 GBVIParameters* gbviParameters, 
                                                 RealOpenMM* bornRadius, RealOpenMM* switchDeriviative) {
145

Mark Friedrichs's avatar
Mark Friedrichs committed
146
    // ---------------------------------------------------------------------------------------
147

148
149
150
151
152
153
154
    static const RealOpenMM zero          = static_cast<RealOpenMM>( 0.0);
    static const RealOpenMM one           = static_cast<RealOpenMM>( 1.0);
    static const RealOpenMM minusOne      = static_cast<RealOpenMM>(-1.0);
    static const RealOpenMM minusThree    = static_cast<RealOpenMM>(-3.0);
    static const RealOpenMM oneEighth     = static_cast<RealOpenMM>( 0.125);
    static const RealOpenMM minusOneThird = static_cast<RealOpenMM>((-1.0/3.0));
    static const RealOpenMM three         = static_cast<RealOpenMM>( 3.0);
155

Mark Friedrichs's avatar
Mark Friedrichs committed
156
    // ---------------------------------------------------------------------------------------
157

Mark Friedrichs's avatar
Mark Friedrichs committed
158
    // R                = [ S(V)*(A - V) ]**(-1/3)
159

Mark Friedrichs's avatar
Mark Friedrichs committed
160
161
162
    // S(V)             = 1                                 V < L
    // S(V)             = qSpline + U/(A-V)                 L < V < A
    // S(V)             = U/(A-V)                           U < V 
163

Mark Friedrichs's avatar
Mark Friedrichs committed
164
    // dR/dr            = (-1/3)*[ S(V)*(A - V) ]**(-4/3)*[ d{ S(V)*(A-V) }/dr
165

Mark Friedrichs's avatar
Mark Friedrichs committed
166
    // d{ S(V)*(A-V) }/dr   = (dV/dr)*[ (A-V)*dS/dV - S(V) ]
167

Mark Friedrichs's avatar
Mark Friedrichs committed
168
    //  (A - V)*dS/dV - S(V)  = 0 - 1                             V < L
169

Mark Friedrichs's avatar
Mark Friedrichs committed
170
    //  (A - V)*dS/dV - S(V)  = (A-V)*d(qSpline) + (A-V)*U/(A-V)**2 - qSpline - U/(A-V) 
171

172
    //                        = (A-V)*d(qSpline) - qSpline        L < V < A**(-3)
173

Mark Friedrichs's avatar
Mark Friedrichs committed
174
175
176
177
    //  (A - V)*dS/dV - S(V)  = (A-V)*U*/(A-V)**2 - U/(A-V) = 0   U < V

    RealOpenMM splineL          = gbviParameters->getQuinticLowerLimitFactor()*atomicRadius3;
    RealOpenMM sum;
178
179
    if (bornSum > splineL) {
        if (bornSum < atomicRadius3) {
Mark Friedrichs's avatar
Mark Friedrichs committed
180
            RealOpenMM splineValue, splineDerivative;
181
            quinticSpline(bornSum, splineL, atomicRadius3, &splineValue, &splineDerivative); 
Mark Friedrichs's avatar
Mark Friedrichs committed
182
183
184
185
186
187
188
189
190
191
            sum                 = (atomicRadius3 - bornSum)*splineValue + gbviParameters->getQuinticUpperBornRadiusLimit();
            *switchDeriviative  = splineValue - (atomicRadius3 - bornSum)*splineDerivative;
        } else {   
            sum                = gbviParameters->getQuinticUpperBornRadiusLimit();
            *switchDeriviative = zero;
        }
    } else {
        sum                = atomicRadius3 - bornSum; 
        *switchDeriviative = one;
    }
192
    *bornRadius = POW(sum, minusOneThird);
Mark Friedrichs's avatar
Mark Friedrichs committed
193
194
195
196
}

/**---------------------------------------------------------------------------------------

Mark Friedrichs's avatar
Mark Friedrichs committed
197
    Get Born radii based on Eq. 3 of Labute paper [JCC 29 p. 1693-1698 2008])
Mark Friedrichs's avatar
Mark Friedrichs committed
198

Mark Friedrichs's avatar
Mark Friedrichs committed
199
200
201
    @param atomCoordinates     atomic coordinates
    @param bornRadii           output array of Born radii
    @param chain               not used here
Mark Friedrichs's avatar
Mark Friedrichs committed
202

Mark Friedrichs's avatar
Mark Friedrichs committed
203
    --------------------------------------------------------------------------------------- */
Mark Friedrichs's avatar
Mark Friedrichs committed
204

205
void ReferenceGBVI::computeBornRadii(const vector<RealVec>& atomCoordinates, vector<RealOpenMM>& bornRadii) {
Mark Friedrichs's avatar
Mark Friedrichs committed
206

Mark Friedrichs's avatar
Mark Friedrichs committed
207
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
208

209
210
211
212
213
214
    static const RealOpenMM zero          = static_cast<RealOpenMM>(0.0);
    static const RealOpenMM one           = static_cast<RealOpenMM>(1.0);
    static const RealOpenMM minusThree    = static_cast<RealOpenMM>(-3.0);
    static const RealOpenMM oneEighth     = static_cast<RealOpenMM>(0.125);
    static const RealOpenMM minusOneThird = static_cast<RealOpenMM>((-1.0/3.0));
    static const RealOpenMM three         = static_cast<RealOpenMM>(3.0);
Mark Friedrichs's avatar
Mark Friedrichs committed
215

Mark Friedrichs's avatar
Mark Friedrichs committed
216
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
217

Mark Friedrichs's avatar
Mark Friedrichs committed
218
219
    GBVIParameters* gbviParameters        = getGBVIParameters();
    int numberOfAtoms                     = gbviParameters->getNumberOfAtoms();
220
221
    const vector<RealOpenMM>& atomicRadii   = gbviParameters->getAtomicRadii();
    const vector<RealOpenMM>& scaledRadii   = gbviParameters->getScaledRadii();
Mark Friedrichs's avatar
Mark Friedrichs committed
222

223
    vector<RealOpenMM>& switchDeriviatives  = getSwitchDeriviative();
Mark Friedrichs's avatar
Mark Friedrichs committed
224

Mark Friedrichs's avatar
Mark Friedrichs committed
225
    // ---------------------------------------------------------------------------------------
226

Mark Friedrichs's avatar
Mark Friedrichs committed
227
    // calculate Born radii
Mark Friedrichs's avatar
Mark Friedrichs committed
228

229
    for (int atomI = 0; atomI < numberOfAtoms; atomI++) {
Mark Friedrichs's avatar
Mark Friedrichs committed
230
231
232
233
234
      
        RealOpenMM radiusI         = atomicRadii[atomI];
        RealOpenMM sum             = zero;
 
        // sum over volumes
Mark Friedrichs's avatar
Mark Friedrichs committed
235

236
        for (int atomJ = 0; atomJ < numberOfAtoms; atomJ++) {
237

238
            if (atomJ != atomI) {
Mark Friedrichs's avatar
Mark Friedrichs committed
239
240
241
  
                RealOpenMM deltaR[ReferenceForce::LastDeltaRIndex];
                if (_gbviParameters->getPeriodic())
242
                    ReferenceForce::getDeltaRPeriodic(atomCoordinates[atomI], atomCoordinates[atomJ], _gbviParameters->getPeriodicBox(), deltaR);
Mark Friedrichs's avatar
Mark Friedrichs committed
243
                else
244
                    ReferenceForce::getDeltaR(atomCoordinates[atomI], atomCoordinates[atomJ], deltaR);
Mark Friedrichs's avatar
Mark Friedrichs committed
245
246
247
248
249
250
   
                RealOpenMM r               = deltaR[ReferenceForce::RIndex];
   
                if (_gbviParameters->getUseCutoff() && r > _gbviParameters->getCutoffDistance())
                    continue;
   
251
                sum  += ReferenceGBVI::getVolume(r, radiusI, scaledRadii[atomJ]);
Mark Friedrichs's avatar
Mark Friedrichs committed
252
253
254
255
   
            }
        }

256
257
        RealOpenMM atomicRadius3 = POW(radiusI, minusThree);
        if (_gbviParameters->getBornRadiusScalingMethod() != GBVIParameters::QuinticSpline) {
Mark Friedrichs's avatar
Mark Friedrichs committed
258
           sum                        = atomicRadius3 - sum; 
259
           bornRadii[atomI]           = POW(sum, minusOneThird);
Mark Friedrichs's avatar
Mark Friedrichs committed
260
261
262
           switchDeriviatives[atomI]  = one; 
        } else {
           RealOpenMM bornRadius, switchDeriviative;
263
264
           computeBornRadiiUsingQuinticSpline(atomicRadius3, sum, gbviParameters, 
                                              &bornRadius, &switchDeriviative);
Mark Friedrichs's avatar
Mark Friedrichs committed
265
266
267
268
           bornRadii[atomI]           = bornRadius;
           switchDeriviatives[atomI]  = switchDeriviative;
        }    
    }
Mark Friedrichs's avatar
Mark Friedrichs committed
269
270
271
272
}

/**---------------------------------------------------------------------------------------

Mark Friedrichs's avatar
Mark Friedrichs committed
273
    Get volume Eq. 4 of Labute paper [JCC 29 p. 1693-1698 2008])
Mark Friedrichs's avatar
Mark Friedrichs committed
274

Mark Friedrichs's avatar
Mark Friedrichs committed
275
276
277
    @param r                   distance between atoms i & j
    @param R                   atomic radius
    @param S                   scaled atomic radius
Mark Friedrichs's avatar
Mark Friedrichs committed
278

Mark Friedrichs's avatar
Mark Friedrichs committed
279
    @return volume
Mark Friedrichs's avatar
Mark Friedrichs committed
280

Mark Friedrichs's avatar
Mark Friedrichs committed
281
    --------------------------------------------------------------------------------------- */
Mark Friedrichs's avatar
Mark Friedrichs committed
282

283
RealOpenMM ReferenceGBVI::getVolume(RealOpenMM r, RealOpenMM R, RealOpenMM S) {
Mark Friedrichs's avatar
Mark Friedrichs committed
284

Mark Friedrichs's avatar
Mark Friedrichs committed
285
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
286

287
288
    static const RealOpenMM zero         = static_cast<RealOpenMM>( 0.0);
    static const RealOpenMM minusThree   = static_cast<RealOpenMM>(-3.0);
Mark Friedrichs's avatar
Mark Friedrichs committed
289

Mark Friedrichs's avatar
Mark Friedrichs committed
290
    RealOpenMM              diff         = (S - R);
291
    if (FABS(diff) < r) {
Mark Friedrichs's avatar
Mark Friedrichs committed
292

Mark Friedrichs's avatar
Mark Friedrichs committed
293
        RealOpenMM lowerBound = (R > (r - S)) ? R : (r - S);
294
295
        return (ReferenceGBVI::getL(r, (r + S),    S) -
                ReferenceGBVI::getL(r, lowerBound, S));
Mark Friedrichs's avatar
Mark Friedrichs committed
296
 
297
    } else if (r <= diff) {
Mark Friedrichs's avatar
Mark Friedrichs committed
298

299
300
        return ReferenceGBVI::getL(r, (r + S), S) -
               ReferenceGBVI::getL(r, (r - S), S) + 
301
               POW(R, minusThree);
Mark Friedrichs's avatar
Mark Friedrichs committed
302

Mark Friedrichs's avatar
Mark Friedrichs committed
303
304
305
    } else {
        return zero;
    }
Mark Friedrichs's avatar
Mark Friedrichs committed
306
307
308
309
}

/**---------------------------------------------------------------------------------------

Mark Friedrichs's avatar
Mark Friedrichs committed
310
    Get L (used in analytical solution for volume integrals) 
Mark Friedrichs's avatar
Mark Friedrichs committed
311

Mark Friedrichs's avatar
Mark Friedrichs committed
312
313
314
    @param r                   distance between atoms i & j
    @param R                   atomic radius
    @param S                   scaled atomic radius
Mark Friedrichs's avatar
Mark Friedrichs committed
315

Mark Friedrichs's avatar
Mark Friedrichs committed
316
    @return L value (Eq. 4 of Labute paper [JCC 29 p. 1693-1698 2008])
Mark Friedrichs's avatar
Mark Friedrichs committed
317

Mark Friedrichs's avatar
Mark Friedrichs committed
318
    --------------------------------------------------------------------------------------- */
Mark Friedrichs's avatar
Mark Friedrichs committed
319

320
RealOpenMM ReferenceGBVI::getL(RealOpenMM r, RealOpenMM x, RealOpenMM S) {
Mark Friedrichs's avatar
Mark Friedrichs committed
321

Mark Friedrichs's avatar
Mark Friedrichs committed
322
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
323

324
325
326
327
328
    static const RealOpenMM one           = static_cast<RealOpenMM>(1.0);
    static const RealOpenMM threeHalves   = static_cast<RealOpenMM>(1.5);
    static const RealOpenMM third         = static_cast<RealOpenMM>((1.0/3.0));
    static const RealOpenMM fourth        = static_cast<RealOpenMM>(0.25);
    static const RealOpenMM eighth        = static_cast<RealOpenMM>(0.125);
Mark Friedrichs's avatar
Mark Friedrichs committed
329

Mark Friedrichs's avatar
Mark Friedrichs committed
330
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
331

Mark Friedrichs's avatar
Mark Friedrichs committed
332
    RealOpenMM rInv   = one/r;
Mark Friedrichs's avatar
Mark Friedrichs committed
333

Mark Friedrichs's avatar
Mark Friedrichs committed
334
335
336
    RealOpenMM xInv   = one/x;
    RealOpenMM xInv2  = xInv*xInv;
    RealOpenMM xInv3  = xInv2*xInv;
Mark Friedrichs's avatar
Mark Friedrichs committed
337

Mark Friedrichs's avatar
Mark Friedrichs committed
338
    RealOpenMM diff2  = (r + S)*(r - S);
Mark Friedrichs's avatar
Mark Friedrichs committed
339

340
    return (threeHalves*xInv)*((xInv*fourth*rInv) - (xInv2*third) + (diff2*xInv3*eighth*rInv));
Mark Friedrichs's avatar
Mark Friedrichs committed
341
342
343
344
}

/**---------------------------------------------------------------------------------------

Mark Friedrichs's avatar
Mark Friedrichs committed
345
    Get partial derivative of L wrt r
Mark Friedrichs's avatar
Mark Friedrichs committed
346

Mark Friedrichs's avatar
Mark Friedrichs committed
347
348
349
    @param r                   distance between atoms i & j
    @param R                   atomic radius
    @param S                   scaled atomic radius
Mark Friedrichs's avatar
Mark Friedrichs committed
350

Mark Friedrichs's avatar
Mark Friedrichs committed
351
    @return partial derivative based on Eq. 4 of Labute paper [JCC 29 p. 1693-1698 2008])
Mark Friedrichs's avatar
Mark Friedrichs committed
352

Mark Friedrichs's avatar
Mark Friedrichs committed
353
    --------------------------------------------------------------------------------------- */
Mark Friedrichs's avatar
Mark Friedrichs committed
354

355
RealOpenMM ReferenceGBVI::dL_dr(RealOpenMM r, RealOpenMM x, RealOpenMM S) {
Mark Friedrichs's avatar
Mark Friedrichs committed
356

Mark Friedrichs's avatar
Mark Friedrichs committed
357
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
358

359
360
361
362
363
364
    static const RealOpenMM one           = static_cast<RealOpenMM>(1.0);
    static const RealOpenMM threeHalves   = static_cast<RealOpenMM>(1.5);
    static const RealOpenMM threeEights   = static_cast<RealOpenMM>(0.375);
    static const RealOpenMM third         = static_cast<RealOpenMM>((1.0/3.0));
    static const RealOpenMM fourth        = static_cast<RealOpenMM>(0.25);
    static const RealOpenMM eighth        = static_cast<RealOpenMM>(0.125);
Mark Friedrichs's avatar
Mark Friedrichs committed
365

Mark Friedrichs's avatar
Mark Friedrichs committed
366
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
367

Mark Friedrichs's avatar
Mark Friedrichs committed
368
369
    RealOpenMM rInv   = one/r;
    RealOpenMM rInv2  = rInv*rInv;
Mark Friedrichs's avatar
Mark Friedrichs committed
370

Mark Friedrichs's avatar
Mark Friedrichs committed
371
372
373
    RealOpenMM xInv   = one/x;
    RealOpenMM xInv2  = xInv*xInv;
    RealOpenMM xInv3  = xInv2*xInv;
Mark Friedrichs's avatar
Mark Friedrichs committed
374

Mark Friedrichs's avatar
Mark Friedrichs committed
375
    RealOpenMM diff2  = (r + S)*(r - S);
Mark Friedrichs's avatar
Mark Friedrichs committed
376

377
    return ((-threeHalves*xInv2*rInv2)*(fourth + eighth*diff2*xInv2) + threeEights*xInv3*xInv);
Mark Friedrichs's avatar
Mark Friedrichs committed
378
379
380
381
}

/**---------------------------------------------------------------------------------------

Mark Friedrichs's avatar
Mark Friedrichs committed
382
    Get partial derivative of L wrt x
Mark Friedrichs's avatar
Mark Friedrichs committed
383

Mark Friedrichs's avatar
Mark Friedrichs committed
384
385
386
    @param r                   distance between atoms i & j
    @param R                   atomic radius
    @param S                   scaled atomic radius
Mark Friedrichs's avatar
Mark Friedrichs committed
387

Mark Friedrichs's avatar
Mark Friedrichs committed
388
    @return partial derivative based on Eq. 4 of Labute paper [JCC 29 p. 1693-1698 2008])
Mark Friedrichs's avatar
Mark Friedrichs committed
389

Mark Friedrichs's avatar
Mark Friedrichs committed
390
    --------------------------------------------------------------------------------------- */
Mark Friedrichs's avatar
Mark Friedrichs committed
391

392
RealOpenMM ReferenceGBVI::dL_dx(RealOpenMM r, RealOpenMM x, RealOpenMM S) {
Mark Friedrichs's avatar
Mark Friedrichs committed
393

Mark Friedrichs's avatar
Mark Friedrichs committed
394
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
395

396
397
398
399
    static const RealOpenMM one           = static_cast<RealOpenMM>( 1.0);
    static const RealOpenMM half          = static_cast<RealOpenMM>( 0.5);
    static const RealOpenMM threeHalvesM  = static_cast<RealOpenMM>(-1.5);
    static const RealOpenMM third         = static_cast<RealOpenMM>( (1.0/3.0));
Mark Friedrichs's avatar
Mark Friedrichs committed
400

Mark Friedrichs's avatar
Mark Friedrichs committed
401
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
402

Mark Friedrichs's avatar
Mark Friedrichs committed
403
    RealOpenMM rInv   = one/r;
Mark Friedrichs's avatar
Mark Friedrichs committed
404

Mark Friedrichs's avatar
Mark Friedrichs committed
405
406
407
    RealOpenMM xInv   = one/x;
    RealOpenMM xInv2  = xInv*xInv;
    RealOpenMM xInv3  = xInv2*xInv;
Mark Friedrichs's avatar
Mark Friedrichs committed
408

Mark Friedrichs's avatar
Mark Friedrichs committed
409
    RealOpenMM diff   = (r + S)*(r - S);
Mark Friedrichs's avatar
Mark Friedrichs committed
410

411
    return (threeHalvesM*xInv3)*((half*rInv) - xInv + (half*diff*xInv2*rInv));
Mark Friedrichs's avatar
Mark Friedrichs committed
412
413
414
415
}

/**---------------------------------------------------------------------------------------

Mark Friedrichs's avatar
Mark Friedrichs committed
416
    Sgb function
Mark Friedrichs's avatar
Mark Friedrichs committed
417

Mark Friedrichs's avatar
Mark Friedrichs committed
418
    @param t                   r*r*G_i*G_j
Mark Friedrichs's avatar
Mark Friedrichs committed
419

Mark Friedrichs's avatar
Mark Friedrichs committed
420
    @return Sgb (top of p. 1694 of Labute paper [JCC 29 p. 1693-1698 2008])
Mark Friedrichs's avatar
Mark Friedrichs committed
421

Mark Friedrichs's avatar
Mark Friedrichs committed
422
    --------------------------------------------------------------------------------------- */
Mark Friedrichs's avatar
Mark Friedrichs committed
423

424
RealOpenMM ReferenceGBVI::Sgb(RealOpenMM t) {
Mark Friedrichs's avatar
Mark Friedrichs committed
425

Mark Friedrichs's avatar
Mark Friedrichs committed
426
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
427

428
    // static const char* methodName = "ReferenceGBVI::Sgb";
Mark Friedrichs's avatar
Mark Friedrichs committed
429

430
431
432
    static const RealOpenMM zero    = static_cast<RealOpenMM>(0.0);
    static const RealOpenMM one     = static_cast<RealOpenMM>(1.0);
    static const RealOpenMM fourth  = static_cast<RealOpenMM>(0.25);
Mark Friedrichs's avatar
Mark Friedrichs committed
433

Mark Friedrichs's avatar
Mark Friedrichs committed
434
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
435

436
    return ((t != zero) ? one/SQRT((one + (fourth*EXP(-t))/t)) : zero);
Mark Friedrichs's avatar
Mark Friedrichs committed
437
438
439
440
}

/**---------------------------------------------------------------------------------------

Mark Friedrichs's avatar
Mark Friedrichs committed
441
    Get GB/VI energy
Mark Friedrichs's avatar
Mark Friedrichs committed
442

Mark Friedrichs's avatar
Mark Friedrichs committed
443
444
    @param atomCoordinates     atomic coordinates
    @param partialCharges      partial charges
Mark Friedrichs's avatar
Mark Friedrichs committed
445

Mark Friedrichs's avatar
Mark Friedrichs committed
446
    @return energy
Mark Friedrichs's avatar
Mark Friedrichs committed
447

Mark Friedrichs's avatar
Mark Friedrichs committed
448
    --------------------------------------------------------------------------------------- */
Mark Friedrichs's avatar
Mark Friedrichs committed
449

450
RealOpenMM ReferenceGBVI::computeBornEnergy(const vector<RealVec>& atomCoordinates, const vector<RealOpenMM>& partialCharges) {
Mark Friedrichs's avatar
Mark Friedrichs committed
451

Mark Friedrichs's avatar
Mark Friedrichs committed
452
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
453

454
455
456
457
458
459
460
461
    static const RealOpenMM zero          = static_cast<RealOpenMM>(0.0);
    static const RealOpenMM one           = static_cast<RealOpenMM>(1.0);
    static const RealOpenMM two           = static_cast<RealOpenMM>(2.0);
    static const RealOpenMM three         = static_cast<RealOpenMM>(3.0);
    static const RealOpenMM four          = static_cast<RealOpenMM>(4.0);
    static const RealOpenMM half          = static_cast<RealOpenMM>(0.5);
    static const RealOpenMM fourth        = static_cast<RealOpenMM>(0.25);
    static const RealOpenMM eighth        = static_cast<RealOpenMM>(0.125);
Mark Friedrichs's avatar
Mark Friedrichs committed
462

Mark Friedrichs's avatar
Mark Friedrichs committed
463
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
464

Mark Friedrichs's avatar
Mark Friedrichs committed
465
466
467
    const GBVIParameters* gbviParameters       = getGBVIParameters();
    const RealOpenMM preFactor                 = gbviParameters->getElectricConstant();
    const int numberOfAtoms                    = gbviParameters->getNumberOfAtoms();
468
469
    const vector<RealOpenMM>& atomicRadii        = gbviParameters->getAtomicRadii();
    const vector<RealOpenMM>& gammaParameters    = gbviParameters->getGammaParameters();
Mark Friedrichs's avatar
Mark Friedrichs committed
470

Mark Friedrichs's avatar
Mark Friedrichs committed
471
    // compute Born radii
Mark Friedrichs's avatar
Mark Friedrichs committed
472

473
    vector<RealOpenMM> bornRadii(numberOfAtoms);
474
    computeBornRadii(atomCoordinates, bornRadii);
Mark Friedrichs's avatar
Mark Friedrichs committed
475

Mark Friedrichs's avatar
Mark Friedrichs committed
476
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
477

Mark Friedrichs's avatar
Mark Friedrichs committed
478
479
480
    // Eq.2 of Labute paper [JCC 29 p. 1693-1698 2008]
    // to minimze roundoff error sum cavityEnergy separately since in general much
    // smaller than other contributions
Mark Friedrichs's avatar
Mark Friedrichs committed
481

Mark Friedrichs's avatar
Mark Friedrichs committed
482
483
    RealOpenMM energy                 = zero;
    RealOpenMM cavityEnergy           = zero;
Mark Friedrichs's avatar
Mark Friedrichs committed
484

485
    for (int atomI = 0; atomI < numberOfAtoms; atomI++) {
Mark Friedrichs's avatar
Mark Friedrichs committed
486
 
Mark Friedrichs's avatar
Mark Friedrichs committed
487
        RealOpenMM partialChargeI   = partialCharges[atomI];
Mark Friedrichs's avatar
Mark Friedrichs committed
488
 
Mark Friedrichs's avatar
Mark Friedrichs committed
489
490
491
492
493
494
495
496
497
        // self-energy term
 
        RealOpenMM  atomIEnergy     = half*partialChargeI/bornRadii[atomI];
 
        // cavity term
 
        RealOpenMM ratio            = (atomicRadii[atomI]/bornRadii[atomI]);
        cavityEnergy               += gammaParameters[atomI]*ratio*ratio*ratio;
 
498
        for (int atomJ = atomI + 1; atomJ < numberOfAtoms; atomJ++) {
Mark Friedrichs's avatar
Mark Friedrichs committed
499
500
501
 
            RealOpenMM deltaR[ReferenceForce::LastDeltaRIndex];
            if (_gbviParameters->getPeriodic())
502
                ReferenceForce::getDeltaRPeriodic(atomCoordinates[atomI], atomCoordinates[atomJ], _gbviParameters->getPeriodicBox(), deltaR);
Mark Friedrichs's avatar
Mark Friedrichs committed
503
            else
504
                ReferenceForce::getDeltaR(atomCoordinates[atomI], atomCoordinates[atomJ], deltaR);
Mark Friedrichs's avatar
Mark Friedrichs committed
505
506
507
508
509
            if (_gbviParameters->getUseCutoff() && deltaR[ReferenceForce::RIndex] > _gbviParameters->getCutoffDistance())
                continue;
  
            RealOpenMM r2           = deltaR[ReferenceForce::R2Index];
            RealOpenMM t            = fourth*r2/(bornRadii[atomI]*bornRadii[atomJ]);         
510
            atomIEnergy            += partialCharges[atomJ]*Sgb(t)/deltaR[ReferenceForce::RIndex];
Mark Friedrichs's avatar
Mark Friedrichs committed
511
512
513
514
515
516
        }
 
        energy += two*partialChargeI*atomIEnergy;
    }
    energy               *= preFactor;
    energy               -= cavityEnergy;
Mark Friedrichs's avatar
Mark Friedrichs committed
517

Mark Friedrichs's avatar
Mark Friedrichs committed
518
519
520
521
    RealOpenMM conversion = static_cast<RealOpenMM>(gbviParameters->getTau());  
    return (conversion*energy);
 
}
Mark Friedrichs's avatar
Mark Friedrichs committed
522

Mark Friedrichs's avatar
Mark Friedrichs committed
523
524
/**---------------------------------------------------------------------------------------

Mark Friedrichs's avatar
Mark Friedrichs committed
525
    Get GB/VI forces
Mark Friedrichs's avatar
Mark Friedrichs committed
526

Mark Friedrichs's avatar
Mark Friedrichs committed
527
528
529
    @param atomCoordinates     atomic coordinates
    @param partialCharges      partial charges
    @param forces              forces
Mark Friedrichs's avatar
Mark Friedrichs committed
530

Mark Friedrichs's avatar
Mark Friedrichs committed
531
    --------------------------------------------------------------------------------------- */
Mark Friedrichs's avatar
Mark Friedrichs committed
532
533


534
void ReferenceGBVI::computeBornForces(std::vector<RealVec>& atomCoordinates, const vector<RealOpenMM>& partialCharges,
535
                                 std::vector<OpenMM::RealVec>& inputForces) {
Mark Friedrichs's avatar
Mark Friedrichs committed
536

Mark Friedrichs's avatar
Mark Friedrichs committed
537
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
538

539
540
541
542
543
544
545
546
547
    static const RealOpenMM zero               = static_cast<RealOpenMM>(0.0);
    static const RealOpenMM one                = static_cast<RealOpenMM>(1.0);
    static const RealOpenMM two                = static_cast<RealOpenMM>(2.0);
    static const RealOpenMM three              = static_cast<RealOpenMM>(3.0);
    static const RealOpenMM four               = static_cast<RealOpenMM>(4.0);
    static const RealOpenMM half               = static_cast<RealOpenMM>(0.5);
    static const RealOpenMM oneThird           = static_cast<RealOpenMM>((1.0/3.0));
    static const RealOpenMM fourth             = static_cast<RealOpenMM>(0.25);
    static const RealOpenMM eighth             = static_cast<RealOpenMM>(0.125);
Mark Friedrichs's avatar
Mark Friedrichs committed
548

Mark Friedrichs's avatar
Mark Friedrichs committed
549
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
550

Mark Friedrichs's avatar
Mark Friedrichs committed
551
552
    const GBVIParameters* gbviParameters       = getGBVIParameters();
    const int numberOfAtoms                    = gbviParameters->getNumberOfAtoms();
553
554
    const vector<RealOpenMM>& atomicRadii        = gbviParameters->getAtomicRadii();
    const vector<RealOpenMM>& gammaParameters    = gbviParameters->getGammaParameters();
Mark Friedrichs's avatar
Mark Friedrichs committed
555

Mark Friedrichs's avatar
Mark Friedrichs committed
556
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
557

Mark Friedrichs's avatar
Mark Friedrichs committed
558
    // constants
Mark Friedrichs's avatar
Mark Friedrichs committed
559

Mark Friedrichs's avatar
Mark Friedrichs committed
560
    const RealOpenMM preFactor                 = two*gbviParameters->getElectricConstant();
Mark Friedrichs's avatar
Mark Friedrichs committed
561

Mark Friedrichs's avatar
Mark Friedrichs committed
562
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
563

Mark Friedrichs's avatar
Mark Friedrichs committed
564
    // compute Born radii
Mark Friedrichs's avatar
Mark Friedrichs committed
565

566
    vector<RealOpenMM> bornRadii(numberOfAtoms);
567
    computeBornRadii(atomCoordinates, bornRadii);
Mark Friedrichs's avatar
Mark Friedrichs committed
568

Mark Friedrichs's avatar
Mark Friedrichs committed
569
    // set energy/forces to zero
Mark Friedrichs's avatar
Mark Friedrichs committed
570

571
572
    std::vector<OpenMM::RealVec> forces(numberOfAtoms);
    for (int ii = 0; ii < numberOfAtoms; ii++) {
Mark Friedrichs's avatar
Mark Friedrichs committed
573
574
575
576
        forces[ii][0] = zero;
        forces[ii][1] = zero;
        forces[ii][2] = zero;
    }
Mark Friedrichs's avatar
Mark Friedrichs committed
577

578
    vector<RealOpenMM> bornForces(numberOfAtoms, 0.0);
Mark Friedrichs's avatar
Mark Friedrichs committed
579

Mark Friedrichs's avatar
Mark Friedrichs committed
580
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
581

Mark Friedrichs's avatar
Mark Friedrichs committed
582
    // first main loop
Mark Friedrichs's avatar
Mark Friedrichs committed
583

584
    for (int atomI = 0; atomI < numberOfAtoms; atomI++) {
Mark Friedrichs's avatar
Mark Friedrichs committed
585
 
Mark Friedrichs's avatar
Mark Friedrichs committed
586
587
588
589
        // partial of polar term wrt Born radius
        // and (dGpol/dr)(dr/dx)
 
        RealOpenMM partialChargeI = preFactor*partialCharges[atomI];
590
        for (int atomJ = atomI; atomJ < numberOfAtoms; atomJ++) {
Mark Friedrichs's avatar
Mark Friedrichs committed
591
592
593
 
            RealOpenMM deltaR[ReferenceForce::LastDeltaRIndex];
            if (_gbviParameters->getPeriodic())
594
                ReferenceForce::getDeltaRPeriodic(atomCoordinates[atomI], atomCoordinates[atomJ], _gbviParameters->getPeriodicBox(), deltaR);
Mark Friedrichs's avatar
Mark Friedrichs committed
595
            else
596
                ReferenceForce::getDeltaR(atomCoordinates[atomI], atomCoordinates[atomJ], deltaR);
Mark Friedrichs's avatar
Mark Friedrichs committed
597
598
            if (_gbviParameters->getUseCutoff() && deltaR[ReferenceForce::RIndex] > _gbviParameters->getCutoffDistance())
                continue;
Mark Friedrichs's avatar
Mark Friedrichs committed
599
  
Mark Friedrichs's avatar
Mark Friedrichs committed
600
            RealOpenMM r2                 = deltaR[ReferenceForce::R2Index];
Mark Friedrichs's avatar
Mark Friedrichs committed
601
602
603
604
605
606
607
608
  
            RealOpenMM deltaX             = deltaR[ReferenceForce::XIndex];
            RealOpenMM deltaY             = deltaR[ReferenceForce::YIndex];
            RealOpenMM deltaZ             = deltaR[ReferenceForce::ZIndex];
  
            RealOpenMM alpha2_ij          = bornRadii[atomI]*bornRadii[atomJ];
            RealOpenMM D_ij               = r2/(four*alpha2_ij);
  
609
            RealOpenMM expTerm            = EXP(-D_ij);
Mark Friedrichs's avatar
Mark Friedrichs committed
610
            RealOpenMM denominator2       = r2 + alpha2_ij*expTerm; 
611
            RealOpenMM denominator        = SQRT(denominator2); 
Mark Friedrichs's avatar
Mark Friedrichs committed
612
613
            
            RealOpenMM Gpol               = (partialChargeI*partialCharges[atomJ])/denominator; 
614
            RealOpenMM dGpol_dr           = -Gpol*(one - fourth*expTerm)/denominator2;  
Mark Friedrichs's avatar
Mark Friedrichs committed
615
  
616
            RealOpenMM dGpol_dalpha2_ij   = -half*Gpol*expTerm*(one + D_ij)/denominator2;
Mark Friedrichs's avatar
Mark Friedrichs committed
617
  
618
            if (atomI != atomJ) {
Mark Friedrichs's avatar
Mark Friedrichs committed
619
620
621
622
623
624
  
                bornForces[atomJ] += dGpol_dalpha2_ij*bornRadii[atomI];
   
                deltaX            *= dGpol_dr;
                deltaY            *= dGpol_dr;
                deltaZ            *= dGpol_dr;
Mark Friedrichs's avatar
Mark Friedrichs committed
625
   
Mark Friedrichs's avatar
Mark Friedrichs committed
626
627
628
                forces[atomI][0]  += deltaX;
                forces[atomI][1]  += deltaY;
                forces[atomI][2]  += deltaZ;
Mark Friedrichs's avatar
Mark Friedrichs committed
629
  
Mark Friedrichs's avatar
Mark Friedrichs committed
630
631
632
                forces[atomJ][0]  -= deltaX;
                forces[atomJ][1]  -= deltaY;
                forces[atomJ][2]  -= deltaZ;
Mark Friedrichs's avatar
Mark Friedrichs committed
633
   
Mark Friedrichs's avatar
Mark Friedrichs committed
634
635
636
637
638
            }
            bornForces[atomI] += dGpol_dalpha2_ij*bornRadii[atomJ];
 
        }
    }
Mark Friedrichs's avatar
Mark Friedrichs committed
639

Mark Friedrichs's avatar
Mark Friedrichs committed
640
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
641

Mark Friedrichs's avatar
Mark Friedrichs committed
642
    // second main loop: (dGpol/dBornRadius)(dBornRadius/dr)(dr/dx)
Mark Friedrichs's avatar
Mark Friedrichs committed
643

Mark Friedrichs's avatar
Mark Friedrichs committed
644
645
    // dGpol/dBornRadius) = bornForces[]
    // dBornRadius/dr     = (1/3)*(bR**4)*(dV/dr)
Mark Friedrichs's avatar
Mark Friedrichs committed
646

647
648
    const vector<RealOpenMM>& scaledRadii           = gbviParameters->getScaledRadii();
    const vector<RealOpenMM>& switchDeriviative     = getSwitchDeriviative();
649
    for (int atomI = 0; atomI < numberOfAtoms; atomI++) {
Mark Friedrichs's avatar
Mark Friedrichs committed
650
651
652
653
654
655
656
657
658
659
660
 
        RealOpenMM R        = atomicRadii[atomI];
 
        // partial of cavity term wrt Born radius
       
        RealOpenMM  ratio   = (atomicRadii[atomI]/bornRadii[atomI]);
        bornForces[atomI]  += (three*gammaParameters[atomI]*ratio*ratio*ratio)/bornRadii[atomI]; 
 
        RealOpenMM b2       = bornRadii[atomI]*bornRadii[atomI];
        bornForces[atomI]  *= switchDeriviative[atomI]*oneThird*b2*b2;
 
661
        for (int atomJ = 0; atomJ < numberOfAtoms; atomJ++) {
Mark Friedrichs's avatar
Mark Friedrichs committed
662
 
663
            if (atomJ != atomI) {
Mark Friedrichs's avatar
Mark Friedrichs committed
664
665
666
667
668
669
670
  
                RealOpenMM deltaX             = atomCoordinates[atomJ][0] - atomCoordinates[atomI][0];
                RealOpenMM deltaY             = atomCoordinates[atomJ][1] - atomCoordinates[atomI][1];
                RealOpenMM deltaZ             = atomCoordinates[atomJ][2] - atomCoordinates[atomI][2];
        
                RealOpenMM deltaR[ReferenceForce::LastDeltaRIndex];
                if (_gbviParameters->getPeriodic())
671
                    ReferenceForce::getDeltaRPeriodic(atomCoordinates[atomI], atomCoordinates[atomJ], _gbviParameters->getPeriodicBox(), deltaR);
Mark Friedrichs's avatar
Mark Friedrichs committed
672
                else
673
                    ReferenceForce::getDeltaR(atomCoordinates[atomI], atomCoordinates[atomJ], deltaR);
Mark Friedrichs's avatar
Mark Friedrichs committed
674
675
676
677
678
679
680
                if (_gbviParameters->getUseCutoff() && deltaR[ReferenceForce::RIndex] > _gbviParameters->getCutoffDistance())
                    continue;
       
                RealOpenMM r2                 = deltaR[ReferenceForce::R2Index];
                           deltaX             = deltaR[ReferenceForce::XIndex];
                           deltaY             = deltaR[ReferenceForce::YIndex];
                           deltaZ             = deltaR[ReferenceForce::ZIndex];
Mark Friedrichs's avatar
Mark Friedrichs committed
681
   
682
                RealOpenMM r                  = SQRT(r2);
Mark Friedrichs's avatar
Mark Friedrichs committed
683
684
685
686
687
688
689
690
    
                RealOpenMM S                  = scaledRadii[atomJ];
                RealOpenMM diff               = (S - R);
   
                RealOpenMM de                 = zero;
   
                // find dRb/dr, where Rb is the Born radius
   
691
                if (FABS(diff) < r) {
692
                    de = ReferenceGBVI::dL_dr(r, r+S, S) + ReferenceGBVI::dL_dx(r, r+S, S);   
693
                    if (R > (r - S)) {
694
                       de -= ReferenceGBVI::dL_dr(r, R, S);  
Mark Friedrichs's avatar
Mark Friedrichs committed
695
                    } else {
696
                       de -= (ReferenceGBVI::dL_dr(r, (r-S), S) + ReferenceGBVI::dL_dx(r, (r-S), S));
Mark Friedrichs's avatar
Mark Friedrichs committed
697
                    }
698
                } else if (r < (S - R)) {
699
700
                    de  = ReferenceGBVI::dL_dr(r, r+S, S) + ReferenceGBVI::dL_dx(r, r+S, S);   
                    de -= (ReferenceGBVI::dL_dr(r, r-S, S) + ReferenceGBVI::dL_dx(r, r-S, S));   
Mark Friedrichs's avatar
Mark Friedrichs committed
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
                }
   
                 // de = (dG/dRb)(dRb/dr)
   
                de                      *= bornForces[atomI]/r;
   
                deltaX                  *= de;
                deltaY                  *= de;
                deltaZ                  *= de;
       
                forces[atomI][0]        += deltaX;
                forces[atomI][1]        += deltaY;
                forces[atomI][2]        += deltaZ;
     
                forces[atomJ][0]        -= deltaX;
                forces[atomJ][1]        -= deltaY;
                forces[atomJ][2]        -= deltaZ;
   
            }
        }
    }
Mark Friedrichs's avatar
Mark Friedrichs committed
722

Mark Friedrichs's avatar
Mark Friedrichs committed
723
    // convert from cal to Joule & apply prefactor tau = (1/diel_solute - 1/diel_solvent)
Mark Friedrichs's avatar
Mark Friedrichs committed
724

Mark Friedrichs's avatar
Mark Friedrichs committed
725
    RealOpenMM conversion = static_cast<RealOpenMM>(gbviParameters->getTau());  
726
    for (int atomI = 0; atomI < numberOfAtoms; atomI++) {
Mark Friedrichs's avatar
Mark Friedrichs committed
727
728
729
730
       inputForces[atomI][0] += conversion*forces[atomI][0];
       inputForces[atomI][1] += conversion*forces[atomI][1];
       inputForces[atomI][2] += conversion*forces[atomI][2];
    }
Mark Friedrichs's avatar
Mark Friedrichs committed
731
732
733
734
735

}

/**---------------------------------------------------------------------------------------

Mark Friedrichs's avatar
Mark Friedrichs committed
736
    Use double precision 
Mark Friedrichs's avatar
Mark Friedrichs committed
737

Mark Friedrichs's avatar
Mark Friedrichs committed
738
    Get volume Eq. 4 of Labute paper [JCC 29 p. 1693-1698 2008])
Mark Friedrichs's avatar
Mark Friedrichs committed
739

Mark Friedrichs's avatar
Mark Friedrichs committed
740
741
742
    @param r                   distance between atoms i & j
    @param R                   atomic radius
    @param S                   scaled atomic radius
Mark Friedrichs's avatar
Mark Friedrichs committed
743

Mark Friedrichs's avatar
Mark Friedrichs committed
744
    @return volume
Mark Friedrichs's avatar
Mark Friedrichs committed
745

Mark Friedrichs's avatar
Mark Friedrichs committed
746
    --------------------------------------------------------------------------------------- */
Mark Friedrichs's avatar
Mark Friedrichs committed
747

748
double ReferenceGBVI::getVolumeD(double r, double R, double S) {
Mark Friedrichs's avatar
Mark Friedrichs committed
749

Mark Friedrichs's avatar
Mark Friedrichs committed
750
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
751

Mark Friedrichs's avatar
Mark Friedrichs committed
752
753
    static const double zero         = 0.0;
    static const double minusThree   = -3.0;
Mark Friedrichs's avatar
Mark Friedrichs committed
754

Mark Friedrichs's avatar
Mark Friedrichs committed
755
    double              diff    = (S - R);
756
    if (fabs(diff) < r) {
Mark Friedrichs's avatar
Mark Friedrichs committed
757

Mark Friedrichs's avatar
Mark Friedrichs committed
758
       double lowerBound = (R > (r - S)) ? R : (r - S);
Mark Friedrichs's avatar
Mark Friedrichs committed
759

760
761
       return (ReferenceGBVI::getLD(r, (r + S),    S) -
               ReferenceGBVI::getLD(r, lowerBound, S));
Mark Friedrichs's avatar
Mark Friedrichs committed
762

763
    } else if (r < diff) {
Mark Friedrichs's avatar
Mark Friedrichs committed
764

765
766
       return ReferenceGBVI::getLD(r, (r + S), S) -
              ReferenceGBVI::getLD(r, (r - S), S) + 
767
              pow(R, minusThree);
Mark Friedrichs's avatar
Mark Friedrichs committed
768

Mark Friedrichs's avatar
Mark Friedrichs committed
769
770
771
    } else {
       return zero;
    }
Mark Friedrichs's avatar
Mark Friedrichs committed
772
773
774
775
}

/**---------------------------------------------------------------------------------------

Mark Friedrichs's avatar
Mark Friedrichs committed
776
    Use double precision 
Mark Friedrichs's avatar
Mark Friedrichs committed
777

Mark Friedrichs's avatar
Mark Friedrichs committed
778
    Get L (used in analytical solution for volume integrals) 
Mark Friedrichs's avatar
Mark Friedrichs committed
779

Mark Friedrichs's avatar
Mark Friedrichs committed
780
781
782
    @param r                   distance between atoms i & j
    @param R                   atomic radius
    @param S                   scaled atomic radius
Mark Friedrichs's avatar
Mark Friedrichs committed
783

Mark Friedrichs's avatar
Mark Friedrichs committed
784
    @return L value (Eq. 4 of Labute paper [JCC 29 p. 1693-1698 2008])
Mark Friedrichs's avatar
Mark Friedrichs committed
785

Mark Friedrichs's avatar
Mark Friedrichs committed
786
    --------------------------------------------------------------------------------------- */
Mark Friedrichs's avatar
Mark Friedrichs committed
787

788
double ReferenceGBVI::getLD(double r, double x, double S) {
Mark Friedrichs's avatar
Mark Friedrichs committed
789

Mark Friedrichs's avatar
Mark Friedrichs committed
790
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
791

Mark Friedrichs's avatar
Mark Friedrichs committed
792
793
794
795
796
    static const double one           =  1.0;
    static const double threeHalves   =  1.5;
    static const double third         =  1.0/3.0;
    static const double fourth        =  0.25;
    static const double eighth        =  0.125;
Mark Friedrichs's avatar
Mark Friedrichs committed
797

Mark Friedrichs's avatar
Mark Friedrichs committed
798
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
799

Mark Friedrichs's avatar
Mark Friedrichs committed
800
    double rInv   = one/r;
Mark Friedrichs's avatar
Mark Friedrichs committed
801

Mark Friedrichs's avatar
Mark Friedrichs committed
802
803
804
    double xInv   = one/x;
    double xInv2  = xInv*xInv;
    double xInv3  = xInv2*xInv;
Mark Friedrichs's avatar
Mark Friedrichs committed
805

Mark Friedrichs's avatar
Mark Friedrichs committed
806
    double diff2  = (r + S)*(r - S);
Mark Friedrichs's avatar
Mark Friedrichs committed
807

808
    return (threeHalves*xInv)*((xInv*fourth*rInv) - (xInv2*third) + (diff2*xInv3*eighth*rInv));
Mark Friedrichs's avatar
Mark Friedrichs committed
809
810
811
812
}

/**---------------------------------------------------------------------------------------

Mark Friedrichs's avatar
Mark Friedrichs committed
813
    Use double precision 
Mark Friedrichs's avatar
Mark Friedrichs committed
814

Mark Friedrichs's avatar
Mark Friedrichs committed
815
    Get partial derivative of L wrt r
Mark Friedrichs's avatar
Mark Friedrichs committed
816

Mark Friedrichs's avatar
Mark Friedrichs committed
817
818
819
    @param r                   distance between atoms i & j
    @param R                   atomic radius
    @param S                   scaled atomic radius
Mark Friedrichs's avatar
Mark Friedrichs committed
820

Mark Friedrichs's avatar
Mark Friedrichs committed
821
    @return partial derivative based on Eq. 4 of Labute paper [JCC 29 p. 1693-1698 2008])
Mark Friedrichs's avatar
Mark Friedrichs committed
822

Mark Friedrichs's avatar
Mark Friedrichs committed
823
    --------------------------------------------------------------------------------------- */
Mark Friedrichs's avatar
Mark Friedrichs committed
824

825
double ReferenceGBVI::dL_drD(double r, double x, double S) {
Mark Friedrichs's avatar
Mark Friedrichs committed
826

Mark Friedrichs's avatar
Mark Friedrichs committed
827
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
828

Mark Friedrichs's avatar
Mark Friedrichs committed
829
830
831
832
833
834
    static const double one           =  1.0;
    static const double threeHalves   =  1.5;
    static const double threeEights   =  0.375;
    static const double third         =  1.0/3.0;
    static const double fourth        =  0.25;
    static const double eighth        =  0.125;
Mark Friedrichs's avatar
Mark Friedrichs committed
835

Mark Friedrichs's avatar
Mark Friedrichs committed
836
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
837

Mark Friedrichs's avatar
Mark Friedrichs committed
838
839
    double rInv   = one/r;
    double rInv2  = rInv*rInv;
Mark Friedrichs's avatar
Mark Friedrichs committed
840

Mark Friedrichs's avatar
Mark Friedrichs committed
841
842
843
    double xInv   = one/x;
    double xInv2  = xInv*xInv;
    double xInv3  = xInv2*xInv;
Mark Friedrichs's avatar
Mark Friedrichs committed
844

Mark Friedrichs's avatar
Mark Friedrichs committed
845
    double diff2  = (r + S)*(r - S);
Mark Friedrichs's avatar
Mark Friedrichs committed
846

847
    return ((-threeHalves*xInv2*rInv2)*(fourth + eighth*diff2*xInv2) + threeEights*xInv3*xInv);
Mark Friedrichs's avatar
Mark Friedrichs committed
848
849
850
851
}

/**---------------------------------------------------------------------------------------

Mark Friedrichs's avatar
Mark Friedrichs committed
852
    Use double precision 
Mark Friedrichs's avatar
Mark Friedrichs committed
853

Mark Friedrichs's avatar
Mark Friedrichs committed
854
    Get partial derivative of L wrt x
Mark Friedrichs's avatar
Mark Friedrichs committed
855

Mark Friedrichs's avatar
Mark Friedrichs committed
856
857
858
    @param r                   distance between atoms i & j
    @param R                   atomic radius
    @param S                   scaled atomic radius
Mark Friedrichs's avatar
Mark Friedrichs committed
859

Mark Friedrichs's avatar
Mark Friedrichs committed
860
    @return partial derivative based on Eq. 4 of Labute paper [JCC 29 p. 1693-1698 2008])
Mark Friedrichs's avatar
Mark Friedrichs committed
861

Mark Friedrichs's avatar
Mark Friedrichs committed
862
    --------------------------------------------------------------------------------------- */
Mark Friedrichs's avatar
Mark Friedrichs committed
863

864
double ReferenceGBVI::dL_dxD(double r, double x, double S) {
Mark Friedrichs's avatar
Mark Friedrichs committed
865

Mark Friedrichs's avatar
Mark Friedrichs committed
866
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
867

Mark Friedrichs's avatar
Mark Friedrichs committed
868
869
870
871
    static const double one           =   1.0;
    static const double half          =   0.5;
    static const double threeHalvesM  =  -1.5;
    static const double third         =   1.0/3.0;
Mark Friedrichs's avatar
Mark Friedrichs committed
872

Mark Friedrichs's avatar
Mark Friedrichs committed
873
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
874

Mark Friedrichs's avatar
Mark Friedrichs committed
875
    double rInv   = one/r;
Mark Friedrichs's avatar
Mark Friedrichs committed
876

Mark Friedrichs's avatar
Mark Friedrichs committed
877
878
879
    double xInv   = one/x;
    double xInv2  = xInv*xInv;
    double xInv3  = xInv2*xInv;
Mark Friedrichs's avatar
Mark Friedrichs committed
880

Mark Friedrichs's avatar
Mark Friedrichs committed
881
    double diff   = (r + S)*(r - S);
Mark Friedrichs's avatar
Mark Friedrichs committed
882

883
    return (threeHalvesM*xInv3)*((half*rInv) - xInv + (half*diff*xInv2*rInv));
Mark Friedrichs's avatar
Mark Friedrichs committed
884
}