CpuObc.cpp 24 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
32
#include "SimTKOpenMMCommon.h"
#include "ReferenceForce.h"
Mark Friedrichs's avatar
Mark Friedrichs committed
33
#include "CpuObc.h"
34

35
36
37
using namespace OpenMM;
using namespace std;

38
39
/**---------------------------------------------------------------------------------------

Mark Friedrichs's avatar
Mark Friedrichs committed
40
    CpuObc constructor
41

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

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

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

Mark Friedrichs's avatar
Mark Friedrichs committed
52
    CpuObc destructor
53

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

Mark Friedrichs's avatar
Mark Friedrichs committed
56
CpuObc::~CpuObc( ){
57
58
59
60
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Mark Friedrichs's avatar
Mark Friedrichs committed
131
void CpuObc::computeBornRadii( const vector<RealVec>& atomCoordinates, vector<RealOpenMM>& bornRadii ){
132

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

Mark Friedrichs's avatar
Mark Friedrichs committed
135
136
137
138
139
140
    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 );
141

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

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

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

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

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

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

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

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

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

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

Mark Friedrichs's avatar
Mark Friedrichs committed
172
          if( atomJ != atomI ){
173

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

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

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

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

Mark Friedrichs's avatar
Mark Friedrichs committed
194
195
196
197
198
                RealOpenMM l_ij2    = l_ij*l_ij;
                RealOpenMM u_ij2    = u_ij*u_ij;
 
                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);
199

Mark Friedrichs's avatar
Mark Friedrichs committed
200
201
202
                // 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
203

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

Mark Friedrichs's avatar
Mark Friedrichs committed
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
             }
          }
       }
 
       // OBC-specific code (Eqs. 6-8 in paper)

       sum                  *= half*offsetRadiusI;
       RealOpenMM sum2       = sum*sum;
       RealOpenMM sum3       = sum*sum2;
       RealOpenMM tanhSum    = TANH( alphaObc*sum - betaObc*sum2 + gammaObc*sum3 );
       
       bornRadii[atomI]      = one/( one/offsetRadiusI - tanhSum/radiusI ); 
 
       obcChain[atomI]       = offsetRadiusI*( alphaObc - two*betaObc*sum + three*gammaObc*sum2 );
       obcChain[atomI]       = (one - tanhSum*tanhSum)*obcChain[atomI]/radiusI;
224

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

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

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

Mark Friedrichs's avatar
Mark Friedrichs committed
232
233
234
235
    @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
236

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

Mark Friedrichs's avatar
Mark Friedrichs committed
239
240
241
242
void CpuObc::computeAceNonPolarForce( const ObcParameters* obcParameters,
                                      const RealOpenMMVector& bornRadii, 
                                      RealOpenMM* energy,
                                      RealOpenMMVector& forces ) const {
243

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

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

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

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

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

Mark Friedrichs's avatar
Mark Friedrichs committed
257
258
    const RealOpenMMVector& atomicRadii   = obcParameters->getAtomicRadii();
    int numberOfAtoms                     = obcParameters->getNumberOfAtoms();
259

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

Mark Friedrichs's avatar
Mark Friedrichs committed
262
263
264
265
    // 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)
266

Mark Friedrichs's avatar
Mark Friedrichs committed
267
268
    // 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
269

Mark Friedrichs's avatar
Mark Friedrichs committed
270
271
272
    // 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.
273

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

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

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

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

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

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

Mark Friedrichs's avatar
Mark Friedrichs committed
297
298
RealOpenMM CpuObc::computeBornEnergyForces( const vector<RealVec>& atomCoordinates,
                                            const RealOpenMMVector& partialCharges, vector<RealVec>& inputForces ){
299

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

Mark Friedrichs's avatar
Mark Friedrichs committed
302
303
304
305
306
307
308
309
    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 );
310

Mark Friedrichs's avatar
Mark Friedrichs committed
311
    // ---------------------------------------------------------------------------------------
312

Mark Friedrichs's avatar
Mark Friedrichs committed
313
314
    const ObcParameters* obcParameters = getObcParameters();
    const int numberOfAtoms            = obcParameters->getNumberOfAtoms();
315

Mark Friedrichs's avatar
Mark Friedrichs committed
316
    // ---------------------------------------------------------------------------------------
317

Mark Friedrichs's avatar
Mark Friedrichs committed
318
    // constants
319

Mark Friedrichs's avatar
Mark Friedrichs committed
320
321
322
323
324
325
    RealOpenMM preFactor;
    if( obcParameters->getSoluteDielectric() != zero && obcParameters->getSolventDielectric() != zero ){
        preFactor = two*obcParameters->getElectricConstant()*( (one/obcParameters->getSoluteDielectric()) - (one/obcParameters->getSolventDielectric()) );
    } else {
        preFactor = zero;
    }   
326

Mark Friedrichs's avatar
Mark Friedrichs committed
327
    const RealOpenMM dielectricOffset    = obcParameters->getDielectricOffset();
328

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

Mark Friedrichs's avatar
Mark Friedrichs committed
331
    // compute Born radii
332

Mark Friedrichs's avatar
Mark Friedrichs committed
333
334
    RealOpenMMVector bornRadii( numberOfAtoms );
    computeBornRadii( atomCoordinates, bornRadii );
335

Mark Friedrichs's avatar
Mark Friedrichs committed
336
    // set energy/forces to zero
337

Mark Friedrichs's avatar
Mark Friedrichs committed
338
339
    RealOpenMM obcEnergy                 = zero;
    RealOpenMMVector bornForces( numberOfAtoms, 0.0 );
340

Mark Friedrichs's avatar
Mark Friedrichs committed
341
    // ---------------------------------------------------------------------------------------
342

Mark Friedrichs's avatar
Mark Friedrichs committed
343
344
345
346
347
    // compute the nonpolar solvation via ACE approximation
     
    if( includeAceApproximation() ){
       computeAceNonPolarForce( obcParameters, bornRadii, &obcEnergy, bornForces );
    }
348
 
Mark Friedrichs's avatar
Mark Friedrichs committed
349
    // ---------------------------------------------------------------------------------------
350

Mark Friedrichs's avatar
Mark Friedrichs committed
351
    // first main loop
352

Mark Friedrichs's avatar
Mark Friedrichs committed
353
    for( int atomI = 0; atomI < numberOfAtoms; atomI++ ){
354
 
Mark Friedrichs's avatar
Mark Friedrichs committed
355
356
       RealOpenMM partialChargeI = preFactor*partialCharges[atomI];
       for( int atomJ = atomI; atomJ < numberOfAtoms; atomJ++ ){
357

Mark Friedrichs's avatar
Mark Friedrichs committed
358
359
360
361
362
363
364
          RealOpenMM deltaR[ReferenceForce::LastDeltaRIndex];
          if (_obcParameters->getPeriodic())
              ReferenceForce::getDeltaRPeriodic( atomCoordinates[atomI], atomCoordinates[atomJ], _obcParameters->getPeriodicBox(), deltaR );
          else
              ReferenceForce::getDeltaR( atomCoordinates[atomI], atomCoordinates[atomJ], deltaR );
          if (_obcParameters->getUseCutoff() && deltaR[ReferenceForce::RIndex] > _obcParameters->getCutoffDistance())
              continue;
365

Mark Friedrichs's avatar
Mark Friedrichs committed
366
367
368
369
          RealOpenMM r2                 = deltaR[ReferenceForce::R2Index];
          RealOpenMM deltaX             = deltaR[ReferenceForce::XIndex];
          RealOpenMM deltaY             = deltaR[ReferenceForce::YIndex];
          RealOpenMM deltaZ             = deltaR[ReferenceForce::ZIndex];
370

Mark Friedrichs's avatar
Mark Friedrichs committed
371
372
          RealOpenMM alpha2_ij          = bornRadii[atomI]*bornRadii[atomJ];
          RealOpenMM D_ij               = r2/(four*alpha2_ij);
373

Mark Friedrichs's avatar
Mark Friedrichs committed
374
375
376
377
378
379
          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;  
380

Mark Friedrichs's avatar
Mark Friedrichs committed
381
          RealOpenMM dGpol_dalpha2_ij   = -half*Gpol*expTerm*( one + D_ij )/denominator2;
382

Mark Friedrichs's avatar
Mark Friedrichs committed
383
          if( atomI != atomJ ){
384

Mark Friedrichs's avatar
Mark Friedrichs committed
385
              bornForces[atomJ]        += dGpol_dalpha2_ij*bornRadii[atomI];
386

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

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

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

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

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

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

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

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

Mark Friedrichs's avatar
Mark Friedrichs committed
413
414
    const RealOpenMMVector& obcChain            = getObcChain();
    const RealOpenMMVector& atomicRadii         = obcParameters->getAtomicRadii();
415

Mark Friedrichs's avatar
Mark Friedrichs committed
416
417
418
419
    const RealOpenMM alphaObc                   = obcParameters->getAlphaObc();
    const RealOpenMM betaObc                    = obcParameters->getBetaObc();
    const RealOpenMM gammaObc                   = obcParameters->getGammaObc();
    const RealOpenMMVector& scaledRadiusFactor  = obcParameters->getScaledRadiusFactors();
420
421
422

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

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

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

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

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

Mark Friedrichs's avatar
Mark Friedrichs committed
436
          if( atomJ != atomI ){
437

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

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

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

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

Mark Friedrichs's avatar
Mark Friedrichs committed
462
             if( offsetRadiusI < rScaledRadiusJ ){
463

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

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

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

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

Mark Friedrichs's avatar
Mark Friedrichs committed
476
                RealOpenMM t3            = eighth*(one + scaledRadiusJ2*r2Inverse)*(l_ij2 - u_ij2) + fourth*LN( u_ij/l_ij )*r2Inverse;
477

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

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

Mark Friedrichs's avatar
Mark Friedrichs committed
496
    }
497

498
499
    //printObc( atomCoordinates, partialCharges, bornRadii, bornForces, inputForces, "Obc Post loop2", stderr );

Mark Friedrichs's avatar
Mark Friedrichs committed
500
    return obcEnergy;
501
}
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536

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

    Print Obc parameters, radii, forces, ...

    @param atomCoordinates     atomic coordinates
    @param partialCharges      partial charges
    @param bornRadii           Born radii (may be empty)
    @param bornForces          Born forces (may be empty)
    @param forces              forces (may be empty)
    @param idString            id string (who is calling)
    @param log                 log file

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

void CpuObc::printObc( const std::vector<OpenMM::RealVec>& atomCoordinates,
                       const RealOpenMMVector& partialCharges,
                       const RealOpenMMVector& bornRadii,
                       const RealOpenMMVector& bornForces,
                       const std::vector<OpenMM::RealVec>& forces,
                       const std::string& idString, FILE* log ){

    // ---------------------------------------------------------------------------------------

    const ObcParameters* obcParameters          = getObcParameters();
    const int numberOfAtoms                     = obcParameters->getNumberOfAtoms();
    const RealOpenMMVector& atomicRadii         = obcParameters->getAtomicRadii();
    const RealOpenMM preFactor                  = 2.0*obcParameters->getElectricConstant();
    const RealOpenMMVector& obcChain            = getObcChain();
    const RealOpenMMVector& scaledRadiusFactor  = obcParameters->getScaledRadiusFactors();

    const RealOpenMM alphaObc                   = obcParameters->getAlphaObc();
    const RealOpenMM betaObc                    = obcParameters->getBetaObc();
    const RealOpenMM gammaObc                   = obcParameters->getGammaObc();

Mark Friedrichs's avatar
Mark Friedrichs committed
537
538
    const int comparisonFormat                  = 1;

539
540
541
    // ---------------------------------------------------------------------------------------

    (void) fprintf( log, "Reference Obc      %s atoms=%d\n", idString.c_str(), numberOfAtoms );
Mark Friedrichs's avatar
Mark Friedrichs committed
542
543
    if( comparisonFormat ){    
        (void) fprintf( log, "Reference Obc  %s atoms=%d Chain/Radii/Force\n", idString.c_str(), numberOfAtoms );
544
        for( unsigned int atomI = 0; atomI < static_cast<unsigned int>(numberOfAtoms); atomI++ ){
Mark Friedrichs's avatar
Mark Friedrichs committed
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
            (void) fprintf( log, "%6d ", atomI );
            if( obcChain.size() > atomI ){
                 (void) fprintf( log, " %15.7e", obcChain[atomI] );
            }
            if( bornRadii.size() > atomI ){
                 (void) fprintf( log, " %15.7e", bornRadii[atomI] );
            }
            if( bornForces.size() > atomI ){
                 (void) fprintf( log, " %15.7e", bornForces[atomI] );    
            }
            (void) fprintf( log, " %15.7e %6.3f", atomicRadii[atomI], partialCharges[atomI] );
            (void) fprintf( log, "\n" );
        }   
    } else { 
        (void) fprintf( log, "Reference Obc      %s atoms=%d\n", idString.c_str(), numberOfAtoms );
        (void) fprintf( log, "    preFactor      %15.7e\n", preFactor );
        (void) fprintf( log, "    alpha          %15.7e\n", alphaObc);
        (void) fprintf( log, "    beta           %15.7e\n", betaObc);
        (void) fprintf( log, "    gamma          %15.7e\n", gammaObc );
     
565
        for( unsigned int atomI = 0; atomI < static_cast<unsigned int>(numberOfAtoms); atomI++ ){
Mark Friedrichs's avatar
Mark Friedrichs committed
566
567
568
569
570
571
572
573
574
575
576
577
578
            (void) fprintf( log, "%6d r=%15.7e q=%6.3f", atomI,
                            atomicRadii[atomI], partialCharges[atomI] );
            if( obcChain.size() > atomI ){
                 (void) fprintf( log, " bChn=%15.7e", obcChain[atomI] );
            }
            if( bornRadii.size() > atomI ){
                 (void) fprintf( log, " bR=%15.7e", bornRadii[atomI] );
            }
            if( bornForces.size() > atomI ){
                 (void) fprintf( log, " bF=%15.7e", bornForces[atomI] );    
            }
            (void) fprintf( log, "\n" );
        }   
579
    }   
Mark Friedrichs's avatar
Mark Friedrichs committed
580
    
581
582
583
584
    return;

}