"...ssh:/git@developer.sourcefind.cn:2222/tsoc/openmm.git" did not exist on "cf8a03e833ae2dc49853b8935ecb09a4872bce71"
ReferenceObc.cpp 20 KB
Newer Older
1

2
/* Portions copyright (c) 2006-2009 Stanford University and Simbios.
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 * 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>
26
#include <stdlib.h>
27
#include <sstream>
Mark Friedrichs's avatar
Mark Friedrichs committed
28
29
#include <cmath>
#include <cstdio>
30

31
#include "ReferenceForce.h"
32
#include "ReferenceObc.h"
33

34
35
36
using namespace OpenMM;
using namespace std;

37
38
/**---------------------------------------------------------------------------------------

39
    ReferenceObc constructor
40

Mark Friedrichs's avatar
Mark Friedrichs committed
41
42
43
    obcParameters      obcParameters object
    
    --------------------------------------------------------------------------------------- */
44

45
ReferenceObc::ReferenceObc(ObcParameters* obcParameters) : _obcParameters(obcParameters), _includeAceApproximation(1) {
Mark Friedrichs's avatar
Mark Friedrichs committed
46
47
    _obcChain.resize(_obcParameters->getNumberOfAtoms());
}
48

Mark Friedrichs's avatar
Mark Friedrichs committed
49
/**---------------------------------------------------------------------------------------
50

51
    ReferenceObc destructor
52

Mark Friedrichs's avatar
Mark Friedrichs committed
53
    --------------------------------------------------------------------------------------- */
54

55
ReferenceObc::~ReferenceObc() {
56
57
58
59
}

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

Mark Friedrichs's avatar
Mark Friedrichs committed
60
    Get ObcParameters reference
61

Mark Friedrichs's avatar
Mark Friedrichs committed
62
    @return ObcParameters reference
63

Mark Friedrichs's avatar
Mark Friedrichs committed
64
    --------------------------------------------------------------------------------------- */
65

66
ObcParameters* ReferenceObc::getObcParameters() const {
Mark Friedrichs's avatar
Mark Friedrichs committed
67
    return _obcParameters;
68
69
70
71
}

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

Mark Friedrichs's avatar
Mark Friedrichs committed
72
    Set ObcParameters reference
73

Mark Friedrichs's avatar
Mark Friedrichs committed
74
    @param ObcParameters reference
75

Mark Friedrichs's avatar
Mark Friedrichs committed
76
    --------------------------------------------------------------------------------------- */
77

78
void ReferenceObc::setObcParameters( ObcParameters* obcParameters) {
Mark Friedrichs's avatar
Mark Friedrichs committed
79
    _obcParameters = obcParameters;
80
81
82
83
}

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

Mark Friedrichs's avatar
Mark Friedrichs committed
84
   Return flag signalling whether AceApproximation for nonpolar term is to be included
85

Mark Friedrichs's avatar
Mark Friedrichs committed
86
   @return flag
87
88
89

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

90
int ReferenceObc::includeAceApproximation() const {
Mark Friedrichs's avatar
Mark Friedrichs committed
91
    return _includeAceApproximation;
92
93
94
95
}

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

Mark Friedrichs's avatar
Mark Friedrichs committed
96
   Set flag indicating whether AceApproximation is to be included
97

Mark Friedrichs's avatar
Mark Friedrichs committed
98
   @param includeAceApproximation new includeAceApproximation value
99
100
101

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

102
void ReferenceObc::setIncludeAceApproximation(int includeAceApproximation) {
Mark Friedrichs's avatar
Mark Friedrichs committed
103
    _includeAceApproximation = includeAceApproximation;
104
105
106
107
}

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

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

Mark Friedrichs's avatar
Mark Friedrichs committed
110
    @return array
111

Mark Friedrichs's avatar
Mark Friedrichs committed
112
    --------------------------------------------------------------------------------------- */
113

114
vector<RealOpenMM>& ReferenceObc::getObcChain() {
Mark Friedrichs's avatar
Mark Friedrichs committed
115
    return _obcChain;
116
117
118
119
}

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

