NAMD
LjPmeMgr.C
Go to the documentation of this file.
1 /* modified from NAMD */
2 
10 #include "LjPmeMgr.h"
11 #include "Lattice.h"
12 #include "LjPmeBase.h"
13 
14 void LjPmeMgr::initialize(const SimParameters *simParams, const int nAtoms) {
15 #ifndef USE_LJPME
16  NAMD_die("In order to use LJ-PME, you must build with -DUSE_LJPME");
17 #else
18 #if defined(NAMD_FFTW_3) || ! defined(NAMD_FFTW)
19  NAMD_die("LJ-PME requires FFTW 2");
20 #endif
21 #endif
22  if (initialized) {
23  NAMD_die("LjPmeMgr has already been initialized!");
24  }
25  int numRecipPes = 1;
26  selfEnergy = recipEnergy = 0.0;
27  setSelf = false;
28  numAtoms = nAtoms;
29  // Store grid informations
30  myGrid.K1 = simParams->LJPMEGridSizeX;
31  myGrid.K2 = simParams->LJPMEGridSizeY;
32  myGrid.K3 = simParams->LJPMEGridSizeZ;
33  myGrid.order = simParams->LJPMEInterpOrder;
34  myGrid.dim2 = myGrid.K2;
35  myGrid.dim3 = 2 * (myGrid.K3 / 2 + 1);
36  myGrid.block1 = (myGrid.K1 + numRecipPes - 1) / numRecipPes;
37  myGrid.block2 = (myGrid.K2 + numRecipPes - 1) / numRecipPes;
38 
39  // Allocate memory
40  myKSpace = new LjPmeKSpace(myGrid);
41  myRealSpace = new LjPmeRealSpace(myGrid, numAtoms);
42  dataArr = new double[4*numAtoms];
43  if (dataArr == 0) NAMD_die("can't allocate LJ-PME Manager dataArr buffer");
44 
45  qsize = myGrid.K1 * myGrid.dim2 * myGrid.dim3;
46  fsize = myGrid.K1 * myGrid.dim2;
47  q_arr = new float *[fsize];
48  if (q_arr == 0) NAMD_die("can't allocate LJ-PME Manager q_arr buffer");
49  memset((void *)q_arr, 0, fsize * sizeof(float *));
50 
51  // kludge so we won't segfault
52  for (int i = 0; i < fsize; i++)
53  {
54  q_arr[i] = new float[myGrid.dim3];
55  if (q_arr[i] == 0) NAMD_die("can't allocate LJ-PME Manager q_arr[i] buffer");
56  memset((void *)q_arr[i], 0, myGrid.dim3 * sizeof(float));
57  }
58  // end kludge
59 
60  f_arr = new char[fsize];
61  if (f_arr == 0) NAMD_die("can't allocate LJ-PME Manager f_arr buffer");
62  fz_arr = new char[myGrid.dim3];
63  if (fz_arr == 0) NAMD_die("can't allocate LJ-PME Manager fz_arr buffer");
64 
65  qGrid = new float[qsize];
66  if (qGrid == 0) NAMD_die("can't allocate LJ-PME Manager qGrid buffer");
67 
68  this->optimizeFFT();
69  memset((void *)qGrid, 0, qsize * sizeof(float));
70  initialized = true;
71 }
72 
74  setSelf = false;
75  initialized = false;
76  if (myRealSpace) delete myRealSpace;
77  if (myKSpace) delete myKSpace;
78  if (dataArr) delete [] dataArr;
79  if (qGrid) delete [] qGrid;
80  if (f_arr) delete [] f_arr;
81  if (fz_arr) delete [] fz_arr;
82  if (work) delete [] work;
83 
84  for (int i = 0; i < fsize; ++i) {
85  if (q_arr[i]) {
86  delete [] q_arr[i];
87  }
88  }
89 }
90 
92  int n[3];
93  n[0] = myGrid.K1;
94  n[1] = myGrid.K2;
95  n[2] = myGrid.K3;
96 #if defined(USE_LJPME) && ! defined(NAMD_FFTW_3)
97  /*
98  * see if using FFTW_ESTIMATE makes start up faster
99  */
100  #ifdef NAMD_FFTW
101  #ifdef NAMD_FFTW_3
102  work = new fftwf_complex[n[0]];
103 
104  iout << iINFO << "Optimizing 4 LJ-PME FFT steps. 1..." << endi;
105  forward_plan_yz = fftwf_plan_many_dft_r2c(2, n+1,
106  myGrid.K1, qGrid, NULL, 1, myGrid.dim2 * myGrid.dim3,
107  (fftwf_complex *)qGrid, NULL, 1,
108  myGrid.dim2 * (myGrid.dim3 / 2), FFTW_ESTIMATE);
109 
110  iout << " 2..." << endi;
111  int zdim = myGrid.dim3;
112  int xStride=myGrid.dim2 *( myGrid.dim3 / 2);
113  forward_plan_x = fftwf_plan_many_dft(1, n, xStride,
114  (fftwf_complex *)qGrid, NULL, xStride, 1,
115  (fftwf_complex *)qGrid, NULL, xStride, 1,
116  FFTW_FORWARD, FFTW_ESTIMATE);
117 
118  iout << " 3..." << endi;
119  backward_plan_x = fftwf_plan_many_dft(1, n, xStride,
120  (fftwf_complex *)qGrid, NULL, xStride, 1,
121  (fftwf_complex *)qGrid, NULL, xStride, 1,
122  FFTW_BACKWARD, FFTW_ESTIMATE);
123 
124  iout << " 4..." << endi;
125  backward_plan_yz = fftwf_plan_many_dft_c2r(2, n+1,
126  myGrid.K1,(fftwf_complex *)qGrid,
127  NULL, 1, myGrid.dim2 * (myGrid.dim3 / 2),
128  qGrid, NULL, 1, myGrid.dim2 * myGrid.dim3,
129  FFTW_ESTIMATE);
130  iout << " Done.\n" << endi;
131  #else
132  work = new fftw_complex[n[0]];
133 
134  iout << iINFO << "Optimizing 4 LJ-PME FFT steps. 1..." << endi;
135  forward_plan_yz = rfftwnd_create_plan_specific(2, n+1, FFTW_REAL_TO_COMPLEX,
136  FFTW_ESTIMATE | FFTW_IN_PLACE | FFTW_USE_WISDOM,
137  qGrid, 1, 0, 0);
138  iout << " 2..." << endi;
139  forward_plan_x = fftw_create_plan_specific(n[0], FFTW_FORWARD,
140  FFTW_ESTIMATE | FFTW_IN_PLACE | FFTW_USE_WISDOM, (fftw_complex *)qGrid,
141  myGrid.dim2 * myGrid.dim3 / 2, work, 1);
142  iout << " 3..." << endi;
143  backward_plan_x = fftw_create_plan_specific(n[0], FFTW_BACKWARD,
144  FFTW_ESTIMATE | FFTW_IN_PLACE | FFTW_USE_WISDOM, (fftw_complex *)qGrid,
145  myGrid.dim2 * myGrid.dim3 / 2, work, 1);
146  iout << " 4..." << endi;
147  backward_plan_yz = rfftwnd_create_plan_specific(2, n + 1, FFTW_COMPLEX_TO_REAL,
148  FFTW_ESTIMATE | FFTW_IN_PLACE | FFTW_USE_WISDOM,
149  qGrid, 1, 0, 0);
150  iout << " Done.\n" << endi;
151  #endif
152  #else
153  NAMD_die("Sorry, FFTW must be compiled in to use LJ-PME.");
154  #endif
155 #endif // USE_LJPME
156 }
157 
158 void LjPmeMgr::computeLongRange(const double *ljPmeCoord,
159  const Lattice &lattice, const double &alphaLJ,
160  double *force, double &energy, double virial[][3],
161  bool doEnergy) {
162  for (int i = 0; i < fsize; ++i) {
163  if (q_arr[i]) {
164  memset((void *)(q_arr[i]), 0, myGrid.dim3 * sizeof(float));
165  }
166  }
167  //memset((void *)qGrid, 0, qsize * sizeof(float)); // Do I need this?
168  memset((void *)f_arr, 0, fsize * sizeof(char));
169  memset((void *)fz_arr, 0, myGrid.dim3 * sizeof(char));
170  recipEnergy = 0.0;
171  for(int i = 0; i < 6; i++) {
172  recipVirial[i] = 0.0;
173  }
174 
175  // Store the charge and scaled coordinates in dataArr buffer
176  this->setScaledCoordinates(ljPmeCoord, lattice);
177  // Compute and store the self term
178  if(!setSelf) {
179  selfEnergy = this->selfCompute(alphaLJ);
180  setSelf = true;
181  }
182  // Split charges into the grid
183  myRealSpace->fill_charges(q_arr, f_arr, fz_arr, dataArr);
184  this->gridCalculation(alphaLJ, lattice);
185  myRealSpace->compute_scaledForces(q_arr, dataArr, force, lattice);
186 
187  // Add energy and virial
188  if(doEnergy) {
189  energy += recipEnergy + selfEnergy;
190  virial[0][0] += recipVirial[0];
191  virial[0][1] += recipVirial[1];
192  virial[0][2] += recipVirial[2];
193  virial[1][0] += recipVirial[1];
194  virial[1][1] += recipVirial[3];
195  virial[1][2] += recipVirial[4];
196  virial[2][0] += recipVirial[2];
197  virial[2][1] += recipVirial[4];
198  virial[2][2] += recipVirial[5];
199  }
200 }
201 
202 void LjPmeMgr::setScaledCoordinates(const double *refPos, const Lattice &lattice) {
203  Vector origin = lattice.origin();
204  Vector recip1 = lattice.a_r();
205  Vector recip2 = lattice.b_r();
206  Vector recip3 = lattice.c_r();
207  double ox = origin.x;
208  double oy = origin.y;
209  double oz = origin.z;
210  double r1x = recip1.x;
211  double r1y = recip1.y;
212  double r1z = recip1.z;
213  double r2x = recip2.x;
214  double r2y = recip2.y;
215  double r2z = recip2.z;
216  double r3x = recip3.x;
217  double r3y = recip3.y;
218  double r3z = recip3.z;
219  int K1 = myGrid.K1;
220  int K2 = myGrid.K2;
221  int K3 = myGrid.K3;
222  double shift1 = ((K1 + myGrid.order - 1)/2)/(double)K1;
223  double shift2 = ((K2 + myGrid.order - 1)/2)/(double)K2;
224  double shift3 = ((K3 + myGrid.order - 1)/2)/(double)K3;
225 
226  for (int i=0; i<numAtoms; i++) {
227  int index = 4*i;
228  double px = refPos[index] - ox;
229  double py = refPos[index+1] - oy;
230  double pz = refPos[index+2] - oz;
231  double c3Term = refPos[index+3];
232  double sx = shift1 + px*r1x + py*r1y + pz*r1z;
233  double sy = shift2 + px*r2x + py*r2y + pz*r2z;
234  double sz = shift3 + px*r3x + py*r3y + pz*r3z;
235  px = K1 * ( sx - floor(sx) );
236  py = K2 * ( sy - floor(sy) );
237  pz = K3 * ( sz - floor(sz) );
238  // Check for rare rounding condition where K * ( 1 - epsilon ) == K
239  // which was observed with g++ on Intel x86 architecture.
240  if ( px == K1 ) px = 0;
241  if ( py == K2 ) py = 0;
242  if ( pz == K3 ) pz = 0;
243 
244  dataArr[index] = px;
245  dataArr[index+1] = py;
246  dataArr[index+2] = pz;
247  dataArr[index+3] = c3Term;
248  }
249 }
250 
251 void LjPmeMgr::gridCalculation(const double &alpha, const Lattice &lattice)
252 {
253 #if defined(USE_LJPME) && ! defined(NAMD_FFTW_3)
254  // Part 1:
255  int i, j, k = 0;
256  for (i = 0; i < myGrid.K1 * myGrid.K2; i++) {
257  for (j = 0; j < myGrid.dim3; j++) {
258  qGrid[k++] = q_arr[i][j];
259  }
260  }
261  #ifdef NAMD_FFTW
262  #ifdef NAMD_FFTW_3
263  fftwf_execute(forward_plan_yz);
264  #else
265  rfftwnd_real_to_complex(forward_plan_yz, myGrid.K1,
266  (fftw_real *)qGrid, 1, myGrid.dim2 * myGrid.dim3,
267  0, 0, 0);
268  #endif
269  #endif
270 
271  // Part2:
272  int zdim = myGrid.dim3;
273  int ny = myGrid.dim2;
274 
275  // finish forward FFT (x dimension)
276  #ifdef NAMD_FFTW
277  #ifdef NAMD_FFTW_3
278  fftwf_execute(forward_plan_x);
279  #else
280  fftw(forward_plan_x, ny * zdim / 2, (fftw_complex *)qGrid,
281  ny * zdim / 2, 1, work, 1, 0);
282  #endif
283  #endif
284 
285  // Calculate energy and virial
286  double tempVir[6];
287  recipEnergy += myKSpace->compute_energy(qGrid, lattice, alpha, tempVir);
288  for(i = 0; i < 6; i++) {
289  recipVirial[i] += tempVir[i];
290  }
291 
292  #ifdef NAMD_FFTW
293  #ifdef NAMD_FFTW_3
294  fftwf_execute(backward_plan_x);
295  #else
296  // start backward FFT (x dimension)
297  fftw(backward_plan_x, ny * zdim / 2, (fftw_complex *)qGrid,
298  ny * zdim / 2, 1, work, 1, 0);
299  #endif
300  #endif
301 
302  // Part 3:
303  #ifdef NAMD_FFTW
304  #ifdef NAMD_FFTW_3
305  fftwf_execute(backward_plan_yz);
306  #else
307  rfftwnd_complex_to_real(backward_plan_yz, myGrid.K1,
308  (fftw_complex *)qGrid, 1, myGrid.dim2 * myGrid.dim3 / 2,
309  0, 0, 0);
310  #endif
311  #endif
312  k = 0;
313  for (i = 0; i < myGrid.K1 * myGrid.K2; i++) {
314  for (j = 0; j < myGrid.dim3; j++) {
315  q_arr[i][j] = qGrid[k++];
316  }
317  }
318 #endif // USE_LJPME
319 }
320 
321 double LjPmeMgr::selfCompute(const double &alphaLJ){
322  double energy = 0.0;
323  double c3Term;
324  double alpha6 = pow(alphaLJ, 6.0);
325  for(int i=0; i < numAtoms; i++) {
326  c3Term = dataArr[4*i+3];
327  energy += c3Term*c3Term;
328  }
329  return (energy * alpha6 / 12.0);
330 }
void compute_scaledForces(const float *const *q_arr, double *pos, double *force, const Lattice &lattice)
void computeLongRange(const double *ljPmeCoord, const Lattice &lattice, const double &alphaLJ, double *force, double &energy, double virial[][3], bool doEnergy)
Definition: LjPmeMgr.C:158
std::ostream & iINFO(std::ostream &s)
Definition: InfoStream.C:81
Definition: Vector.h:72
void gridCalculation(const double &alpha, const Lattice &lattice)
Definition: LjPmeMgr.C:251
~LjPmeMgr()
Definition: LjPmeMgr.C:73
std::ostream & endi(std::ostream &s)
Definition: InfoStream.C:54
BigReal z
Definition: Vector.h:74
#define iout
Definition: InfoStream.h:51
void setScaledCoordinates(const double *refPos, const Lattice &lattice)
Definition: LjPmeMgr.C:202
void initialize(const SimParameters *simParams, const int nAtoms)
Definition: LjPmeMgr.C:14
int dim2
Definition: LjPmeBase.h:22
int dim3
Definition: LjPmeBase.h:22
double compute_energy(float *q_arr, const Lattice &lattice, double ewald, double *virial)
Definition: LjPmeKSpace.C:52
BigReal x
Definition: Vector.h:74
NAMD_HOST_DEVICE Vector a_r() const
Definition: Lattice.h:284
NAMD_HOST_DEVICE Vector b_r() const
Definition: Lattice.h:285
void NAMD_die(const char *err_msg)
Definition: common.C:147
int K3
Definition: LjPmeBase.h:21
NAMD_HOST_DEVICE Vector c_r() const
Definition: Lattice.h:286
void optimizeFFT()
Definition: LjPmeMgr.C:91
double selfCompute(const double &alphaLJ)
Definition: LjPmeMgr.C:321
#define simParams
Definition: Output.C:129
void fill_charges(float **q_arr, char *f_arr, char *fz_arr, double *p)
BigReal y
Definition: Vector.h:74
int block2
Definition: LjPmeBase.h:24
int block1
Definition: LjPmeBase.h:24
int K1
Definition: LjPmeBase.h:21
int K2
Definition: LjPmeBase.h:21
NAMD_HOST_DEVICE Vector origin() const
Definition: Lattice.h:278
int order
Definition: LjPmeBase.h:23