NAMD
ComputeNonbondedCUDAExcl.C
Go to the documentation of this file.
1 
7 #include "ComputeNonbondedUtil.h"
8 #include "InfoStream.h"
10 #include "Molecule.h"
11 #include "Parameters.h"
12 #include "LJTable.h"
13 #include "Node.h"
14 #include "ReductionMgr.h"
15 #include "Lattice.h"
16 #include "PressureProfile.h"
17 #include "Debug.h"
18 
19 
20 // static initialization
25 int ExclElem::pswitchTable[3*3] = {0,1,2,1,1,99,2,99,2};
26 
28  (Molecule* mol, int* count, int32*** byatom, Exclusion** structarray)
29 {
30 #ifdef MEM_OPT_VERSION
31  NAMD_die("Should not be called in ExclElem::getMoleculePointers in memory optimized version!");
32 #else
33  *count = mol->numExclusions;
34  *byatom = mol->exclusionsByAtom;
35  *structarray = mol->exclusions;
36 #endif
37 }
38 
39 void ExclElem::getParameterPointers(Parameters *p, const int **v) {
40  *v = 0;
41 }
42 
43 
45  ExclElem *tuples,
46  int ntuple,
47  BigReal *reduction,
48  BigReal *pressureProfileData
49  )
50 {
51  //
52  // Use the following from ComputeNonbondedUtil:
53  const auto& cutoff2 = ComputeNonbondedUtil::cutoff2;
54  const auto& switchOn2 = ComputeNonbondedUtil::switchOn2;
55  const auto& r2_table = ComputeNonbondedUtil::r2_table;
56  const auto& fast_table = ComputeNonbondedUtil::fast_table;
57  const auto& slow_table = ComputeNonbondedUtil::slow_table;
58  const auto& table_noshort = ComputeNonbondedUtil::table_noshort;
59  const auto& ljTable = ComputeNonbondedUtil::ljTable;
60  const auto& r2_delta = ComputeNonbondedUtil::r2_delta;
61  const auto& scaling = ComputeNonbondedUtil::scaling;
62  const auto& scale14 = ComputeNonbondedUtil::scale14;
63  const auto& dielectric_1 = ComputeNonbondedUtil::dielectric_1;
64  const auto& r2_delta_exp = ComputeNonbondedUtil::r2_delta_exp;
65  // alchFepOn
66  // alchVdwShiftCoeff
67  // alchDecouple
68  // scaling
69  // scale14
70  // dielectric_1
71  // ljTable
72  // r2_table
73  // table_noshort
74  // fast_table
75  // slow_table
76  //
77  const Lattice & lattice = tuples[0].p[0]->p->lattice;
78  const Flags &flags = tuples[0].p[0]->p->flags;
79  if ( ! flags.doNonbonded ) return;
81  const int doFull = flags.doFullElectrostatics;
82  const int doEnergy = flags.doEnergy;
83 
84  /* ALCH STUFF */
85  BigReal lambdaUp, lambdaDown, lambda2Up, lambda2Down, switchfactor;
86  BigReal vdwLambdaUp, vdwLambdaDown, elecLambdaUp, elecLambdaDown;
87  BigReal elecLambda2Up, elecLambda2Down, vdwLambda2Up, vdwLambda2Down;
88  BigReal vdwShiftUp, vdwShift2Up, vdwShiftDown, vdwShift2Down;
89  BigReal myVdwLambda, myVdwLambda2, myElecLambda, myElecLambda2, myVdwShift, myVdwShift2;
90  //bool isAlch = simParams->alchFepOn;
91  int pswitch, ref, alch, dec, up, down;
92 
93  if (simParams->alchFepOn || simParams->alchThermIntOn) {
94  BigReal lambdaUp = simParams->getCurrentLambda(flags.step);
95  BigReal lambda2Up = simParams->getCurrentLambda2(flags.step);
96  BigReal lambdaDown = 1 - lambdaUp;
97  BigReal lambda2Down = 1 - lambda2Up;
98  switchfactor = 1./((cutoff2 - switchOn2)*
99  (cutoff2 - switchOn2)*(cutoff2 - switchOn2));
100  vdwLambdaUp = simParams->getVdwLambda(lambdaUp);
101  vdwLambdaDown = simParams->getVdwLambda(lambdaDown);
102  elecLambdaUp = simParams->getElecLambda(lambdaUp);
103  elecLambdaDown = simParams->getElecLambda(lambdaDown);
104  elecLambda2Up = simParams->getElecLambda(lambda2Up);
105  elecLambda2Down = simParams->getElecLambda(lambda2Down);
106  vdwLambda2Up = simParams->getVdwLambda(lambda2Up);
107  vdwLambda2Down = simParams->getVdwLambda(lambda2Down);
108  vdwShiftUp = simParams->alchVdwShiftCoeff*(1 - vdwLambdaUp);
109  vdwShiftDown = simParams->alchVdwShiftCoeff*(1 - vdwLambdaDown);
110  vdwShift2Up = simParams->alchVdwShiftCoeff*(1 - vdwLambda2Up);
111  vdwShift2Down = simParams->alchVdwShiftCoeff*(1 - vdwLambda2Down);
112 
113  if (simParams->alchDecouple) {
114  // decoupling: PME calculates extra grids so that while PME
115  // interaction with the full system is switched off, a new PME grid
116  // containing only alchemical atoms is switched on. Full interactions
117  // between alchemical atoms are maintained; potentials within one
118  // partition need not be scaled here.
119  pswitchTable[1+3*1] = 0;
120  pswitchTable[2+3*2] = 0;
121  }
122  }
123 
124  for ( int ituple=0; ituple<ntuple; ++ituple ) {
125  // ENERGIES FOR REDUCTION
126  BigReal energyVdw = 0.0, energyElec = 0.0, energySlow = 0.0;
127  // FEP Energies
128  BigReal energyVdw_s = 0.0, energyElec_s = 0.0, energySlow_s = 0.0;
129 
130  const ExclElem &tup = tuples[ituple];
131  enum { size = 2 };
132  const AtomID (&atomID)[size](tup.atomID);
133  const int (&localIndex)[size](tup.localIndex);
134  TuplePatchElem * const(&p)[size](tup.p);
135  const Real (&scale)(tup.scale);
136  const int (&modified)(tup.modified);
137 
138  const CompAtom &p_i = p[0]->x[localIndex[0]];
139  const CompAtom &p_j = p[1]->x[localIndex[1]];
140 
141  const unsigned char p1 = p_i.partition;
142  const unsigned char p2 = p_j.partition;
143 
144  BigReal alch_vdw_energy = 0.0;
145  BigReal alch_vdw_energy_2 = 0.0;
146  BigReal alch_vdw_force = 0.0;
147  BigReal alch_vdw_dUdl = 0.0;
148 
149  // compute vectors between atoms and their distances
150  const Vector r12 = lattice.delta(p_i.position, p_j.position);
151  BigReal r2 = r12.length2();
152 
153  if ( r2 > cutoff2 ) continue;
154 
155  if ( modified && r2 < 1.0 ) r2 = 1.0; // match CUDA interpolation
156 
157  r2 += r2_delta;
158 
159  pswitch = pswitchTable[p1 + 3*p2];
160  if (simParams->alchFepOn || simParams->alchThermIntOn) {
161  switch (pswitch) {
162  case 0:
163  myVdwLambda = 1.0; myElecLambda = 1.0;
164  myVdwLambda2 = 1.0; myElecLambda2 = 1.0;
165  break;
166  case 1:
167  myVdwLambda = vdwLambdaUp; myElecLambda = elecLambdaUp; myVdwShift = vdwShiftUp;
168  myVdwLambda2 = vdwLambda2Up; myElecLambda2 = elecLambda2Up; myVdwShift2 = vdwShift2Up;
169  break;
170  case 2:
171  myVdwLambda = vdwLambdaDown; myElecLambda = elecLambdaDown; myVdwShift = vdwShiftDown;
172  myVdwLambda2 = vdwLambda2Down; myElecLambda2 = elecLambda2Down; myVdwShift2 = vdwShift2Down;
173  break;
174  default:
175  myVdwLambda = 0.0; myElecLambda = 0.0;
176  myVdwLambda2 = 0.0; myElecLambda2 = 0.0;
177  break;
178  }
179  }
180  else {
181  myVdwLambda = 1.0; myElecLambda = 1.0;
182  myVdwLambda2 = 1.0; myElecLambda2 = 1.0;
183  }
184 
185  union { double f; int64 i; } r2i;
186  r2i.f = r2;
187  const int r2_delta_expc = 64 * (r2_delta_exp - 1023);
188  int table_i = (r2i.i >> (32+14)) + r2_delta_expc; // table_i >= 0
189 
190  const BigReal* const table_four_i = table_noshort + 16*table_i;
191 
192  BigReal diffa = r2 - r2_table[table_i];
193 
194  BigReal fast_a = 0., fast_b = 0., fast_c = 0., fast_d = 0.;
195  BigReal slow_a, slow_b, slow_c, slow_d;
196 
197  if ( modified ) { // fix modified 1-4 interactions
198 
199  const LJTable::TableEntry * lj_pars =
200  ljTable->table_row(p_i.vdwType) + 2 * p_j.vdwType;
201 
202  // modified - normal = correction
203  const BigReal A = scaling * ( (lj_pars+1)->A - lj_pars->A );
204  const BigReal B = scaling * ( (lj_pars+1)->B - lj_pars->B );
205 
206  BigReal vdw_d = A * table_four_i[0] - B * table_four_i[4];
207  BigReal vdw_c = A * table_four_i[1] - B * table_four_i[5];
208  BigReal vdw_b = A * table_four_i[2] - B * table_four_i[6];
209  BigReal vdw_a = A * table_four_i[3] - B * table_four_i[7];
210 
211  const BigReal kqq = (1.0 - scale14) *
212  COULOMB * p_i.charge * p_j.charge * scaling * dielectric_1;
213 
214  fast_a = kqq * fast_table[4*table_i+0]; // not used!
215  fast_b = 2. * kqq * fast_table[4*table_i+1];
216  fast_c = 4. * kqq * fast_table[4*table_i+2];
217  fast_d = 6. * kqq * fast_table[4*table_i+3];
218 
219  if ( doFull ) {
220  slow_a = kqq * slow_table[4*table_i+3]; // not used!
221  slow_b = 2. * kqq * slow_table[4*table_i+2];
222  slow_c = 4. * kqq * slow_table[4*table_i+1];
223  slow_d = 6. * kqq * slow_table[4*table_i+0];
224  }
225 
226  if ( doEnergy ) {
227  energyElec = (( ( diffa * (1./6.)*fast_d + 0.25*fast_c ) * diffa
228  + 0.5*fast_b ) * diffa + fast_a);
229  if ( doFull ) {
230  energySlow = (( ( diffa * (1./6.)*slow_d + 0.25*slow_c ) * diffa
231  + 0.5*slow_b ) * diffa + slow_a);
232  }
233  }
234 
235  if (pswitch == 0) {
236  fast_a += vdw_a;
237  fast_b += vdw_b;
238  fast_c += vdw_c;
239  fast_d += vdw_d;
240  if (doEnergy) {
241  energyVdw = (( ( diffa * (1./6.)*vdw_d + 0.25*vdw_c ) * diffa
242  + 0.5*vdw_b ) * diffa + vdw_a);
243  }
244  }
245  else if(pswitch != 99) {
246  // Special alch forces should be calculated here
247  if(simParams->alchFepOn){
248  const BigReal r2_1 = 1./(r2 + myVdwShift);
249  const BigReal r2_2 = 1./(r2 + myVdwShift2);
250  const BigReal r6_1 = r2_1*r2_1*r2_1;
251  const BigReal r6_2 = r2_2*r2_2*r2_2;
252  const BigReal U1 = A*r6_1*r6_1 - B*r6_1; // NB: unscaled, shorthand only
253  const BigReal U2 = A*r6_2*r6_2 - B*r6_2;
254 
255  const BigReal switchmul = (r2 > switchOn2 ?
256  switchfactor * (cutoff2 - r2) * (cutoff2 - r2) *
257  (cutoff2 - 3.*switchOn2 + 2.*r2) : 1.);
258 
259  const BigReal switchmul2 = (r2 > switchOn2 ?
260  12.*switchfactor * (cutoff2 - r2) * (r2 - switchOn2) : 0.);
261  BigReal rinv = namd_rsqrt(r2);
262  alch_vdw_energy = myVdwLambda*switchmul*U1;
263  alch_vdw_energy_2 = myVdwLambda2*switchmul*U2;
264  alch_vdw_force = myVdwLambda*((switchmul*(12.*U1 + 6.*B*r6_1)*r2_1 +
265  switchmul2*U1));
266  if (doEnergy) {
267  reduction[vdwEnergyIndex] += alch_vdw_energy;
268  reduction[vdwEnergyIndex_s] += alch_vdw_energy_2;
269  }
270  }else if(simParams->alchThermIntOn){
271  const BigReal r2_1 = 1./(r2 + myVdwShift);
272  const BigReal r6_1 = r2_1*r2_1*r2_1;
273  // switching function (this is correct whether switching is active or not)
274  const BigReal switchmul = (r2 > switchOn2 ? switchfactor*(cutoff2 - r2) \
275  *(cutoff2 - r2) \
276  *(cutoff2 - 3.*switchOn2 + 2.*r2) : 1.);
277  const BigReal switchmul2 = (r2 > switchOn2 ? \
278  12.*switchfactor*(cutoff2 - r2) \
279  *(r2 - switchOn2) : 0.);
280 
281  // separation-shifted vdW force and energy
282  const BigReal U = A*r6_1*r6_1 - B*r6_1; // NB: unscaled! for shorthand only!
283  alch_vdw_energy = myVdwLambda*switchmul*U;
284  alch_vdw_force = (myVdwLambda*(switchmul*(12.*U + 6.*B*r6_1)*r2_1 \
285  + switchmul2*U));
286  alch_vdw_dUdl = (switchmul*(U + myVdwLambda*simParams->alchVdwShiftCoeff \
287  *(6.*U + 3.*B*r6_1)*r2_1));
288  if (doEnergy) {
289  reduction[vdwEnergyIndex] += alch_vdw_energy;
290  reduction[vdwEnergyIndex_ti_1] += alch_vdw_dUdl*(pswitch == 1);
291  reduction[vdwEnergyIndex_ti_2] += alch_vdw_dUdl*(pswitch == 2);
292  }
293  }//alchFepOn
294  }
295  } // end if modified
296  else if ( doFull ) { // full exclusion
297 
298  const BigReal kqq =
299  COULOMB * p_i.charge * p_j.charge * scaling * dielectric_1;
300 
301  slow_d = kqq * ( table_four_i[8] - table_four_i[12] );
302  slow_c = kqq * ( table_four_i[9] - table_four_i[13] );
303  slow_b = kqq * ( table_four_i[10] - table_four_i[14] );
304  slow_a = kqq * ( table_four_i[11] - table_four_i[15] ); // not used!
305 
306  if ( doEnergy ) {
307  energySlow = (( ( diffa * (1./6.)*slow_d + 0.25*slow_c ) * diffa
308  + 0.5*slow_b ) * diffa + slow_a);
309  }
310  }
311 
312  register BigReal fast_dir = (diffa * fast_d + fast_c) * diffa + fast_b;
313 
314  fast_dir = (fast_dir*myElecLambda) + alch_vdw_force*(pswitch == 1 || pswitch == 2);
315  const Force f12 = fast_dir * r12;
316 
317  // Now add the forces to each force vector
318  p[0]->r->f[Results::nbond][localIndex[0]] += f12;
319  p[1]->r->f[Results::nbond][localIndex[1]] -= f12;
320 
321  // reduction[nonbondedEnergyIndex] += energy;
322  reduction[virialIndex_XX] += f12.x * r12.x;
323  //reduction[virialIndex_XY] += f12.x * r12.y;
324  //reduction[virialIndex_XZ] += f12.x * r12.z;
325  reduction[virialIndex_YX] += f12.y * r12.x;
326  reduction[virialIndex_YY] += f12.y * r12.y;
327  //reduction[virialIndex_YZ] += f12.y * r12.z;
328  reduction[virialIndex_ZX] += f12.z * r12.x;
329  reduction[virialIndex_ZY] += f12.z * r12.y;
330  reduction[virialIndex_ZZ] += f12.z * r12.z;
331 
332  if ( doFull ) {
333  register BigReal slow_dir = (diffa * slow_d + slow_c) * diffa + slow_b;
334 
335  slow_dir = (slow_dir * myElecLambda);
336  const Force slow_f12 = slow_dir * r12;
337 
338  p[0]->r->f[Results::slow][localIndex[0]] += slow_f12;
339  p[1]->r->f[Results::slow][localIndex[1]] -= slow_f12;
340 
341  // reduction[nonbondedEnergyIndex] += energy;
342  reduction[slowVirialIndex_XX] += slow_f12.x * r12.x;
343  //reduction[slowVirialIndex_XY] += slow_f12.x * r12.y;
344  //reduction[slowVirialIndex_XZ] += slow_f12.x * r12.z;
345  reduction[slowVirialIndex_YX] += slow_f12.y * r12.x;
346  reduction[slowVirialIndex_YY] += slow_f12.y * r12.y;
347  //reduction[slowVirialIndex_YZ] += slow_f12.y * r12.z;
348  reduction[slowVirialIndex_ZX] += slow_f12.z * r12.x;
349  reduction[slowVirialIndex_ZY] += slow_f12.z * r12.y;
350  reduction[slowVirialIndex_ZZ] += slow_f12.z * r12.z;
351  }
352 
353  // Scale the energies here
354  if (doEnergy) {
355  reduction[vdwEnergyIndex] -= energyVdw*myElecLambda;
356  reduction[electEnergyIndex] -= energyElec*myElecLambda;
357  if (doFull) {
358  reduction[fullElectEnergyIndex] -= energySlow*myElecLambda;
359  }
360  if (simParams->alchFepOn) {
361  reduction[vdwEnergyIndex_s] -= energyVdw*myElecLambda2;
362  reduction[electEnergyIndex_s] -= energyElec*myElecLambda2;
363  if (doFull) {
364  reduction[fullElectEnergyIndex_s] -= energySlow*myElecLambda2;
365  }
366  }else if (simParams->alchThermIntOn){
367  if(pswitch == 1){
368  //Those aren't defined here. What should I do?
369  //reduction[vdwEnergyIndex_ti_1] -= alch_vdw_dUdl;
370  reduction[electEnergyIndex_ti_1] -= energyElec;
371  if (doFull) reduction[slowEnergyIndex_ti_1] -= energySlow;
372  }
373  else if (pswitch == 2){
374  //reduction[vdwEnergyIndex_ti_2] -= alch_vdw_dUdl;
375  reduction[electEnergyIndex_ti_2] -= energyElec;
376  if (doFull) reduction[slowEnergyIndex_ti_2] -= energySlow; //should I be scaling those?
377  }
378  }
379  } // end if doEnergy
380  } // end for loop
381 } // end computeForce()
382 
383 
385 {
386  //bool isAlch = Node::Object()->simParameters->alchFepOn;
388 
389  reduction->item(REDUCTION_ELECT_ENERGY) += data[electEnergyIndex];
390  reduction->item(REDUCTION_LJ_ENERGY) += data[vdwEnergyIndex];
392  if (simParams->alchFepOn) {
393  reduction->item(REDUCTION_ELECT_ENERGY_F) += data[electEnergyIndex_s];
395  reduction->item(REDUCTION_LJ_ENERGY_F) += data[vdwEnergyIndex_s];
396  }else if (simParams->alchThermIntOn){
403  }
404  //transposes the virial tensor after calculation
405  data[virialIndex_XY] = data[virialIndex_YX];
406  data[virialIndex_XZ] = data[virialIndex_ZX];
407  data[virialIndex_YZ] = data[virialIndex_ZY];
408 
409  data[slowVirialIndex_XY] = data[slowVirialIndex_YX];
410  data[slowVirialIndex_XZ] = data[slowVirialIndex_ZX];
411  data[slowVirialIndex_YZ] = data[slowVirialIndex_ZY];
412 
413  ADD_TENSOR(reduction,REDUCTION_VIRIAL_NBOND,data,virialIndex);
414  ADD_TENSOR(reduction,REDUCTION_VIRIAL_SLOW,data,slowVirialIndex);
415 }
416 
static Node * Object()
Definition: Node.h:86
static BigReal * fast_table
static int pressureProfileAtomTypes
Lattice & lattice
Definition: Patch.h:127
#define ADD_TENSOR(R, RL, D, DL)
Definition: ReductionMgr.h:33
Definition: Vector.h:72
static void submitReductionData(BigReal *, SubmitReduction *)
SimParameters * simParameters
Definition: Node.h:181
static void computeForce(ExclElem *, int, BigReal *, BigReal *)
float Real
Definition: common.h:118
#define COULOMB
Definition: common.h:53
int32_t int32
Definition: common.h:38
BigReal & item(int i)
Definition: ReductionMgr.h:336
#define table_four_i
BigReal z
Definition: Vector.h:74
Position position
Definition: NamdTypes.h:78
static void getParameterPointers(Parameters *, const int **)
#define p_j
Molecule stores the structural information for the system.
Definition: Molecule.h:174
#define lj_pars
Flags flags
Definition: Patch.h:128
#define namd_rsqrt(x)
Definition: Vector.h:68
Charge charge
Definition: NamdTypes.h:79
static BigReal * table_noshort
static int pswitchTable[3 *3]
int doEnergy
Definition: PatchTypes.h:20
int doFullElectrostatics
Definition: PatchTypes.h:23
int16 vdwType
Definition: NamdTypes.h:80
Force * f[maxNumForces]
Definition: PatchTypes.h:150
NAMD_HOST_DEVICE BigReal length2(void) const
Definition: Vector.h:206
uint8 partition
Definition: NamdTypes.h:81
BigReal x
Definition: Vector.h:74
int doNonbonded
Definition: PatchTypes.h:22
void NAMD_die(const char *err_msg)
Definition: common.C:147
TuplePatchElem * p[size]
static int pressureProfileSlabs
AtomID atomID[size]
static BigReal * slow_table
#define simParams
Definition: Output.C:131
int32 AtomID
Definition: NamdTypes.h:35
BigReal y
Definition: Vector.h:74
static const LJTable * ljTable
static BigReal pressureProfileThickness
int64_t int64
Definition: common.h:39
static BigReal pressureProfileMin
static void getMoleculePointers(Molecule *, int *, int32 ***, Exclusion **)
double BigReal
Definition: common.h:123
NAMD_HOST_DEVICE Vector delta(const Position &pos1, const Position &pos2) const
Definition: Lattice.h:149
int step
Definition: PatchTypes.h:16
int numExclusions
Definition: Molecule.h:600