Mark Friedrichs's avatar
Mark Friedrichs committed
120
    Get Born radii based on papers:
121

Mark Friedrichs's avatar
Mark Friedrichs committed
122
123
       J. Phys. Chem. 1996 100, 19824-19839 (HCT paper)
       Proteins: Structure, Function, and Bioinformatcis 55:383-394 (2004) (OBC paper)
124

Mark Friedrichs's avatar
Mark Friedrichs committed
125
126
    @param atomCoordinates     atomic coordinates
    @param bornRadii           output array of Born radii
127

Mark Friedrichs's avatar
Mark Friedrichs committed
128
    --------------------------------------------------------------------------------------- */
129

130
void ReferenceObc::computeBornRadii(const vector<RealVec>& atomCoordinates, vector<RealOpenMM>& bornRadii) {
131

Mark Friedrichs's avatar
Mark Friedrichs committed
132
    // ---------------------------------------------------------------------------------------
133

134
135
136
137
138
139
    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 half    = static_cast<RealOpenMM>(0.5);
    static const RealOpenMM fourth  = static_cast<RealOpenMM>(0.25);
140

Mark Friedrichs's avatar
Mark Friedrichs committed
141
    // ---------------------------------------------------------------------------------------
142

Mark Friedrichs's avatar
Mark Friedrichs committed
143
    ObcParameters* obcParameters                = getObcParameters();
144

Mark Friedrichs's avatar
Mark Friedrichs committed
145
    int numberOfAtoms                           = obcParameters->getNumberOfAtoms();
146
147
148
    const vector<RealOpenMM>& atomicRadii         = obcParameters->getAtomicRadii();
    const vector<RealOpenMM>& scaledRadiusFactor  = obcParameters->getScaledRadiusFactors();
    vector<RealOpenMM>& obcChain                  = getObcChain();
149

Mark Friedrichs's avatar
Mark Friedrichs committed
150
151
152
153
    RealOpenMM dielectricOffset                 = obcParameters->getDielectricOffset();
    RealOpenMM alphaObc                         = obcParameters->getAlphaObc();
    RealOpenMM betaObc                          = obcParameters->getBetaObc();
    RealOpenMM gammaObc                         = obcParameters->getGammaObc();
154

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

Mark Friedrichs's avatar
Mark Friedrichs committed
157
    // calculate Born radii
158

159
    for (int atomI = 0; atomI < numberOfAtoms; atomI++) {
Mark Friedrichs's avatar
Mark Friedrichs committed
160
161
162
      
       RealOpenMM radiusI         = atomicRadii[atomI];
       RealOpenMM offsetRadiusI   = radiusI - dielectricOffset;
163

Mark Friedrichs's avatar
Mark Friedrichs committed
164
165
       RealOpenMM radiusIInverse  = one/offsetRadiusI;
       RealOpenMM sum             = zero;
166

Mark Friedrichs's avatar
Mark Friedrichs committed
167
       // HCT code
168

169
       for (int atomJ = 0; atomJ < numberOfAtoms; atomJ++) {
170

171
          if (atomJ != atomI) {
172

Mark Friedrichs's avatar
Mark Friedrichs committed
173
174
             RealOpenMM deltaR[ReferenceForce::LastDeltaRIndex];
             if (_obcParameters->getPeriodic())
175
                 ReferenceForce::getDeltaRPeriodic(atomCoordinates[atomI], atomCoordinates[atomJ], _obcParameters->getPeriodicBox(), deltaR);
Mark Friedrichs's avatar
Mark Friedrichs committed
176
             else
177
                 ReferenceForce::getDeltaR(atomCoordinates[atomI], atomCoordinates[atomJ], deltaR);
Mark Friedrichs's avatar
Mark Friedrichs committed
178
179
180
             RealOpenMM r               = deltaR[ReferenceForce::RIndex];
             if (_obcParameters->getUseCutoff() && r > _obcParameters->getCutoffDistance())
                 continue;
181

Mark Friedrichs's avatar
Mark Friedrichs committed
182
183
184
             RealOpenMM offsetRadiusJ   = atomicRadii[atomJ] - dielectricOffset; 
             RealOpenMM scaledRadiusJ   = offsetRadiusJ*scaledRadiusFactor[atomJ];
             RealOpenMM rScaledRadiusJ  = r + scaledRadiusJ;
185

186
             if (offsetRadiusI < rScaledRadiusJ) {
Mark Friedrichs's avatar
Mark Friedrichs committed
187
                RealOpenMM rInverse = one/r;
188
                RealOpenMM l_ij     = offsetRadiusI > FABS(r - scaledRadiusJ) ? offsetRadiusI : FABS(r - scaledRadiusJ);
Mark Friedrichs's avatar
Mark Friedrichs committed
189
                           l_ij     = one/l_ij;
190

Mark Friedrichs's avatar
Mark Friedrichs committed
191
                RealOpenMM u_ij     = one/rScaledRadiusJ;
192

Mark Friedrichs's avatar
Mark Friedrichs committed
193
194
195
                RealOpenMM l_ij2    = l_ij*l_ij;
                RealOpenMM u_ij2    = u_ij*u_ij;
 
196
197
                RealOpenMM ratio    = LN((u_ij/l_ij));
                RealOpenMM term     = l_ij - u_ij + fourth*r*(u_ij2 - l_ij2)  + (half*rInverse*ratio) + (fourth*scaledRadiusJ*scaledRadiusJ*rInverse)*(l_ij2 - u_ij2);
198

Mark Friedrichs's avatar
Mark Friedrichs committed
199
200
201
                // this case (atom i completely inside atom j) is not considered in the original paper
                // Jay Ponder and the authors of Tinker recognized this and
                // worked out the details
202

203
204
                if (offsetRadiusI < (scaledRadiusJ - r)) {
                   term += two*(radiusIInverse - l_ij);
Mark Friedrichs's avatar
Mark Friedrichs committed
205
206
                }
                sum += term;
207

Mark Friedrichs's avatar
Mark Friedrichs committed
208
209
210
211
212
213
214
215
216
             }
          }
       }
 
       // OBC-specific code (Eqs. 6-8 in paper)

       sum                  *= half*offsetRadiusI;
       RealOpenMM sum2       = sum*sum;
       RealOpenMM sum3       = sum*sum2;
217
       RealOpenMM tanhSum    = TANH(alphaObc*sum - betaObc*sum2 + gammaObc*sum3);
Mark Friedrichs's avatar
Mark Friedrichs committed
218
       
219
       bornRadii[atomI]      = one/(one/offsetRadiusI - tanhSum/radiusI); 
Mark Friedrichs's avatar
Mark Friedrichs committed
220
 
221
       obcChain[atomI]       = offsetRadiusI*(alphaObc - two*betaObc*sum + three*gammaObc*sum2);
Mark Friedrichs's avatar
Mark Friedrichs committed
222
       obcChain[atomI]       = (one - tanhSum*tanhSum)*obcChain[atomI]/radiusI;
223

Mark Friedrichs's avatar
Mark Friedrichs committed
224
225
    }
}
226

