coulombLennardJones.cl 6.15 KB
Newer Older
1
2
3
4
5
6
{
#ifdef USE_DOUBLE_PRECISION
    unsigned long includeInteraction;
#else
    unsigned int includeInteraction;
#endif
7
#if USE_EWALD
8
9
    bool needCorrection = hasExclusions && isExcluded && atom1 != atom2 && atom1 < NUM_ATOMS && atom2 < NUM_ATOMS;
    includeInteraction = ((!isExcluded && r2 < CUTOFF_SQUARED) || needCorrection);
Peter Eastman's avatar
Peter Eastman committed
10
11
12
    const real alphaR = EWALD_ALPHA*r;
    const real expAlphaRSqr = EXP(-alphaR*alphaR);
    const real prefactor = 138.935456f*posq1.w*posq2.w*invR;
13

14
#ifdef USE_DOUBLE_PRECISION
Peter Eastman's avatar
Peter Eastman committed
15
    const real erfcAlphaR = erfc(alphaR);
16
#else
Peter Eastman's avatar
Peter Eastman committed
17
18
    // This approximation for erfc is from Abramowitz and Stegun (1964) p. 299.  They cite the following as
    // the original source: C. Hastings, Jr., Approximations for Digital Computers (1955).  It has a maximum
19
    // error of 1.5e-7.
20

21
22
    const real t = RECIP(1.0f+0.3275911f*alphaR);
    const real erfcAlphaR = (0.254829592f+(-0.284496736f+(1.421413741f+(-1.453152027f+1.061405429f*t)*t)*t)*t)*t*expAlphaRSqr;
23
#endif
Peter Eastman's avatar
Peter Eastman committed
24
    real tempForce = 0;
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#if HAS_LENNARD_JONES
    // The multiplicative term to correct for the multiplicative terms that are always
    // present in reciprocal space.  The real terms have an additive contribution
    // added in, but for excluded terms the multiplicative term is just subtracted.
    // These factors are needed in both clauses of the needCorrection statement, so
    // I declare them up here.
    #if DO_LJPME
        const real dispersionAlphaR = EWALD_DISPERSION_ALPHA*r;
        const real dar2 = dispersionAlphaR*dispersionAlphaR;
        const real dar4 = dar2*dar2;
        const real dar6 = dar4*dar2;
        const real invR2 = invR*invR;
        const real expDar2 = EXP(-dar2);
        const float2 sigExpProd = sigmaEpsilon1*sigmaEpsilon2;
        const real c6 = 64*sigExpProd.x*sigExpProd.x*sigExpProd.x*sigExpProd.y;
        const real coef = invR2*invR2*invR2*c6;
        const real eprefac = 1.0f + dar2 + 0.5f*dar4;
        const real dprefac = eprefac + dar6/6.0f;
    #endif
#endif
Peter Eastman's avatar
Peter Eastman committed
45
46
    if (needCorrection) {
        // Subtract off the part of this interaction that was included in the reciprocal space contribution.
47

48
        if (1-erfcAlphaR > 1e-6) {
49
50
51
            real erfAlphaR = erf(alphaR); // Our erfc approximation is not accurate enough when r is very small, which happens with Drude particles.
            tempForce = -prefactor*(erfAlphaR-alphaR*expAlphaRSqr*TWO_OVER_SQRT_PI);
            tempEnergy += -prefactor*erfAlphaR;
52
        }
53
        else {
54
            includeInteraction = false;
55
56
            tempEnergy -= TWO_OVER_SQRT_PI*EWALD_ALPHA*138.935456f*posq1.w*posq2.w;
        }
57
58
59
60
61
62
63
#if HAS_LENNARD_JONES
        #if DO_LJPME
            // The multiplicative grid term
            tempEnergy += coef*(1.0f - expDar2*eprefac);
            tempForce += 6.0f*coef*(1.0f - expDar2*dprefac);
        #endif
#endif
Peter Eastman's avatar
Peter Eastman committed
64
65
    }
    else {
66
#if HAS_LENNARD_JONES
Peter Eastman's avatar
Peter Eastman committed
67
68
69
70
        real sig = sigmaEpsilon1.x + sigmaEpsilon2.x;
        real sig2 = invR*sig;
        sig2 *= sig2;
        real sig6 = sig2*sig2*sig2;
71
72
        real eps = sigmaEpsilon1.y*sigmaEpsilon2.y;
        real epssig6 = sig6*eps;
Peter Eastman's avatar
Peter Eastman committed
73
74
75
76
77
78
79
80
81
82
83
        tempForce = epssig6*(12.0f*sig6 - 6.0f);
        real ljEnergy = epssig6*(sig6 - 1.0f);
        #if USE_LJ_SWITCH
        if (r > LJ_SWITCH_CUTOFF) {
            real x = r-LJ_SWITCH_CUTOFF;
            real switchValue = 1+x*x*x*(LJ_SWITCH_C3+x*(LJ_SWITCH_C4+x*LJ_SWITCH_C5));
            real switchDeriv = x*x*(3*LJ_SWITCH_C3+x*(4*LJ_SWITCH_C4+x*5*LJ_SWITCH_C5));
            tempForce = tempForce*switchValue - ljEnergy*switchDeriv*r;
            ljEnergy *= switchValue;
        }
        #endif
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#if DO_LJPME
        // The multiplicative grid term
        ljEnergy += coef*(1.0f - expDar2*eprefac);
        tempForce += 6.0f*coef*(1.0f - expDar2*dprefac);
        // The potential shift accounts for the step at the cutoff introduced by the
        // transition from additive to multiplicative combintion rules and is only
        // needed for the real (not excluded) terms.  By addin these terms to ljEnergy
        // instead of tempEnergy here, the includeInteraction mask is correctly applied.
        sig2 = sig*sig;
        sig6 = sig2*sig2*sig2*INVCUT6;
        epssig6 = eps*sig6;
        // The additive part of the potential shift
        ljEnergy += epssig6*(1.0f - sig6);
        // The multiplicative part of the potential shift
        ljEnergy += MULTSHIFT6*c6;
#endif
Peter Eastman's avatar
Peter Eastman committed
100
        tempForce += prefactor*(erfcAlphaR+alphaR*expAlphaRSqr*TWO_OVER_SQRT_PI);
101
        tempEnergy += select((real) 0, ljEnergy + prefactor*erfcAlphaR, includeInteraction);
102
#else
Peter Eastman's avatar
Peter Eastman committed
103
        tempForce = prefactor*(erfcAlphaR+alphaR*expAlphaRSqr*TWO_OVER_SQRT_PI);
104
        tempEnergy += select((real) 0, prefactor*erfcAlphaR, includeInteraction);
105
#endif
106
    }
107
    dEdR += select((real) 0, tempForce*invR*invR, includeInteraction);
108
#else
109
#ifdef USE_CUTOFF
110
    includeInteraction = (!isExcluded && r2 < CUTOFF_SQUARED);
111
#else
112
    includeInteraction = (!isExcluded);
113
#endif
114
    real tempForce = 0;
115
  #if HAS_LENNARD_JONES
116
117
    real sig = sigmaEpsilon1.x + sigmaEpsilon2.x;
    real sig2 = invR*sig;
118
    sig2 *= sig2;
119
120
    real sig6 = sig2*sig2*sig2;
    real epssig6 = sig6*(sigmaEpsilon1.y*sigmaEpsilon2.y);
121
    tempForce = epssig6*(12.0f*sig6 - 6.0f);
122
    real ljEnergy = epssig6*(sig6-1);
123
124
125
126
127
128
129
130
131
    #if USE_LJ_SWITCH
    if (r > LJ_SWITCH_CUTOFF) {
        real x = r-LJ_SWITCH_CUTOFF;
        real switchValue = 1+x*x*x*(LJ_SWITCH_C3+x*(LJ_SWITCH_C4+x*LJ_SWITCH_C5));
        real switchDeriv = x*x*(3*LJ_SWITCH_C3+x*(4*LJ_SWITCH_C4+x*5*LJ_SWITCH_C5));
        tempForce = tempForce*switchValue - ljEnergy*switchDeriv*r;
        ljEnergy *= switchValue;
    }
    #endif
132
    ljEnergy = select((real) 0, ljEnergy, includeInteraction);
133
    tempEnergy += ljEnergy;
134
135
136
  #endif
#if HAS_COULOMB
  #ifdef USE_CUTOFF
137
    const real prefactor = 138.935456f*posq1.w*posq2.w;
138
    tempForce += prefactor*(invR - 2.0f*REACTION_FIELD_K*r2);
139
    tempEnergy += select((real) 0, prefactor*(invR + REACTION_FIELD_K*r2 - REACTION_FIELD_C), includeInteraction);
140
  #else
141
    const real prefactor = 138.935456f*posq1.w*posq2.w*invR;
142
    tempForce += prefactor;
143
    tempEnergy += select((real) 0, prefactor, includeInteraction);
144
  #endif
145
#endif
146
    dEdR += select((real) 0, tempForce*invR*invR, includeInteraction);
147
#endif
148
}