16 NAMD_die(
"In order to use LJ-PME, you must build with -DUSE_LJPME");
18 #if defined(NAMD_FFTW_3) || ! defined(NAMD_FFTW) 23 NAMD_die(
"LjPmeMgr has already been initialized!");
26 selfEnergy = recipEnergy = 0.0;
35 myGrid.
dim3 = 2 * (myGrid.
K3 / 2 + 1);
36 myGrid.
block1 = (myGrid.
K1 + numRecipPes - 1) / numRecipPes;
37 myGrid.
block2 = (myGrid.
K2 + numRecipPes - 1) / numRecipPes;
42 dataArr =
new double[4*numAtoms];
43 if (dataArr == 0)
NAMD_die(
"can't allocate LJ-PME Manager dataArr buffer");
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 *));
52 for (
int i = 0; i < fsize; i++)
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));
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");
65 qGrid =
new float[qsize];
66 if (qGrid == 0)
NAMD_die(
"can't allocate LJ-PME Manager qGrid buffer");
69 memset((
void *)qGrid, 0, qsize *
sizeof(
float));
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;
84 for (
int i = 0; i < fsize; ++i) {
96 #if defined(USE_LJPME) && ! defined(NAMD_FFTW_3) 102 work =
new fftwf_complex[n[0]];
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);
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);
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);
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,
132 work =
new fftw_complex[n[0]];
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,
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);
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);
147 backward_plan_yz = rfftwnd_create_plan_specific(2, n + 1, FFTW_COMPLEX_TO_REAL,
148 FFTW_ESTIMATE | FFTW_IN_PLACE | FFTW_USE_WISDOM,
153 NAMD_die(
"Sorry, FFTW must be compiled in to use LJ-PME.");
159 const Lattice &lattice,
const double &alphaLJ,
160 double *force,
double &energy,
double virial[][3],
162 for (
int i = 0; i < fsize; ++i) {
164 memset((
void *)(q_arr[i]), 0, myGrid.
dim3 *
sizeof(
float));
168 memset((
void *)f_arr, 0, fsize *
sizeof(
char));
169 memset((
void *)fz_arr, 0, myGrid.
dim3 *
sizeof(
char));
171 for(
int i = 0; i < 6; i++) {
172 recipVirial[i] = 0.0;
183 myRealSpace->
fill_charges(q_arr, f_arr, fz_arr, dataArr);
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];
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;
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;
226 for (
int i=0; i<numAtoms; 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) );
240 if ( px == K1 ) px = 0;
241 if ( py == K2 ) py = 0;
242 if ( pz == K3 ) pz = 0;
245 dataArr[index+1] = py;
246 dataArr[index+2] = pz;
247 dataArr[index+3] = c3Term;
253 #if defined(USE_LJPME) && ! defined(NAMD_FFTW_3) 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];
263 fftwf_execute(forward_plan_yz);
265 rfftwnd_real_to_complex(forward_plan_yz, myGrid.
K1,
266 (fftw_real *)qGrid, 1, myGrid.
dim2 * myGrid.
dim3,
272 int zdim = myGrid.
dim3;
273 int ny = myGrid.
dim2;
278 fftwf_execute(forward_plan_x);
280 fftw(forward_plan_x, ny * zdim / 2, (fftw_complex *)qGrid,
281 ny * zdim / 2, 1, work, 1, 0);
287 recipEnergy += myKSpace->
compute_energy(qGrid, lattice, alpha, tempVir);
288 for(i = 0; i < 6; i++) {
289 recipVirial[i] += tempVir[i];
294 fftwf_execute(backward_plan_x);
297 fftw(backward_plan_x, ny * zdim / 2, (fftw_complex *)qGrid,
298 ny * zdim / 2, 1, work, 1, 0);
305 fftwf_execute(backward_plan_yz);
307 rfftwnd_complex_to_real(backward_plan_yz, myGrid.
K1,
308 (fftw_complex *)qGrid, 1, myGrid.
dim2 * myGrid.
dim3 / 2,
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++];
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;
329 return (energy * alpha6 / 12.0);
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)
std::ostream & iINFO(std::ostream &s)
void gridCalculation(const double &alpha, const Lattice &lattice)
std::ostream & endi(std::ostream &s)
void setScaledCoordinates(const double *refPos, const Lattice &lattice)
void initialize(const SimParameters *simParams, const int nAtoms)
double compute_energy(float *q_arr, const Lattice &lattice, double ewald, double *virial)
NAMD_HOST_DEVICE Vector a_r() const
NAMD_HOST_DEVICE Vector b_r() const
void NAMD_die(const char *err_msg)
NAMD_HOST_DEVICE Vector c_r() const
double selfCompute(const double &alphaLJ)
void fill_charges(float **q_arr, char *f_arr, char *fz_arr, double *p)
NAMD_HOST_DEVICE Vector origin() const