Mark Friedrichs's avatar
Mark Friedrichs committed
227
/**---------------------------------------------------------------------------------------
228

Mark Friedrichs's avatar
Mark Friedrichs committed
229
    Get nonpolar solvation force constribution via ACE approximation
230

Mark Friedrichs's avatar
Mark Friedrichs committed
231
232
233
234
    @param obcParameters parameters
    @param bornRadii                 Born radii
    @param energy                    energy (output): value is incremented from input value 
    @param forces                    forces: values are incremented from input values
235

Mark Friedrichs's avatar
Mark Friedrichs committed
236
    --------------------------------------------------------------------------------------- */
237

238
void ReferenceObc::computeAceNonPolarForce(const ObcParameters* obcParameters,
239
                                      const vector<RealOpenMM>& bornRadii,
Mark Friedrichs's avatar
Mark Friedrichs committed
240
                                      RealOpenMM* energy,
241
                                      vector<RealOpenMM>& forces) const {
242

Mark Friedrichs's avatar
Mark Friedrichs committed
243
    // ---------------------------------------------------------------------------------------
244

245
    static const RealOpenMM zero     = static_cast<RealOpenMM>(0.0);
Mark Friedrichs's avatar
Mark Friedrichs committed
246
    static const RealOpenMM minusSix = -6.0;
247
    static const RealOpenMM six      = static_cast<RealOpenMM>(6.0);
248

Mark Friedrichs's avatar
Mark Friedrichs committed
249
    // ---------------------------------------------------------------------------------------
250

Mark Friedrichs's avatar
Mark Friedrichs committed
251
    // compute the nonpolar solvation via ACE approximation
252

Mark Friedrichs's avatar
Mark Friedrichs committed
253
254
    const RealOpenMM probeRadius          = obcParameters->getProbeRadius();
    const RealOpenMM surfaceAreaFactor    = obcParameters->getPi4Asolv();
255

256
    const vector<RealOpenMM>& atomicRadii   = obcParameters->getAtomicRadii();
Mark Friedrichs's avatar
Mark Friedrichs committed
257
    int numberOfAtoms                     = obcParameters->getNumberOfAtoms();
258

Mark Friedrichs's avatar
Mark Friedrichs committed
259
    // the original ACE equation is based on Eq.2 of
260

Mark Friedrichs's avatar
Mark Friedrichs committed
261
262
263
264
    // M. Schaefer, C. Bartels and M. Karplus, "Solution Conformations
    // and Thermodynamics of Structured Peptides: Molecular Dynamics
    // Simulation with an Implicit Solvation Model", J. Mol. Biol.,
    // 284, 835-848 (1998)  (ACE Method)
265

Mark Friedrichs's avatar
Mark Friedrichs committed
266
267
    // The original equation includes the factor (atomicRadii[atomI]/bornRadii[atomI]) to the first power,
    // whereas here the ratio is raised to the sixth power: (atomicRadii[atomI]/bornRadii[atomI])**6
268

Mark Friedrichs's avatar
Mark Friedrichs committed
269
270
271
    // This modification was made by Jay Ponder who observed it gave better correlations w/
    // observed values. He did not think it was important enough to write up, so there is
    // no paper to cite.
272

273
274
    for (int atomI = 0; atomI < numberOfAtoms; atomI++) {
        if (bornRadii[atomI] > zero) {
Mark Friedrichs's avatar
Mark Friedrichs committed
275
            RealOpenMM r            = atomicRadii[atomI] + probeRadius;
276
            RealOpenMM ratio6       = POW(atomicRadii[atomI]/bornRadii[atomI], six);
Mark Friedrichs's avatar
Mark Friedrichs committed
277
278
279
280
281
            RealOpenMM saTerm       = surfaceAreaFactor*r*r*ratio6;
            *energy                += saTerm;
            forces[atomI]          += minusSix*saTerm/bornRadii[atomI]; 
        }
    }
282
283
284
285
}

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

