"vscode:/vscode.git/clone" did not exist on "6b25abb3c36415e70e1983b0eb145da63edc085a"
CpuGBVI.cpp 35 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
27
28
29
#include <sstream>

#include "../SimTKUtilities/SimTKOpenMMCommon.h"
#include "../SimTKReference/ReferenceForce.h"
Mark Friedrichs's avatar
Mark Friedrichs committed
30
#include "CpuGBVI.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
/**---------------------------------------------------------------------------------------

Mark Friedrichs's avatar
Mark Friedrichs committed
37
    CpuGBVI 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

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

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

Mark Friedrichs's avatar
Mark Friedrichs committed
49
    CpuGBVI 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
54
55
56
57

CpuGBVI::~CpuGBVI( ){
}

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

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* CpuGBVI::getGBVIParameters( void ) 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

Mark Friedrichs's avatar
Mark Friedrichs committed
76
77
void CpuGBVI::setGBVIParameters( GBVIParameters* gbviParameters ){
    _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

Mark Friedrichs's avatar
Mark Friedrichs committed
88
89
RealOpenMMVector& CpuGBVI::getSwitchDeriviative( void ){
    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
105
106

void CpuGBVI::quinticSpline( RealOpenMM x, RealOpenMM rl, RealOpenMM ru,
                             RealOpenMM* outValue, RealOpenMM* outDerivative ){

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

Mark Friedrichs's avatar
Mark Friedrichs committed
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
143
144
145

void CpuGBVI::computeBornRadiiUsingQuinticSpline( RealOpenMM atomicRadius3, RealOpenMM bornSum,
                                                  GBVIParameters* gbviParameters, 
                                                  RealOpenMM* bornRadius, RealOpenMM* switchDeriviative ){

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

Mark Friedrichs's avatar
Mark Friedrichs committed
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
173

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

Mark Friedrichs's avatar
Mark Friedrichs committed
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
    //  (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;
    if( bornSum > splineL ){
        if( bornSum < atomicRadius3 ){
            RealOpenMM splineValue, splineDerivative;
            quinticSpline( bornSum, splineL, atomicRadius3, &splineValue, &splineDerivative ); 
            sum                 = (atomicRadius3 - bornSum)*splineValue + gbviParameters->getQuinticUpperBornRadiusLimit();
            *switchDeriviative  = splineValue - (atomicRadius3 - bornSum)*splineDerivative;
        } else {   
            sum                = gbviParameters->getQuinticUpperBornRadiusLimit();
            *switchDeriviative = zero;
        }
    } else {
        sum                = atomicRadius3 - bornSum; 
        *switchDeriviative = one;
    }
    *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

Mark Friedrichs's avatar
Mark Friedrichs committed
205
void CpuGBVI::computeBornRadii( const vector<RealVec>& atomCoordinates, RealOpenMMVector& 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

Mark Friedrichs's avatar
Mark Friedrichs committed
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
220
221
    GBVIParameters* gbviParameters        = getGBVIParameters();
    int numberOfAtoms                     = gbviParameters->getNumberOfAtoms();
    const RealOpenMMVector& atomicRadii   = gbviParameters->getAtomicRadii();
    const RealOpenMMVector& scaledRadii   = gbviParameters->getScaledRadii();
Mark Friedrichs's avatar
Mark Friedrichs committed
222

Mark Friedrichs's avatar
Mark Friedrichs committed
223
    RealOpenMMVector& 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

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

Mark Friedrichs's avatar
Mark Friedrichs committed
236
        for( int atomJ = 0; atomJ < numberOfAtoms; atomJ++ ){
237

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

        RealOpenMM atomicRadius3 = POW( radiusI, minusThree );
        if( _gbviParameters->getBornRadiusScalingMethod() == GBVIParameters::QuinticSpline ){
           sum                        = atomicRadius3 - sum; 
           bornRadii[atomI]           = POW( sum, minusOneThird );
           switchDeriviatives[atomI]  = one; 
        } else {
           RealOpenMM bornRadius, switchDeriviative;
           computeBornRadiiUsingQuinticSpline( atomicRadius3, sum, gbviParameters, 
                                               &bornRadius, &switchDeriviative );
           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
284

RealOpenMM CpuGBVI::getVolume( RealOpenMM r, RealOpenMM R, RealOpenMM S ){

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

Mark Friedrichs's avatar
Mark Friedrichs committed
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
291
    RealOpenMM              diff         = (S - R);
    if( FABS( diff ) < r ){
Mark Friedrichs's avatar
Mark Friedrichs committed
292

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

Mark Friedrichs's avatar
Mark Friedrichs committed
299
300
301
        return CpuGBVI::getL( r, (r + S), S ) -
               CpuGBVI::getL( r, (r - S), S ) + 
               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
321

RealOpenMM CpuGBVI::getL( RealOpenMM r, RealOpenMM x, RealOpenMM S ){

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

Mark Friedrichs's avatar
Mark Friedrichs committed
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

Mark Friedrichs's avatar
Mark Friedrichs committed
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
356

RealOpenMM CpuGBVI::dL_dr( RealOpenMM r, RealOpenMM x, RealOpenMM S ){

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

Mark Friedrichs's avatar
Mark Friedrichs committed
359
    // static const char* methodName = "\nCpuGBVI::dL_dr";
Mark Friedrichs's avatar
Mark Friedrichs committed
360

Mark Friedrichs's avatar
Mark Friedrichs committed
361
362
363
364
365
366
    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
367

Mark Friedrichs's avatar
Mark Friedrichs committed
368
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
369

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

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

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

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

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

Mark Friedrichs's avatar
Mark Friedrichs committed
384
    Get partial derivative of L wrt x
Mark Friedrichs's avatar
Mark Friedrichs committed
385

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

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

Mark Friedrichs's avatar
Mark Friedrichs committed
392
    --------------------------------------------------------------------------------------- */
