NAMD
CudaComputeNonbondedInteractions.h
Go to the documentation of this file.
1 #ifndef CUDACOMPUTENONBONDEDINTERACTIONS_H
2 #define CUDACOMPUTENONBONDEDINTERACTIONS_H
3 
4 #include "CudaUtils.h"
5 
6 #if defined(NAMD_CUDA) || defined(NAMD_HIP)
7 
8 /*
9  * CudaNBConstants: defined in CudaUtils.h
10  *
11  * float lj_0; // denom * cutoff2 - 3.0f * switch2 * denom
12  * float lj_1; // denom * 2.0f
13  * float lj_2; // denom * -12.0f
14  * float lj_3; // denom * 12.0f * switch2
15  * float lj_4; // cutoff2
16  * float lj_5; // switch2
17  * float e_0; // roff3Inv
18  * float e_0_slow; // roff3Inv * (1 - slowScale)
19  * float e_1; // roff2Inv
20  * float e_2; // roffInv
21  * float ewald_0; // ewaldcof
22  * float ewald_1; // pi_ewaldcof
23  * float ewald_2; // ewaldcof ^ 2
24  * float ewald_3_slow; // ewaldcof ^ 3 * slowScale
25  * float slowScale; // ratio of full electrostatics to nonbonded frequency
26  */
27 
28 
29 /*
30  * Computes the Van der Waals interaction between two particles with
31  * energy switching.
32  *
33  * ljab is loaded from the vdw coef table, so this function can be used by
34  * both the nonbonded and modified exclusion kernels;
35  *
36  */
37 template<bool doEnergy>
38 __device__ __forceinline__
39 void cudaNBForce_Vdw_EnergySwitch(const float r2, const float rinv6, const float rinv8,
40  const float2 ljab, const CudaNBConstants c,
41  float& f_vdw, float& energyVdw) {
42 
43  const float ab_r6 = ljab.x * rinv6 - ljab.y;
44  const float w = ab_r6 * rinv6;
45  const float dw_r = (ljab.x * rinv6 + ab_r6) * -6.0f * rinv8;
46 
47  float e_vdw;
48 
49  if (r2 > c.lj_5) {
50  const float delta_r = (c.lj_4 - r2);
51  const float s = delta_r * delta_r * (c.lj_0 + c.lj_1 * r2);
52  const float ds_r = delta_r * (c.lj_3 + c.lj_2 * r2);
53  f_vdw = w * ds_r + dw_r * s;
54  if (doEnergy) e_vdw = w * s;
55  } else {
56  f_vdw = dw_r;
57  if (doEnergy) e_vdw = w;
58  }
59 
60  if (doEnergy) energyVdw += e_vdw;
61 }
62 
63 /*
64  * Computes the electrostatic interaction between two particles with the PME
65  * correction term and a C1 splitting function
66  *
67  * This will take the slowScale into account so it is only usable when
68  * the fast and slow force buffers are combine
69  *
70  */
71 template<bool doEnergy>
72 __device__ __forceinline__
73 void cudaNBForce_PMESlowAndFast_C1(const float r2, const float rinv,
74  const float rinv2, const float rinv3,
75  const float charge,
76  const CudaNBConstants c,
77  float& f_elec, float& energyElec, float& energySlow
78 ) {
79  const float elec_fast = -1.0f * rinv3 + c.e_0;
80  const float r = sqrtf(r2);
81  const float elec_a = r * c.ewald_0;
82  const float elec_exp = expf(-1.0f * elec_a * elec_a);
83  const float elec_b = erfcf(elec_a);
84  const float corr_grad = elec_b + c.ewald_1 * r * elec_exp;
85 
86  const float elec_slow = -1.0f * c.e_0 * r;
87  const float scor_grad = (elec_slow - (corr_grad - 1.0f) * rinv2)*rinv;
88 
89  if (doEnergy) {
90  float slow_energy = 0.5f * c.e_2 * (3.0f - r2 * c.e_1);
91  float fast_energy = rinv - slow_energy;
92  energyElec += charge * fast_energy;
93  const float corr_energy = elec_b;
94  const float scor_energy = slow_energy + (corr_energy - 1.0f) * rinv;
95  energySlow += charge * scor_energy;
96  }
97  f_elec = charge * (elec_fast + scor_grad * c.slowScale);
98 }
99 
100 /*
101  * Computes the electrostatic interaction between two particles without the PME
102  * correction term and with a C1 splitting function
103  *
104  * This is used on non-PME timesteps
105  *
106  */
107 template<bool doEnergy>
108 __device__ __forceinline__
109 void cudaNBForce_PMEFast_C1(const float r2, const float rinv,
110  const float rinv2, const float rinv3,
111  const float charge,
112  const CudaNBConstants c,
113  float& f_elec, float& energyElec
114 ) {
115  const float elec_fast = -1.0f * rinv3 + c.e_0;
116  f_elec = charge * elec_fast;
117 
118  if (doEnergy) {
119  float slow_energy = 0.5f * c.e_2 * (3.0f - r2 * c.e_1);
120  float fast_energy = rinv - slow_energy;
121  energyElec += charge * fast_energy;
122  }
123 }
124 
125 /*
126  * Computes the PME correction term and with a C1 splitting function
127  *
128  * This is used on PME timesteps
129  *
130  */
131 template<bool doEnergy>
132 __device__ __forceinline__
133 void cudaNBForce_PMESlow_C1(const float r2, const float rinv,
134  const float rinv2, const float rinv3,
135  const float charge,
136  const CudaNBConstants c,
137  float& fSlow, float& energySlow
138 ) {
139  fSlow = charge;
140 
141  const float r = sqrtf(r2);
142  const float elec_a = r * c.ewald_0;
143  // very expensive
144  const float elec_b = erfcf(elec_a);
145  const float elec_exp = expf(-1.0f * elec_a * elec_a);
146  const float corr_grad = elec_b + c.ewald_1 * r * elec_exp;
147 
148  const float elec_slow = -1.0f * c.e_0 * r;
149  const float scor_grad = (elec_slow - (corr_grad - 1.0f) * rinv2)*rinv;
150 
151  if (doEnergy) {
152  float slow_energy = 0.5f * c.e_2 * (3.0f - r2 * c.e_1);
153  const float corr_energy = elec_b;
154  const float scor_energy = slow_energy + (corr_energy - 1.0f) * rinv;
155  energySlow += fSlow * scor_energy;
156  }
157 
158  fSlow *= scor_grad;
159 }
160 
161 /*
162  * Computes the modified electrostatic interaction between two particles with a C1 splitting function
163  *
164  * This is used by the modifiedExclusionForce kernel, it corresponds to just
165  * computing the force from the "slow" table instead of the "scor" table.
166  *
167  */
168 template<bool doEnergy>
169 __device__ __forceinline__
170 void cudaModExclForce_PMESlow_C1(const float r2, const float rinv,
171  const float rinv2, const float rinv3,
172  const float charge,
173  const CudaNBConstants c,
174  float& f_elec, float& energySlow
175 ) {
176  const float elec_slow = -1.0f * c.e_0;
177  f_elec = charge * elec_slow;
178 
179  if (doEnergy) {
180  float slow_energy = 0.5f * c.e_2 * (3.0f - r2 * c.e_1);
181  energySlow += charge * slow_energy;
182  }
183 }
184 
185 /*
186  * Computes the nonbonded interaction between two particles combining Van der Waals
187  * with energy switching and PME corrected electrostatics with a C1 splitting function
188  *
189  */
190 template<bool doEnergy, bool doSlow>
191 __device__ __forceinline__
192 void cudaNBForceMagCalc_VdwEnergySwitch_PMEC1(const float r2, const float rinv,
193  const float charge, const float2 ljab, const CudaNBConstants c,
194  float& f, float& fSlow,
195  float& energyVdw, float& energyElec, float& energySlow) {
196 
197  const float rinv2 = rinv * rinv;
198  const float rinv3 = rinv * rinv2;
199  const float rinv6 = rinv3 * rinv3;
200  const float rinv8 = rinv6 * rinv2;
201 
202  float f_vdw;
203  cudaNBForce_Vdw_EnergySwitch<doEnergy>(r2, rinv6, rinv8, ljab, c, f_vdw, energyVdw);
204 
205  // Electrostatics
206  float f_elec;
207  if (!doSlow) {
208  cudaNBForce_PMEFast_C1<doEnergy>(r2, rinv, rinv2, rinv3, charge, c, f_elec, energyElec);
209  } else {
210  cudaNBForce_PMEFast_C1<doEnergy>(r2, rinv, rinv2, rinv3, charge, c, f_elec, energyElec);
211  cudaNBForce_PMESlow_C1<doEnergy>(r2, rinv, rinv2, rinv3, charge, c, fSlow, energySlow);
212  }
213  f = f_elec + f_vdw;
214 }
215 
216 /*
217  * Computes the modified exclusion force between two particles combining Van der Waals
218  * with energy switching and PME corrected electrostatics with a C1 splitting function
219  *
220  */
221 template<bool doEnergy>
222 __device__ __forceinline__
224  const int doSlow, const int doElec,
225  const float r2, const float rinv,
226  const float charge, const float2 ljab, const CudaNBConstants c,
227  float& f, float& fSlow,
228  float& energyVdw, float& energyElec, float& energySlow) {
229 
230  const float rinv2 = rinv * rinv;
231  const float rinv3 = rinv * rinv2;
232  const float rinv6 = rinv3 * rinv3;
233  const float rinv8 = rinv6 * rinv2;
234 
235  float f_vdw;
236  cudaNBForce_Vdw_EnergySwitch<doEnergy>(r2, rinv6, rinv8, ljab, c, f_vdw, energyVdw);
237  // Sign corrections. The force tables are flipped and exclusions kernel uses xyz.i - xyz.j while
238  // the nonbonded kernel uses xyz.j - xyz.i
239  f = -1.0f * f_vdw;
240 
241  // Electrostatics
242  if (doElec) {
243  float f_elec;
244  cudaNBForce_PMEFast_C1<doEnergy>(r2, rinv, rinv2, rinv3, charge, c, f_elec, energyElec);
245 
246  f += f_elec;
247  energyElec *= -1.0f;
248 
249  if (doSlow) {
250  cudaModExclForce_PMESlow_C1<doEnergy>(r2, rinv, rinv2, rinv3, charge, c, fSlow, energySlow);
251  energySlow *= -1.0f;
252  }
253  }
254 }
255 
256 
257 #endif // NAMD_CUDA
258 #endif // CUDACOMPUTENONBONDEDINTERACTIONS_H
259 
__device__ __forceinline__ void cudaNBForce_PMEFast_C1(const float r2, const float rinv, const float rinv2, const float rinv3, const float charge, const CudaNBConstants c, float &f_elec, float &energyElec)
__device__ __forceinline__ void cudaNBForceMagCalc_VdwEnergySwitch_PMEC1(const float r2, const float rinv, const float charge, const float2 ljab, const CudaNBConstants c, float &f, float &fSlow, float &energyVdw, float &energyElec, float &energySlow)
__device__ __forceinline__ void cudaNBForce_PMESlowAndFast_C1(const float r2, const float rinv, const float rinv2, const float rinv3, const float charge, const CudaNBConstants c, float &f_elec, float &energyElec, float &energySlow)
__device__ __forceinline__ void cudaModExclForce_PMESlow_C1(const float r2, const float rinv, const float rinv2, const float rinv3, const float charge, const CudaNBConstants c, float &f_elec, float &energySlow)
__device__ __forceinline__ void cudaNBForce_Vdw_EnergySwitch(const float r2, const float rinv6, const float rinv8, const float2 ljab, const CudaNBConstants c, float &f_vdw, float &energyVdw)
__device__ __forceinline__ void cudaNBForce_PMESlow_C1(const float r2, const float rinv, const float rinv2, const float rinv3, const float charge, const CudaNBConstants c, float &fSlow, float &energySlow)
__device__ __forceinline__ void cudaModExclForceMagCalc_VdwEnergySwitch_PMEC1(const int doSlow, const int doElec, const float r2, const float rinv, const float charge, const float2 ljab, const CudaNBConstants c, float &f, float &fSlow, float &energyVdw, float &energyElec, float &energySlow)