Mark Friedrichs's avatar
Mark Friedrichs committed
286
    Get Obc Born energy and forces
287

Mark Friedrichs's avatar
Mark Friedrichs committed
288
289
290
    @param atomCoordinates     atomic coordinates
    @param partialCharges      partial charges
    @param forces              forces
291

Mark Friedrichs's avatar
Mark Friedrichs committed
292
    The array bornRadii is also updated and the obcEnergy
293

Mark Friedrichs's avatar
Mark Friedrichs committed
294
    --------------------------------------------------------------------------------------- */
295

296
RealOpenMM ReferenceObc::computeBornEnergyForces(const vector<RealVec>& atomCoordinates,
297
                                           const vector<RealOpenMM>& partialCharges, vector<RealVec>& inputForces) {
298

Mark Friedrichs's avatar
Mark Friedrichs committed
299
    // ---------------------------------------------------------------------------------------
300

301
302
303
304
305
306
307
308
    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);
309

Mark Friedrichs's avatar
Mark Friedrichs committed
310
    // constants
311

312
313
314
315
316
    const int numberOfAtoms = _obcParameters->getNumberOfAtoms();
    const RealOpenMM dielectricOffset = _obcParameters->getDielectricOffset();
    const RealOpenMM cutoffDistance = _obcParameters->getCutoffDistance();
    const RealOpenMM soluteDielectric = _obcParameters->getSoluteDielectric();
    const RealOpenMM solventDielectric = _obcParameters->getSolventDielectric();