Mark Friedrichs's avatar
Mark Friedrichs committed
393
394
395

RealOpenMM CpuGBVI::dL_dx( RealOpenMM r, RealOpenMM x, RealOpenMM S ){

Mark Friedrichs's avatar
Mark Friedrichs committed
396
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
397

Mark Friedrichs's avatar
Mark Friedrichs committed
398
    // static const char* methodName = "CpuGBVI::dL_dx";
Mark Friedrichs's avatar
Mark Friedrichs committed
399

Mark Friedrichs's avatar
Mark Friedrichs committed
400
401
402
403
    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
404

Mark Friedrichs's avatar
Mark Friedrichs committed
405
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
406

Mark Friedrichs's avatar
Mark Friedrichs committed
407
    RealOpenMM rInv   = one/r;
Mark Friedrichs's avatar
Mark Friedrichs committed
408

Mark Friedrichs's avatar
Mark Friedrichs committed
409
410
411
    RealOpenMM xInv   = one/x;
    RealOpenMM xInv2  = xInv*xInv;
    RealOpenMM xInv3  = xInv2*xInv;
Mark Friedrichs's avatar
Mark Friedrichs committed
412

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

Mark Friedrichs's avatar
Mark Friedrichs committed
415
    return (threeHalvesM*xInv3)*( (half*rInv) - xInv + (half*diff*xInv2*rInv) );
Mark Friedrichs's avatar
Mark Friedrichs committed
416
417
418
419
}

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

Mark Friedrichs's avatar
Mark Friedrichs committed
420
    Sgb function
Mark Friedrichs's avatar
Mark Friedrichs committed
421

Mark Friedrichs's avatar
Mark Friedrichs committed
422
    @param t                   r*r*G_i*G_j
Mark Friedrichs's avatar
Mark Friedrichs committed
423

Mark Friedrichs's avatar
Mark Friedrichs committed
424
    @return Sgb (top of p. 1694 of Labute paper [JCC 29 p. 1693-1698 2008])
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
429

