15 #if defined(NAMD_FFTW_3) || ! defined(NAMD_FFTW) 16 NAMD_die(
"LJPMESerial requires FFTW 2");
19 NAMD_die(
"LjPmeMgr has already been initialized!");
22 selfEnergy = recipEnergy = 0.0;
31 myGrid.
dim3 = 2 * (myGrid.
K3 / 2 + 1);
32 myGrid.
block1 = (myGrid.
K1 + numRecipPes - 1) / numRecipPes;
33 myGrid.
block2 = (myGrid.
K2 + numRecipPes - 1) / numRecipPes;
38 dataArr =
new double[4*numAtoms];
39 if (dataArr == 0)
NAMD_die(
"can't allocate LJ-PME Manager dataArr buffer");
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 *));
48 for (
int i = 0; i < fsize; i++)
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));
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");
61 qGrid =
new float[qsize];
62 if (qGrid == 0)
NAMD_die(
"can't allocate LJ-PME Manager qGrid buffer");
65 memset((
void *)qGrid, 0, qsize *
sizeof(
float));
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;
80 for (
int i = 0; i < fsize; ++i) {
99 work =
new fftwf_complex[n[0]];
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);
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);
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);
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,
129 NAMD_die(
"LJPMESerial requires FFTW 2");
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 LJPMESerial.");
158 const Lattice &lattice,
const double &alphaLJ,
159 double *force,
double &energy,
double virial[][3],
161 for (
int i = 0; i < fsize; ++i) {
163 memset((
void *)(q_arr[i]), 0, myGrid.
dim3 *
sizeof(
float));
167 memset((
void *)f_arr, 0, fsize *
sizeof(
char));
168 memset((
void *)fz_arr, 0, myGrid.
dim3 *
sizeof(
char));
170 for(
int i = 0; i < 6; i++) {
171 recipVirial[i] = 0.0;
182 myRealSpace->
fill_charges(q_arr, f_arr, fz_arr, dataArr);
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];
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;
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;
225 for (
int i=0; i<numAtoms; 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) );
239 if ( px == K1 ) px = 0;
240 if ( py == K2 ) py = 0;
241 if ( pz == K3 ) pz = 0;
244 dataArr[index+1] = py;
245 dataArr[index+2] = pz;
246 dataArr[index+3] = c3Term;
254 NAMD_die(
"LJPMESerial requires FFTW 2");
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];
265 fftwf_execute(forward_plan_yz);
267 rfftwnd_real_to_complex(forward_plan_yz, myGrid.
K1,
268 (fftw_real *)qGrid, 1, myGrid.
dim2 * myGrid.
dim3,
274 int zdim = myGrid.
dim3;
275 int ny = myGrid.
dim2;
280 fftwf_execute(forward_plan_x);
282 fftw(forward_plan_x, ny * zdim / 2, (fftw_complex *)qGrid,
283 ny * zdim / 2, 1, work, 1, 0);
289 recipEnergy += myKSpace->
compute_energy(qGrid, lattice, alpha, tempVir);
290 for(i = 0; i < 6; i++) {
291 recipVirial[i] += tempVir[i];
296 fftwf_execute(backward_plan_x);
299 fftw(backward_plan_x, ny * zdim / 2, (fftw_complex *)qGrid,
300 ny * zdim / 2, 1, work, 1, 0);
307 fftwf_execute(backward_plan_yz);
309 rfftwnd_complex_to_real(backward_plan_yz, myGrid.
K1,
310 (fftw_complex *)qGrid, 1, myGrid.
dim2 * myGrid.
dim3 / 2,
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++];
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;
331 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