Mark Friedrichs's avatar
Mark Friedrichs committed
317
    RealOpenMM preFactor;
318
319
320
    if (soluteDielectric != zero && solventDielectric != zero)
        preFactor = two*_obcParameters->getElectricConstant()*((one/soluteDielectric) - (one/solventDielectric));
    else
Mark Friedrichs's avatar
Mark Friedrichs committed
321
        preFactor = zero;
322

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

Mark Friedrichs's avatar
Mark Friedrichs committed
325
    // compute Born radii
326

327
    vector<RealOpenMM> bornRadii(numberOfAtoms);
328
    computeBornRadii(atomCoordinates, bornRadii);
329

Mark Friedrichs's avatar
Mark Friedrichs committed
330
    // set energy/forces to zero
331

Mark Friedrichs's avatar
Mark Friedrichs committed
332
    RealOpenMM obcEnergy                 = zero;
333
    vector<RealOpenMM> bornForces(numberOfAtoms, 0.0);
334

Mark Friedrichs's avatar
Mark Friedrichs committed
335
    // ---------------------------------------------------------------------------------------
336

Mark Friedrichs's avatar
Mark Friedrichs committed
337
338
    // compute the nonpolar solvation via ACE approximation
     
339
340
    if (includeAceApproximation()) {
       computeAceNonPolarForce(_obcParameters, bornRadii, &obcEnergy, bornForces);
Mark Friedrichs's avatar
Mark Friedrichs committed
341
    }
342
 
Mark Friedrichs's avatar
Mark Friedrichs committed
343
    // ---------------------------------------------------------------------------------------
344

Mark Friedrichs's avatar
Mark Friedrichs committed
345
    // first main loop
346