RealOpenMM CpuGBVI::Sgb( RealOpenMM t ){

Mark Friedrichs's avatar
Mark Friedrichs committed
430
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
431

Mark Friedrichs's avatar
Mark Friedrichs committed
432
    // static const char* methodName = "CpuGBVI::Sgb";
Mark Friedrichs's avatar
Mark Friedrichs committed
433

Mark Friedrichs's avatar
Mark Friedrichs committed
434
435
436
    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
437

Mark Friedrichs's avatar
Mark Friedrichs committed
438
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
439

Mark Friedrichs's avatar
Mark Friedrichs committed
440
    return ( (t != zero) ? one/SQRT( (one + (fourth*EXP( -t ))/t) ) : zero);
Mark Friedrichs's avatar
Mark Friedrichs committed
441
442
443
444
}

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

Mark Friedrichs's avatar
Mark Friedrichs committed
445
    Get GB/VI energy
Mark Friedrichs's avatar
Mark Friedrichs committed
446

Mark Friedrichs's avatar
Mark Friedrichs committed
447
448
    @param atomCoordinates     atomic coordinates
    @param partialCharges      partial charges
Mark Friedrichs's avatar
Mark Friedrichs committed
449

Mark Friedrichs's avatar
Mark Friedrichs committed
450
    @return energy
Mark Friedrichs's avatar
Mark Friedrichs committed
451

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

Mark Friedrichs's avatar
Mark Friedrichs committed
454
RealOpenMM CpuGBVI::computeBornEnergy( const vector<RealVec>& atomCoordinates, const RealOpenMMVector& partialCharges ){
Mark Friedrichs's avatar
Mark Friedrichs committed
455

Mark Friedrichs's avatar
Mark Friedrichs committed
456
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
457

Mark Friedrichs's avatar
Mark Friedrichs committed
458
459
460
461
462
463
464
465
    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
466

Mark Friedrichs's avatar
Mark Friedrichs committed
467
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
468

Mark Friedrichs's avatar
Mark Friedrichs committed
469
470
471
472
473
    const GBVIParameters* gbviParameters       = getGBVIParameters();
    const RealOpenMM preFactor                 = gbviParameters->getElectricConstant();
    const int numberOfAtoms                    = gbviParameters->getNumberOfAtoms();
    const RealOpenMMVector& atomicRadii        = gbviParameters->getAtomicRadii();
    const RealOpenMMVector& gammaParameters    = gbviParameters->getGammaParameters();
Mark Friedrichs's avatar
Mark Friedrichs committed
474

Mark Friedrichs's avatar
Mark Friedrichs committed
475
    // compute Born radii
Mark Friedrichs's avatar
Mark Friedrichs committed
476

Mark Friedrichs's avatar
Mark Friedrichs committed
477
478
    RealOpenMMVector bornRadii( numberOfAtoms );
    computeBornRadii( atomCoordinates, bornRadii );
Mark Friedrichs's avatar
Mark Friedrichs committed
479

Mark Friedrichs's avatar
Mark Friedrichs committed
480
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
481

Mark Friedrichs's avatar
Mark Friedrichs committed
482
483
484
    // 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
485

Mark Friedrichs's avatar
Mark Friedrichs committed
486
487
    RealOpenMM energy                 = zero;
    RealOpenMM cavityEnergy           = zero;
Mark Friedrichs's avatar
Mark Friedrichs committed
488

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

Mark Friedrichs's avatar
Mark Friedrichs committed
522
523
524
525
    RealOpenMM conversion = static_cast<RealOpenMM>(gbviParameters->getTau());  
    return (conversion*energy);
 
}
Mark Friedrichs's avatar
Mark Friedrichs committed
526

Mark Friedrichs's avatar
Mark Friedrichs committed
527
528
/**---------------------------------------------------------------------------------------

Mark Friedrichs's avatar
Mark Friedrichs committed
529
    Get GB/VI forces
Mark Friedrichs's avatar
Mark Friedrichs committed
530

Mark Friedrichs's avatar
Mark Friedrichs committed
531
532
533
    @param atomCoordinates     atomic coordinates
    @param partialCharges      partial charges
    @param forces              forces
Mark Friedrichs's avatar
Mark Friedrichs committed
534

Mark Friedrichs's avatar
Mark Friedrichs committed
535
    --------------------------------------------------------------------------------------- */
