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