347
    for (int atomI = 0; atomI < numberOfAtoms; atomI++) {
348
 
Mark Friedrichs's avatar
Mark Friedrichs committed
349
       RealOpenMM partialChargeI = preFactor*partialCharges[atomI];
350
       for (int atomJ = atomI; atomJ < numberOfAtoms; atomJ++) {
351

Mark Friedrichs's avatar
Mark Friedrichs committed
352
353
          RealOpenMM deltaR[ReferenceForce::LastDeltaRIndex];
          if (_obcParameters->getPeriodic())
354
              ReferenceForce::getDeltaRPeriodic(atomCoordinates[atomI], atomCoordinates[atomJ], _obcParameters->getPeriodicBox(), deltaR);
Mark Friedrichs's avatar
Mark Friedrichs committed
355
          else
356
              ReferenceForce::getDeltaR(atomCoordinates[atomI], atomCoordinates[atomJ], deltaR);
357
          if (_obcParameters->getUseCutoff() && deltaR[ReferenceForce::RIndex] > cutoffDistance)
Mark Friedrichs's avatar
Mark Friedrichs committed
358
              continue;
359

Mark Friedrichs's avatar
Mark Friedrichs committed
360
361
362
363
          RealOpenMM r2                 = deltaR[ReferenceForce::R2Index];
          RealOpenMM deltaX             = deltaR[ReferenceForce::XIndex];
          RealOpenMM deltaY             = deltaR[ReferenceForce::YIndex];
          RealOpenMM deltaZ             = deltaR[ReferenceForce::ZIndex];
364

Mark Friedrichs's avatar
Mark Friedrichs committed
365
366
          RealOpenMM alpha2_ij          = bornRadii[atomI]*bornRadii[atomJ];
          RealOpenMM D_ij               = r2/(four*alpha2_ij);
367

368
          RealOpenMM expTerm            = EXP(-D_ij);
Mark Friedrichs's avatar
Mark Friedrichs committed
369
          RealOpenMM denominator2       = r2 + alpha2_ij*expTerm; 
370
          RealOpenMM denominator        = SQRT(denominator2); 
Mark Friedrichs's avatar
Mark Friedrichs committed
371
372
          
          RealOpenMM Gpol               = (partialChargeI*partialCharges[atomJ])/denominator; 
373
          RealOpenMM dGpol_dr           = -Gpol*(one - fourth*expTerm)/denominator2;  
374

375
          RealOpenMM dGpol_dalpha2_ij   = -half*Gpol*expTerm*(one + D_ij)/denominator2;
376
377
          
          RealOpenMM energy = Gpol;
378

379
          if (atomI != atomJ) {
380

381
382
383
              if (_obcParameters->getUseCutoff())
                  energy -= partialChargeI*partialCharges[atomJ]/cutoffDistance;
              
Mark Friedrichs's avatar
Mark Friedrichs committed
384
              bornForces[atomJ]        += dGpol_dalpha2_ij*bornRadii[atomI];
385

Mark Friedrichs's avatar
Mark Friedrichs committed
386
387
388
              deltaX                   *= dGpol_dr;
              deltaY                   *= dGpol_dr;
              deltaZ                   *= dGpol_dr;
389

Mark Friedrichs's avatar
Mark Friedrichs committed
390
391
392
              inputForces[atomI][0]    += deltaX;
              inputForces[atomI][1]    += deltaY;
              inputForces[atomI][2]    += deltaZ;
393

Mark Friedrichs's avatar
Mark Friedrichs committed
394
395
396
              inputForces[atomJ][0]    -= deltaX;
              inputForces[atomJ][1]    -= deltaY;
              inputForces[atomJ][2]    -= deltaZ;
397

Mark Friedrichs's avatar
Mark Friedrichs committed
398
          } else {
399
             energy *= half;
Mark Friedrichs's avatar
Mark Friedrichs committed
400
          }
401

402
          obcEnergy         += energy;
Mark Friedrichs's avatar
Mark Friedrichs committed
403
          bornForces[atomI] += dGpol_dalpha2_ij*bornRadii[atomJ];
404

Mark Friedrichs's avatar
Mark Friedrichs committed
405
406
       }
    }
407

Mark Friedrichs's avatar
Mark Friedrichs committed
408
    // ---------------------------------------------------------------------------------------
409

Mark Friedrichs's avatar
Mark Friedrichs committed
410
    // second main loop
411

412
413
    const vector<RealOpenMM>& obcChain            = getObcChain();
    const vector<RealOpenMM>& atomicRadii         = _obcParameters->getAtomicRadii();
414

415
416
417
    const RealOpenMM alphaObc                   = _obcParameters->getAlphaObc();
    const RealOpenMM betaObc                    = _obcParameters->getBetaObc();
    const RealOpenMM gammaObc                   = _obcParameters->getGammaObc();
418
    const vector<RealOpenMM>& scaledRadiusFactor  = _obcParameters->getScaledRadiusFactors();
419
420
421

    // compute factor that depends only on the outer loop index

422
    for (int atomI = 0; atomI < numberOfAtoms; atomI++) {
Mark Friedrichs's avatar
Mark Friedrichs committed
423
424
       bornForces[atomI] *= bornRadii[atomI]*bornRadii[atomI]*obcChain[atomI];      
    }
425