Mark Friedrichs's avatar
Mark Friedrichs committed
536
537


Mark Friedrichs's avatar
Mark Friedrichs committed
538
539
void CpuGBVI::computeBornForces( std::vector<RealVec>& atomCoordinates, const RealOpenMMVector& partialCharges,
                                 std::vector<OpenMM::RealVec>& inputForces){
Mark Friedrichs's avatar
Mark Friedrichs committed
540

Mark Friedrichs's avatar
Mark Friedrichs committed
541
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
542

Mark Friedrichs's avatar
Mark Friedrichs committed
543
544
545
546
547
548
549
550
551
    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
552

Mark Friedrichs's avatar
Mark Friedrichs committed
553
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
554

Mark Friedrichs's avatar
Mark Friedrichs committed
555
556
557
558
    const GBVIParameters* gbviParameters       = getGBVIParameters();
    const int numberOfAtoms                    = gbviParameters->getNumberOfAtoms();
    const RealOpenMMVector& atomicRadii        = gbviParameters->getAtomicRadii();
    const RealOpenMMVector& gammaParameters    = gbviParameters->getGammaParameters();
Mark Friedrichs's avatar
Mark Friedrichs committed
559

Mark Friedrichs's avatar
Mark Friedrichs committed
560
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
561

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

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

Mark Friedrichs's avatar
Mark Friedrichs committed
566
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
567

Mark Friedrichs's avatar
Mark Friedrichs committed
568
    // compute Born radii
Mark Friedrichs's avatar
Mark Friedrichs committed
569

Mark Friedrichs's avatar
Mark Friedrichs committed
570
571
    RealOpenMMVector bornRadii( numberOfAtoms );
    computeBornRadii( atomCoordinates, bornRadii );
Mark Friedrichs's avatar
Mark Friedrichs committed
572

Mark Friedrichs's avatar
Mark Friedrichs committed
573
    // set energy/forces to zero
Mark Friedrichs's avatar
Mark Friedrichs committed
574

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

Mark Friedrichs's avatar
Mark Friedrichs committed
582
    RealOpenMMVector bornForces( numberOfAtoms, 0.0);
Mark Friedrichs's avatar
Mark Friedrichs committed
583

Mark Friedrichs's avatar
Mark Friedrichs committed
584
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
585

Mark Friedrichs's avatar
Mark Friedrichs committed
586
    // first main loop
Mark Friedrichs's avatar
Mark Friedrichs committed
587

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

Mark Friedrichs's avatar
Mark Friedrichs committed
644
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
645

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

Mark Friedrichs's avatar
Mark Friedrichs committed
648
649
    // dGpol/dBornRadius) = bornForces[]
    // dBornRadius/dr     = (1/3)*(bR**4)*(dV/dr)
Mark Friedrichs's avatar
Mark Friedrichs committed
650

Mark Friedrichs's avatar
Mark Friedrichs committed
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
    const RealOpenMMVector& scaledRadii           = gbviParameters->getScaledRadii();
    const RealOpenMMVector& switchDeriviative     = getSwitchDeriviative();
    for( int atomI = 0; atomI < numberOfAtoms; atomI++ ){
 
        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;
 
        for( int atomJ = 0; atomJ < numberOfAtoms; atomJ++ ){
 
            if( atomJ != atomI ){
  
                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())
                    ReferenceForce::getDeltaRPeriodic( atomCoordinates[atomI], atomCoordinates[atomJ], _gbviParameters->getPeriodicBox(), deltaR );
                else
                    ReferenceForce::getDeltaR( atomCoordinates[atomI], atomCoordinates[atomJ], deltaR );
                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
685
   
Mark Friedrichs's avatar
Mark Friedrichs committed
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
                RealOpenMM r                  = SQRT( r2 );
    
                RealOpenMM S                  = scaledRadii[atomJ];
                RealOpenMM diff               = (S - R);
   
                RealOpenMM de                 = zero;
   
                // find dRb/dr, where Rb is the Born radius
   
                de = CpuGBVI::dL_dr( r, r+S, S ) + CpuGBVI::dL_dx( r, r+S, S );   
                if( FABS( diff ) < r ){
                    if( R > (r - S) ){
                       de -= CpuGBVI::dL_dr( r, R, S );  
                    } else {
                       de -= ( CpuGBVI::dL_dr( r, (r-S), S ) + CpuGBVI::dL_dx( r, (r-S), S ) );
                    }
                } else if( r < (S - R) ){
                    de -= ( CpuGBVI::dL_dr( r, r-S, S ) + CpuGBVI::dL_dx( r, r-S, S ) );   
                }
   
                 // 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
725

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

Mark Friedrichs's avatar
Mark Friedrichs committed
728
729
730
731
732
733
    RealOpenMM conversion = static_cast<RealOpenMM>(gbviParameters->getTau());  
    for( int atomI = 0; atomI < numberOfAtoms; atomI++ ){
       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
734
735
736
737
738

}

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

Mark Friedrichs's avatar
Mark Friedrichs committed
739
    Use double precision 
Mark Friedrichs's avatar
Mark Friedrichs committed
740

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

Mark Friedrichs's avatar
Mark Friedrichs committed
743
744
745
    @param r                   distance between atoms i & j
    @param R                   atomic radius
    @param S                   scaled atomic radius
Mark Friedrichs's avatar
Mark Friedrichs committed
746

Mark Friedrichs's avatar
Mark Friedrichs committed
747
    @return volume
Mark Friedrichs's avatar
Mark Friedrichs committed
748

Mark Friedrichs's avatar
Mark Friedrichs committed
749
    --------------------------------------------------------------------------------------- */
Mark Friedrichs's avatar
Mark Friedrichs committed
750
751
752

double CpuGBVI::getVolumeD( double r, double R, double S ){

Mark Friedrichs's avatar
Mark Friedrichs committed
753
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
754

Mark Friedrichs's avatar
Mark Friedrichs committed
755
756
    static const double zero         = 0.0;
    static const double minusThree   = -3.0;
Mark Friedrichs's avatar
Mark Friedrichs committed
757

Mark Friedrichs's avatar
Mark Friedrichs committed
758
759
    double              diff    = (S - R);
    if( fabs( diff ) < r ){
Mark Friedrichs's avatar
Mark Friedrichs committed
760

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

Mark Friedrichs's avatar
Mark Friedrichs committed
763
764
       return (CpuGBVI::getLD( r, (r + S),    S ) -
               CpuGBVI::getLD( r, lowerBound, S ));
Mark Friedrichs's avatar
Mark Friedrichs committed
765

Mark Friedrichs's avatar
Mark Friedrichs committed
766
    } else if( r < diff ){
Mark Friedrichs's avatar
Mark Friedrichs committed
767

Mark Friedrichs's avatar
Mark Friedrichs committed
768
769
770
       return CpuGBVI::getLD( r, (r + S), S ) -
              CpuGBVI::getLD( r, (r - S), S ) + 
              pow( R, minusThree );
Mark Friedrichs's avatar
Mark Friedrichs committed
771

Mark Friedrichs's avatar
Mark Friedrichs committed
772
773
774
    } else {
       return zero;
    }
Mark Friedrichs's avatar
Mark Friedrichs committed
775
776
777
778
}

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

Mark Friedrichs's avatar
Mark Friedrichs committed
779
    Use double precision 
Mark Friedrichs's avatar
Mark Friedrichs committed
780

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

Mark Friedrichs's avatar
Mark Friedrichs committed
783
784
785
    @param r                   distance between atoms i & j
    @param R                   atomic radius
    @param S                   scaled atomic radius
Mark Friedrichs's avatar
Mark Friedrichs committed
786

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

Mark Friedrichs's avatar
Mark Friedrichs committed
789
    --------------------------------------------------------------------------------------- */
Mark Friedrichs's avatar
Mark Friedrichs committed
790
791
792

double CpuGBVI::getLD( double r, double x, double S ){

Mark Friedrichs's avatar
Mark Friedrichs committed
793
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
794

Mark Friedrichs's avatar
Mark Friedrichs committed
795
796
797
798
799
    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
800

Mark Friedrichs's avatar
Mark Friedrichs committed
801
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
802

Mark Friedrichs's avatar
Mark Friedrichs committed
803
    double rInv   = one/r;
Mark Friedrichs's avatar
Mark Friedrichs committed
804

Mark Friedrichs's avatar
Mark Friedrichs committed
805
806
807
    double xInv   = one/x;
    double xInv2  = xInv*xInv;
    double xInv3  = xInv2*xInv;
Mark Friedrichs's avatar
Mark Friedrichs committed
808

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

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

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

Mark Friedrichs's avatar
Mark Friedrichs committed
816
    Use double precision 
Mark Friedrichs's avatar
Mark Friedrichs committed
817

Mark Friedrichs's avatar
Mark Friedrichs committed
818
    Get partial derivative of L wrt r
Mark Friedrichs's avatar
Mark Friedrichs committed
819

Mark Friedrichs's avatar
Mark Friedrichs committed
820
821
822
    @param r                   distance between atoms i & j
    @param R                   atomic radius
    @param S                   scaled atomic radius
Mark Friedrichs's avatar
Mark Friedrichs committed
823

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

Mark Friedrichs's avatar
Mark Friedrichs committed
826
    --------------------------------------------------------------------------------------- */
Mark Friedrichs's avatar
Mark Friedrichs committed
827
828
829

double CpuGBVI::dL_drD( double r, double x, double S ){

Mark Friedrichs's avatar
Mark Friedrichs committed
830
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
831

Mark Friedrichs's avatar
Mark Friedrichs committed
832
833
834
835
836
837
    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
838

Mark Friedrichs's avatar
Mark Friedrichs committed
839
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
840

Mark Friedrichs's avatar
Mark Friedrichs committed
841
842
    double rInv   = one/r;
    double rInv2  = rInv*rInv;
Mark Friedrichs's avatar
Mark Friedrichs committed
843

Mark Friedrichs's avatar
Mark Friedrichs committed
844
845
846
    double xInv   = one/x;
    double xInv2  = xInv*xInv;
    double xInv3  = xInv2*xInv;
Mark Friedrichs's avatar
Mark Friedrichs committed
847

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

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

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

Mark Friedrichs's avatar
Mark Friedrichs committed
855
    Use double precision 
Mark Friedrichs's avatar
Mark Friedrichs committed
856

Mark Friedrichs's avatar
Mark Friedrichs committed
857
    Get partial derivative of L wrt x
Mark Friedrichs's avatar
Mark Friedrichs committed
858

Mark Friedrichs's avatar
Mark Friedrichs committed
859
860
861
    @param r                   distance between atoms i & j
    @param R                   atomic radius
    @param S                   scaled atomic radius
Mark Friedrichs's avatar
Mark Friedrichs committed
862

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

Mark Friedrichs's avatar
Mark Friedrichs committed
865
    --------------------------------------------------------------------------------------- */
Mark Friedrichs's avatar
Mark Friedrichs committed
866
867
868

double CpuGBVI::dL_dxD( double r, double x, double S ){

Mark Friedrichs's avatar
Mark Friedrichs committed
869
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
870

Mark Friedrichs's avatar
Mark Friedrichs committed
871
872
873
874
    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
875

Mark Friedrichs's avatar
Mark Friedrichs committed
876
    // ---------------------------------------------------------------------------------------
Mark Friedrichs's avatar
Mark Friedrichs committed
877

Mark Friedrichs's avatar
Mark Friedrichs committed
878
    double rInv   = one/r;
Mark Friedrichs's avatar
Mark Friedrichs committed
879

Mark Friedrichs's avatar
Mark Friedrichs committed
880
881
882
    double xInv   = one/x;
    double xInv2  = xInv*xInv;
    double xInv3  = xInv2*xInv;
Mark Friedrichs's avatar
Mark Friedrichs committed
883

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

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