NAMD
LjPmeKSpace.C
Go to the documentation of this file.
1 
7 #include <stdlib.h>
8 #include "LjPmeKSpace.h"
9 #include "Lattice.h"
10 #include "LjPmeBase.h"
11 
13  : myGrid(grid) {
14  int K1, K2, K3, order;
15  K1=myGrid.K1; K2=myGrid.K2, K3=myGrid.K3; order=myGrid.order;
16 
17  bm1 = new double[K1];
18  bm2 = new double[K2];
19  bm3 = new double[K3];
20 
21  switch (myGrid.order) {
22  case 4:
23  compute_b_moduli<4>(bm1, K1);
24  compute_b_moduli<4>(bm2, K2);
25  compute_b_moduli<4>(bm3, K3);
26  break;
27  case 6:
28  compute_b_moduli<6>(bm1, K1);
29  compute_b_moduli<6>(bm2, K2);
30  compute_b_moduli<6>(bm3, K3);
31  break;
32  case 8:
33  compute_b_moduli<8>(bm1, K1);
34  compute_b_moduli<8>(bm2, K2);
35  compute_b_moduli<8>(bm3, K3);
36  break;
37  case 10:
38  compute_b_moduli<10>(bm1, K1);
39  compute_b_moduli<10>(bm2, K2);
40  compute_b_moduli<10>(bm3, K3);
41  break;
42  default: NAMD_die("unsupported LJPMEInterpOrder");
43  }
44 }
45 
47  delete [] bm1;
48  delete [] bm2;
49  delete [] bm3;
50 }
51 
52 double LjPmeKSpace::compute_energy(float *q_arr, const Lattice &lattice,
53  double ewald, double *virial) {
54  double energy = 0.0;
55  double v0 = 0.0;
56  double v1 = 0.0;
57  double v2 = 0.0;
58  double v3 = 0.0;
59  double v4 = 0.0;
60  double v5 = 0.0;
61 
62  int n;
63  int k1, k2, k3, ind;
64  int K1, K2, K3;
65  int maxK1, maxK2, maxK3;
66 
67  K1=myGrid.K1; K2=myGrid.K2; K3=myGrid.K3;
68  maxK1 = K1/2; maxK2 = K2/2; maxK3 = K3/2;
69  // Constant needed to calculate the LJ-PME screening function
70  double box_factor = -M_PI*SQRT_PI/(3.0*lattice.volume());
71  double beta3 = ewald*ewald*ewald;
72  double fac1 = -2.0*ewald*M_PI*M_PI;
73  double fac2 = -M_PI*M_PI/(ewald*ewald);
74  double fac3 = 2.0*M_PI*M_PI*M_PI*SQRT_PI;
75  double fac4 = M_PI/ewald;
76 
77  //printf("LJ-PME: Grid(%d, %d, %d) \n", K1, K2, K3);
78  //printf("box_factor: %6.12f, beta3: %6.12f, fact1: %6.12f, fact2: %6.12f, fact3: %6.12f \n",
79  //box_factor, beta3, fac1, fac2, fac3);
80 
81  if ( lattice.orthogonal() ) {
82  double recipx = lattice.a_r().x;
83  double recipy = lattice.b_r().y;
84  double recipz = lattice.c_r().z;
85  //printf("recip_x: %6.12f, recip_y: %6.12f, recip_z: %6.12f \n", recipx, recipy, recipz);
86 
87  ind = 0;
88  for ( k1=0; k1<K1; ++k1 ) {
89  double m1, m11, b1;
90  b1 = bm1[k1];
91  // Grid indices in the upper half correspond to negative frequencies!
92  int k1_s = k1<=maxK1 ? k1 : k1-K1;
93  m1 = k1_s*recipx;
94  m11 = m1*m1;
95  for ( k2=0; k2<K2; ++k2 ) {
96  double m2, m22, b1b2;
97  b1b2 = b1*bm2[k2];
98  // Grid indices in the upper half correspond to negative frequencies!
99  int k2_s = k2<=maxK2 ? k2 : k2-K2;
100  m2 = k2_s*recipy;
101  m22 = m2*m2;
102  // We use symmetric in z dimension. Unlike electrostatic, we can have m == 0
103  for ( k3=0; k3<=maxK3; ++k3 ) {
104  double m3, m33, msq, mFreq, vir, tempE;
105  double b1b2b3, eTerm, q2, qr, qc;
106  // Inverse b-spline module (b1*b2*b3)
107  b1b2b3 = bm3[k3] *b1b2;
108  m3 = k3*recipz;
109  m33 = m3*m3;
110  // Calculate the square root of frequency
111  msq = m11 + m22 + m33;
112  mFreq = sqrt(msq);
113  qr = q_arr[ind]; qc=q_arr[ind+1];
114  // Using symmetary, multiply the structure factor by 2
115  q2 = 2.0*(qr*qr + qc*qc);
116  // except for (k3 == 0) || ( k3 == K3/2)
117  if ( (k3 == 0) || ( k3 == maxK3 && ! (K3 & 1) ) ) q2 *= 0.5;
118  // Calculate the energy term (f(x) / b_spline) for this frequency m
119  eTerm = b1b2b3*box_factor*((beta3 + fac1*msq)*exp(fac2*msq) + fac3*msq*mFreq*erfc(fac4*mFreq));
120  // Calculate the Long-range PME contribution ro dispersion energy
121  q_arr[ind] *= eTerm;
122  q_arr[ind+1] *= eTerm;
123  // Calculate the Energy
124  tempE = q2*eTerm;
125  energy += tempE;
126  // Calculate the virial using GROMACS formulation
127  vir = 3.0*box_factor*b1b2b3*(fac1*exp(fac2*msq)+fac3*mFreq*erfc(fac4*mFreq))*q2;
128  v0 += tempE + vir*m11;
129  v1 += vir*m1*m2;
130  v2 += vir*m1*m3;
131  v3 += tempE + vir*m22;
132  v4 += vir*m2*m3;
133  v5 += tempE + vir*m33;
134 
135  ind += 2;
136  }
137  }
138  }
139  } else {
140  Vector recip1 = lattice.a_r();
141  Vector recip2 = lattice.b_r();
142  Vector recip3 = lattice.c_r();
143  double recip2_x = recip2.x;
144  double recip2_y = recip2.y;
145  double recip2_z = recip2.z;
146  double recip3_x = recip3.x;
147  double recip3_y = recip3.y;
148  double recip3_z = recip3.z;
149 
150  ind = 0;
151  for ( k1=0; k1<K1; ++k1 ) {
152  double b1; Vector m1;
153  b1 = bm1[k1];
154  // Grid indices in the upper half correspond to negative frequencies!
155  int k1_s = k1<=maxK1 ? k1 : k1-K1;
156  m1 = k1_s*recip1;
157  for ( k2=0; k2<K2; ++k2 ) {
158  double b1b2, m2_x, m2_y, m2_z;
159  b1b2 = b1*bm2[k2];
160  // Grid indices in the upper half correspond to negative frequencies!
161  int k2_s = k2<=maxK2 ? k2 : k2-K2;
162  m2_x = m1.x + k2_s*recip2_x;
163  m2_y = m1.y + k2_s*recip2_y;
164  m2_z = m1.z + k2_s*recip2_z;
165  // We use symmetric in z dimension. Unlike electrostatic, we can have m == 0
166  for ( k3=0; k3<=maxK3; ++k3 ) {
167  double xp3, msq, mFreq, vir, tempE;
168  double b1b2b3, eTerm, q2, qr, qc;
169  double m_x, m_y, m_z;
170  // Inverse b-spline module (b1*b2*b3)
171  b1b2b3 = bm3[k3] *b1b2;
172  m_x = m2_x + k3*recip3_x;
173  m_y = m2_y + k3*recip3_y;
174  m_z = m2_z + k3*recip3_z;
175  // Calculate the square root of frequency
176  msq = m_x*m_x + m_y*m_y + m_z*m_z;
177  mFreq = sqrt(msq);
178  qr = q_arr[ind]; qc=q_arr[ind+1];
179  // Using symmetary, multiply the structure factor by 2
180  q2 = 2.0*(qr*qr + qc*qc);
181  // except for (k3 == 0) || ( k3 == K3/2)
182  if ( (k3 == 0) || ( k3 == maxK3 && ! (K3 & 1) ) ) q2 *= 0.5;
183  // Calculate the energy term (f(x) / b_spline) for this frequency m
184  eTerm = b1b2b3*box_factor*((beta3 + fac1*msq)*exp(fac2*msq) + fac3*msq*mFreq*erfc(fac4*mFreq));
185  // Calculate and write back convolution data to grid
186  q_arr[ind] *= eTerm;
187  q_arr[ind+1] *= eTerm;
188  // Calculate the Long-range PME contribution ro dispersion energy
189  tempE = q2*eTerm;
190  energy += tempE;
191  // Calculate the virial using GROMACS formulation
192  vir = 3.0*box_factor*b1b2b3*(fac1*exp(fac2*msq)+fac3*mFreq*erfc(fac4*mFreq))*q2;
193  v0 += tempE + vir*m_x*m_x;
194  v1 += vir*m_x*m_y;
195  v2 += vir*m_x*m_z;
196  v3 += tempE + vir*m_y*m_y;
197  v4 += vir*m_y*m_z;
198  v5 += tempE + vir*m_z*m_z;
199  ind += 2;
200  }
201  }
202  }
203 
204  }
205 
206  virial[0] = 0.5 * v0;
207  virial[1] = 0.5 * v1;
208  virial[2] = 0.5 * v2;
209  virial[3] = 0.5 * v3;
210  virial[4] = 0.5 * v4;
211  virial[5] = 0.5 * v5;
212  return 0.5*energy;
213 }
214 
215 template <int order>
216 void LjPmeKSpace::compute_b_moduli(double *bm, int K) {
217  int i;
218  double fr[3];
219 
220  double *M = new double[3*order];
221  double *dM = new double[3*order];
222  double *scratch = new double[K];
223 
224  fr[0]=fr[1]=fr[2]=0.0;
225  compute_LjPme_b_spline<order>(fr,M,dM);
226  for (i=0; i<order; i++) bm[i] = M[i];
227  for (i=order; i<K; i++) bm[i] = 0.0;
228  this->dftmod(scratch, bm, K);
229  // Store the inverse bspline module
230  for (i=0; i<K; i++) bm[i] = 1.0/scratch[i];
231 
232  delete [] scratch;
233  delete [] dM;
234  delete [] M;
235 }
236 
237 void LjPmeKSpace::dftmod(double *bsp_mod, double *bsp_arr, int nfft) {
238  int j, k;
239  double twopi, arg, sum1, sum2;
240  double infft = 1.0/nfft;
241 /* Computes the modulus of the discrete fourier transform of bsp_arr, */
242 /* storing it into bsp_mod */
243  twopi = 2.0 * M_PI;
244 
245  for (k = 0; k <nfft; ++k) {
246  sum1 = 0.;
247  sum2 = 0.;
248  for (j = 0; j < nfft; ++j) {
249  arg = twopi * k * j * infft;
250  sum1 += bsp_arr[j] * cos(arg);
251  sum2 += bsp_arr[j] * sin(arg);
252  }
253  bsp_mod[k] = sum1*sum1 + sum2*sum2;
254  }
255 }
#define M_PI
Definition: GoMolecule.C:40
Definition: Vector.h:72
BigReal z
Definition: Vector.h:74
NAMD_HOST_DEVICE int orthogonal() const
Definition: Lattice.h:273
#define SQRT_PI
Definition: ComputeExt.C:30
#define order
Definition: PmeRealSpace.C:235
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 BigReal volume(void) const
Definition: Lattice.h:293
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
LjPmeKSpace(LjPmeGrid grid)
Definition: LjPmeKSpace.C:12
BigReal y
Definition: Vector.h:74
int K1
Definition: LjPmeBase.h:21
int K2
Definition: LjPmeBase.h:21
int order
Definition: LjPmeBase.h:23