426
    for (int atomI = 0; atomI < numberOfAtoms; atomI++) {
427
 
Mark Friedrichs's avatar
Mark Friedrichs committed
428
       // radius w/ dielectric offset applied
429

Mark Friedrichs's avatar
Mark Friedrichs committed
430
431
       RealOpenMM radiusI        = atomicRadii[atomI];
       RealOpenMM offsetRadiusI  = radiusI - dielectricOffset;
432

433
       for (int atomJ = 0; atomJ < numberOfAtoms; atomJ++) {
434

435
          if (atomJ != atomI) {
436

Mark Friedrichs's avatar
Mark Friedrichs committed
437
438
             RealOpenMM deltaR[ReferenceForce::LastDeltaRIndex];
             if (_obcParameters->getPeriodic())
439
                ReferenceForce::getDeltaRPeriodic(atomCoordinates[atomI], atomCoordinates[atomJ], _obcParameters->getPeriodicBox(), deltaR);
Mark Friedrichs's avatar
Mark Friedrichs committed
440
             else 
441
                ReferenceForce::getDeltaR(atomCoordinates[atomI], atomCoordinates[atomJ], deltaR);
442
             if (_obcParameters->getUseCutoff() && deltaR[ReferenceForce::RIndex] > cutoffDistance)
Mark Friedrichs's avatar
Mark Friedrichs committed
443
444
445
446
447
448
                    continue;
    
             RealOpenMM deltaX             = deltaR[ReferenceForce::XIndex];
             RealOpenMM deltaY             = deltaR[ReferenceForce::YIndex];
             RealOpenMM deltaZ             = deltaR[ReferenceForce::ZIndex];
             RealOpenMM r                  = deltaR[ReferenceForce::RIndex];
449
 
Mark Friedrichs's avatar
Mark Friedrichs committed
450
             // radius w/ dielectric offset applied
451

Mark Friedrichs's avatar
Mark Friedrichs committed
452
             RealOpenMM offsetRadiusJ      = atomicRadii[atomJ] - dielectricOffset;
453

Mark Friedrichs's avatar
Mark Friedrichs committed
454
455
456
             RealOpenMM scaledRadiusJ      = offsetRadiusJ*scaledRadiusFactor[atomJ];
             RealOpenMM scaledRadiusJ2     = scaledRadiusJ*scaledRadiusJ;
             RealOpenMM rScaledRadiusJ     = r + scaledRadiusJ;
457

Mark Friedrichs's avatar
Mark Friedrichs committed
458
459
             // dL/dr & dU/dr are zero (this can be shown analytically)
             // removed from calculation
460

461
             if (offsetRadiusI < rScaledRadiusJ) {
462

463
                RealOpenMM l_ij          = offsetRadiusI > FABS(r - scaledRadiusJ) ? offsetRadiusI : FABS(r - scaledRadiusJ);
Mark Friedrichs's avatar
Mark Friedrichs committed
464
                     l_ij                = one/l_ij;
465

Mark Friedrichs's avatar
Mark Friedrichs committed
466
                RealOpenMM u_ij          = one/rScaledRadiusJ;
467

Mark Friedrichs's avatar
Mark Friedrichs committed
468
                RealOpenMM l_ij2         = l_ij*l_ij;
469

Mark Friedrichs's avatar
Mark Friedrichs committed
470
                RealOpenMM u_ij2         = u_ij*u_ij;
471
 
Mark Friedrichs's avatar
Mark Friedrichs committed
472
473
                RealOpenMM rInverse      = one/r;
                RealOpenMM r2Inverse     = rInverse*rInverse;
474

475
                RealOpenMM t3            = eighth*(one + scaledRadiusJ2*r2Inverse)*(l_ij2 - u_ij2) + fourth*LN(u_ij/l_ij)*r2Inverse;
476

Mark Friedrichs's avatar
Mark Friedrichs committed
477
                RealOpenMM de            = bornForces[atomI]*t3*rInverse;
478

Mark Friedrichs's avatar
Mark Friedrichs committed
479
480
481
482
483
484
485
                deltaX                  *= de;
                deltaY                  *= de;
                deltaZ                  *= de;
    
                inputForces[atomI][0]   -= deltaX;
                inputForces[atomI][1]   -= deltaY;
                inputForces[atomI][2]   -= deltaZ;
486
  
Mark Friedrichs's avatar
Mark Friedrichs committed
487
488
489
                inputForces[atomJ][0]   += deltaX;
                inputForces[atomJ][1]   += deltaY;
                inputForces[atomJ][2]   += deltaZ;
490
 
Mark Friedrichs's avatar
Mark Friedrichs committed
491
492
493
             }
          }
       }
494

Mark Friedrichs's avatar
Mark Friedrichs committed
495
    }
496

Mark Friedrichs's avatar
Mark Friedrichs committed
497
    return obcEnergy;
498
}