4 * Created by Toshi Nagata on 2012/11/03.
5 * Copyright 2012 Toshi Nagata. All rights reserved.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation version 2 of the License.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
26 /* Temporary structure for Particle Mesh Ewald (Some fields are also used for Direct Ewald) */
28 Int grid_x, grid_y, grid_z; /* Grid size for each cell direction (should be even numbers) */
29 Int natoms; /* Number of atoms (necessary to indicate the size of allocated memory) */
30 fftw_complex *qarray; /* Q array; size grid_x * grid_y * grid_z */
31 fftw_complex *qfarray; /* Finv(Q) (Finv is inverse FFT); size grid_x * grid_y * grid_z */
32 fftw_complex *qqarray; /* F(B*C*Finv(Q)) (F is FFT); size grid_x * grid_y * grid_z */
33 fftw_complex *b0array; /* Complex B array (for debug); size grid_x + grid_y + grid_z */
34 double *marray; /* M array; size (grid_x + grid_y + grid_z) * 2 * natoms */
35 double *barray; /* B array; size grid_x + grid_y + grid_z */
36 double *bcarray; /* B*C array; size grid_x * grid_y * grid_z */
37 double *carray; /* C array (for debug); size grid_x * grid_y * grid_z */
38 fftw_plan plan1; /* Inverse FFT of Q */
39 fftw_plan plan2; /* FFT of (B*C*Finv(Q)) */
40 Int order; /* Order of cardinal B spline (must be even and >=4 and <= MAX_DIM_SPLINE ) */
41 Double direct_limit; /* Maximum (k/beta) for direct Ewald summation (default = 1.29; this is where erfc(lim*PI) = 1e-8 */
42 Int *kxyz; /* Reciprocal lattice indices for direct Ewald summation */
44 Double self_correction; /* Self correction term, -beta/sqrt(PI)*sigma(charge**2) */
47 static Double *s_spline_coeffs;
49 #define SPLINE_COEFF(_n, _m, _k) s_spline_coeffs[(_k) + MAX_DIM_SPLINE * ((_m) + MAX_DIM_SPLINE * ((_n) - 2))]
51 /* Calculate the coefficients of the cardinal B-spline functions */
53 s_initialize_spline_coeffs(void)
56 if (s_spline_coeffs != NULL && SPLINE_COEFF(2, 0, 1) == 1.0 && SPLINE_COEFF(2, 1, 1) == -1.0)
57 return; /* Already initialized */
58 s_spline_coeffs = (Double *)calloc(sizeof(Double), (MAX_DIM_SPLINE - 1) * MAX_DIM_SPLINE * MAX_DIM_SPLINE);
59 SPLINE_COEFF(2, 0, 0) = 0.0;
60 SPLINE_COEFF(2, 0, 1) = 1.0;
61 SPLINE_COEFF(2, 1, 0) = 2.0;
62 SPLINE_COEFF(2, 1, 1) = -1.0;
63 for (n = 3; n <= MAX_DIM_SPLINE; n++) {
64 for (m = 0; m < n; m++) {
67 for (k = 0; k < n; k++) {
73 for (j = k; j < n - 1; j++) {
74 b += SPLINE_COEFF(n - 1, m - 1, j) * bin * sgn;
76 bin = bin * (j + 1) / (j + 1 - k); /* Always dividable; this is a binomial coefficient (j+1 k) */
79 if (k > 0 && m < n - 1)
80 a = SPLINE_COEFF(n - 1, m, k - 1);
82 a = (a + n * b - b_prev) / (n - 1);
84 SPLINE_COEFF(n, m, k) = a;
91 s_calc_spline(Int order, Double x)
95 if (x <= 0 || x >= order)
98 y = SPLINE_COEFF(order, m, order - 1);
99 for (i = order - 2; i >= 0; i--)
100 y = y * x + SPLINE_COEFF(order, m, i);
105 s_complex_add(fftw_complex dst, fftw_complex src1, fftw_complex src2)
107 dst[0] = src1[0] + src2[0];
108 dst[1] = src1[1] + src2[1];
112 s_complex_scale_add(fftw_complex dst, fftw_complex src1, fftw_complex src2, double scale)
114 dst[0] = src1[0] + src2[0] * scale;
115 dst[1] = src1[1] + src2[1] * scale;
119 s_complex_mul(fftw_complex dst, fftw_complex src1, fftw_complex src2)
122 real = src1[0] * src2[0] - src1[1] * src2[1];
123 dst[1] = src1[0] * src2[1] + src1[1] * src2[0];
129 s_output_array_as_cube(MDArena *arena, fftw_complex *ary, const char *fname)
132 /* Output array for visualize */
135 FILE *fp = fopen(fname, "w");
136 Molecule *mol = arena->xmol;
137 XtalCell *cp = mol->cell;
138 MDPME *pme = arena->pme;
140 fprintf(fp, "PME test\n");
141 fprintf(fp, "Output of the array\n");
142 fprintf(fp, "%5d %11.6f %11.6f %11.6f\n", -(mol->natoms), cp->origin.x, cp->origin.y, cp->origin.z);
143 fprintf(fp, "%5d %11.6f %11.6f %11.6f\n", pme->grid_x, cp->axes[0].x / pme->grid_x, cp->axes[0].y / pme->grid_x, cp->axes[0].z / pme->grid_x);
144 fprintf(fp, "%5d %11.6f %11.6f %11.6f\n", pme->grid_y, cp->axes[1].x / pme->grid_y, cp->axes[1].y / pme->grid_y, cp->axes[1].z / pme->grid_y);
145 fprintf(fp, "%5d %11.6f %11.6f %11.6f\n", pme->grid_z, cp->axes[2].x / pme->grid_z, cp->axes[2].y / pme->grid_z, cp->axes[2].z / pme->grid_z);
147 /* Atomic information */
148 for (i = 0; i < mol->natoms; i++) {
149 Atom *ap = ATOM_AT_INDEX(mol->atoms, i);
150 fprintf(fp, "%5d %11.6f %11.6f %11.6f %11.6f\n", ap->atomicNumber, (double)ap->charge, ap->r.x, ap->r.y, ap->r.z);
152 fprintf(fp, "%5d%5d\n", 1, 1);
155 for (i = 0; i < pme->grid_x * pme->grid_y * pme->grid_z; i++) {
156 d = sqrt(ary[i][0] * ary[i][0] + ary[i][1] * ary[i][1]);
162 max = (max > -min ? max : -min);
163 for (i = n = 0; i < pme->grid_x; i++) {
164 for (j = 0; j < pme->grid_y; j++) {
165 for (k = 0; k < pme->grid_z; k++) {
166 fprintf(fp, " %12.5e", sqrt(ary[n][0] * ary[n][0] + ary[n][1] * ary[n][1]) / max);
168 if (k == pme->grid_z - 1 || k % 6 == 5)
176 /* Prepare kxyz for direct Ewald sum */
178 s_prepare_direct_ewald(MDArena *arena)
181 XtalCell *cell = arena->mol->cell;
182 Int pass, count, dc, n, ninit, nstep;
183 raxes[0].x = cell->rtr[0];
184 raxes[0].y = cell->rtr[3];
185 raxes[0].z = cell->rtr[6];
186 raxes[1].x = cell->rtr[1];
187 raxes[1].y = cell->rtr[4];
188 raxes[1].z = cell->rtr[7];
189 raxes[2].x = cell->rtr[2];
190 raxes[2].y = cell->rtr[5];
191 raxes[2].z = cell->rtr[8];
195 for (pass = 0; pass < 2; pass++) {
198 ip = arena->pme->kxyz;
199 for (n = ninit; n <= 50; n += nstep) {
200 Int nx, ny, nz, nx0, ny0, nz0;
204 nx0 = (arena->periodic_a ? n : 1);
205 ny0 = (arena->periodic_b ? n : 1);
206 nz0 = (arena->periodic_c ? n : 1);
207 for (nx = -nx0 + 1; nx < nx0; nx++) {
208 VecScale(vx, raxes[0], nx);
209 for (ny = -ny0 + 1; ny < ny0; ny++) {
210 VecScale(vy, raxes[1], ny);
211 for (nz = -nz0 + 1; nz < nz0; nz++) {
213 if (arena->periodic_a == 0 || (nx > -n + nstep && nx < n - nstep))
214 if (arena->periodic_b == 0 || (ny > -n + nstep && ny < n - nstep))
215 if (arena->periodic_c == 0 || (nz > -n + nstep && nz < n - nstep))
217 if (nx == 0 && ny == 0 && nz == 0)
219 VecScale(vm, raxes[2], nz);
223 if (len / arena->ewald_beta <= arena->pme->direct_limit) {
237 if ((pass == 0 && dc == 0) || (pass == 1 && count <= 0))
241 arena->pme->kxyz = (Int *)realloc(arena->pme->kxyz, sizeof(Int) * 3 * count);
242 arena->pme->nkxyz = count;
249 calc_direct_electrostatic(MDArena *arena)
251 Molecule *mol = arena->mol;
252 XtalCell *cell = arena->mol->cell;
256 Int i, j, n, nx, ny, nz, nx0, ny0, nz0, zero, ninit, nstep;
259 forces = &arena->forces[kPMEIndex * arena->mol->natoms];
261 coul = COULOMBIC / arena->dielectric;
264 for (n = ninit; n <= 50; n += nstep) {
268 nx0 = (arena->periodic_a ? n : 1);
269 ny0 = (arena->periodic_b ? n : 1);
270 nz0 = (arena->periodic_c ? n : 1);
271 for (nx = -nx0 + 1; nx < nx0; nx++) {
272 VecScale(vx, cell->axes[0], nx);
273 for (ny = -ny0 + 1; ny < ny0; ny++) {
274 VecScale(vy, cell->axes[1], ny);
275 for (nz = -nz0 + 1; nz < nz0; nz++) {
277 if (arena->periodic_a == 0 || (nx > -n + nstep && nx < n - nstep))
278 if (arena->periodic_b == 0 || (ny > -n + nstep && ny < n - nstep))
279 if (arena->periodic_c == 0 || (nz > -n + nstep && nz < n - nstep))
281 zero = (nx == 0 && ny == 0 && nz == 0);
282 VecScale(vz, cell->axes[2], nz);
283 for (i = 0, ap = mol->atoms, f = forces; i < mol->natoms; i++, ap = ATOM_NEXT(ap), f++) {
286 for (j = 0, apj = mol->atoms; j < mol->natoms; j++, apj = ATOM_NEXT(apj)) {
287 Double w1, w2, w3, qiqj;
290 qiqj = ap->charge * apj->charge;
296 w1 = 1.0 / VecLength2(rij);
310 if (arena->debug_result != NULL && arena->debug_output_level > 0) {
311 fprintf(arena->debug_result, "Direct electrostatic energy\n");
312 fprintf(arena->debug_result, "N = %d energy = %.9g %.9g\n", n, energy * INTERNAL2KCAL, de * INTERNAL2KCAL);
313 if (arena->debug_output_level > 1) {
314 for (i = 0; i < mol->natoms; i++) {
315 fprintf(arena->debug_result, " %d: %.9g %.9g %.9g\n", i, forces[i].x * coul * INTERNAL2KCAL, forces[i].y * coul * INTERNAL2KCAL, forces[i].z * coul * INTERNAL2KCAL);
319 if (fabs(de) < 1e-7 || fabs(de / energy) < 1e-6)
322 if (arena->debug_result != NULL) {
323 fprintf(arena->debug_result, "Direct electrostatic energy = %g\n", energy);
325 arena->energies[kPMEIndex] += energy;
328 /* Direct Ewald Sum */
330 calc_direct_ewald_force(MDArena *arena)
332 Molecule *mol = arena->mol;
333 XtalCell *cell = arena->mol->cell;
334 Vector raxes[3], *forces;
335 Double energy_rec, coul_v;
336 Int i, n, nx, ny, nz, *ip;
339 /* Reciprocal cell axes */
340 raxes[0].x = cell->rtr[0];
341 raxes[0].y = cell->rtr[3];
342 raxes[0].z = cell->rtr[6];
343 raxes[1].x = cell->rtr[1];
344 raxes[1].y = cell->rtr[4];
345 raxes[1].z = cell->rtr[7];
346 raxes[2].x = cell->rtr[2];
347 raxes[2].y = cell->rtr[5];
348 raxes[2].z = cell->rtr[8];
350 coul_v = COULOMBIC / arena->dielectric / (2 * PI * TransformDeterminant(cell->tr));
351 if (arena->debug_result != NULL)
352 fprintf(arena->debug_result, "Direct Ewald sum\n");
353 forces = &arena->forces[kPMEIndex * arena->mol->natoms];
354 for (n = 0, ip = arena->pme->kxyz; n < arena->pme->nkxyz; n++, ip += 3) {
356 Double de, w, ww, m2;
357 Double s_real, s_imag, *mp;
362 VecScale(vm, raxes[0], nx);
363 VecScaleInc(vm, raxes[1], ny);
364 VecScaleInc(vm, raxes[2], nz);
367 mp = arena->pme->marray;
368 for (i = 0, ap = mol->atoms; i < mol->natoms; i++, ap = ATOM_NEXT(ap)) {
369 Double mr = VecDot(vm, ap->r) * 2 * PI;
370 mp[0] = ap->charge * cos(mr);
371 mp[1] = ap->charge * sin(mr);
376 w = PI * PI * m2 / (arena->ewald_beta * arena->ewald_beta);
378 de += ww * (s_real * s_real + s_imag * s_imag);
379 mp = arena->pme->marray;
380 for (i = 0; i < mol->natoms; i++) {
381 Double w2 = 4 * PI * ww * (s_imag * mp[0] - s_real * mp[1]);
382 f.x = w2 * (nx * raxes[0].x + ny * raxes[1].x + nz * raxes[2].x);
383 f.y = w2 * (nx * raxes[0].y + ny * raxes[1].y + nz * raxes[2].y);
384 f.z = w2 * (nx * raxes[0].z + ny * raxes[1].z + nz * raxes[2].z);
385 VecInc(forces[i], f);
388 if (arena->debug_result != NULL && arena->debug_output_level > 0) {
389 fprintf(arena->debug_result, "(%d %d %d) %.9g %.9g %.6g\n", nx, ny, nz, (ww * (s_real * s_real + s_imag * s_imag)) *coul_v * INTERNAL2KCAL, de * coul_v * INTERNAL2KCAL, sqrt(w) / PI);
394 for (i = 0; i < mol->natoms; i++) {
395 VecScaleSelf(forces[i], coul_v);
397 arena->energies[kPMEIndex] += energy_rec;
398 if (arena->debug_result != NULL) {
399 fprintf(arena->debug_result, "Reciprocal energy = %g\n", energy_rec);
400 if (arena->debug_output_level > 0) {
401 for (i = 0; i < mol->natoms; i++) {
402 fprintf(arena->debug_result, " reciprocal force %d = {%g,%g,%g}\n", i, forces[i].x * INTERNAL2KCAL, forces[i].y * INTERNAL2KCAL, forces[i].z * INTERNAL2KCAL);
408 /* Particle Mesh Ewald Sum */
410 calc_pme_force(MDArena *arena)
416 Int grid_x, grid_y, grid_z, order;
417 Int i, j, k, kx, ky, kz, n, n0, n1, n2;
418 Int debug_level = -1;
419 double m0, m1, t, *mp, *bp, *bcp;
424 Double *energy = &arena->energies[kPMEIndex];
425 Vector *forces = &arena->forces[kPMEIndex * arena->mol->natoms];
427 if (arena == NULL || (mol = arena->mol) == NULL || (pme = arena->pme) == NULL)
430 if (arena->debug_result != NULL) {
431 debug_level = arena->debug_output_level;
434 forces = &arena->forces[kPMEIndex * arena->mol->natoms];
435 dielec_r = COULOMBIC / arena->dielectric;
438 grid_x = pme->grid_x;
439 grid_y = pme->grid_y;
440 grid_z = pme->grid_z;
443 beta2 = arena->ewald_beta * arena->ewald_beta;
444 memset(cp, 0, sizeof(fftw_complex) * grid_x * grid_y * grid_z);
445 for (i = 0, ap = mol->atoms; i < mol->natoms; i++, ap = ATOM_NEXT(ap)) {
446 /* Calculate fractional coordinate */
447 TransformVec(&r, mol->cell->rtr, &ap->r);
451 mp = pme->marray + (grid_x + grid_y + grid_z) * 2 * i;
452 for (k = 0; k < grid_x; k++) {
457 n0 = floor((r.x - order - k) / grid_x) + 1;
458 n1 = floor((r.x - k) / grid_x);
460 for (n = n0; n <= n1; n++) {
461 t = r.x - k - n * grid_x;
462 m0 += s_calc_spline(order, t);
463 m1 += (s_calc_spline(order - 1, t) - s_calc_spline(order - 1, t - 1)) * grid_x;
468 if (debug_level > 1) fprintf(arena->debug_result, "mx[%d] (%g, %g)\n", k, m0, m1);
470 for (k = 0; k < grid_y; k++) {
475 n0 = floor((r.y - order - k) / grid_y) + 1;
476 n1 = floor((r.y - k) / grid_y);
478 for (n = n0; n <= n1; n++) {
479 t = r.y - k - n * grid_y;
480 m0 += s_calc_spline(order, t);
481 m1 += (s_calc_spline(order - 1, t) - s_calc_spline(order - 1, t - 1)) * grid_y;
484 mp[(k + grid_x) * 2] = m0;
485 mp[(k + grid_x) * 2 + 1] = m1;
486 if (debug_level > 1) fprintf(arena->debug_result, "my[%d] (%g, %g)\n", k, m0, m1);
488 for (k = 0; k < grid_z; k++) {
493 n0 = floor((r.z - order - k) / grid_z) + 1;
494 n1 = floor((r.z - k) / grid_z);
496 for (n = n0; n <= n1; n++) {
497 t = r.z - k - n * grid_z;
498 m0 += s_calc_spline(order, t);
499 m1 += (s_calc_spline(order - 1, t) - s_calc_spline(order - 1, t - 1)) * grid_z;
502 mp[(k + grid_x + grid_y) * 2] = m0;
503 mp[(k + grid_x + grid_y) * 2 + 1] = m1;
504 if (debug_level > 1) fprintf(arena->debug_result, "mz[%d] (%g, %g)\n", k, m0, m1);
506 for (kx = 0; kx < grid_x; kx++) {
507 for (ky = 0; ky < grid_y; ky++) {
508 for (kz = 0; kz < grid_z; kz++) {
509 cp[kz + grid_z * (ky + grid_y * kx)][0] += ap->charge * mp[kx * 2] * mp[(ky + grid_x) * 2] * mp[(kz + grid_x + grid_y) * 2];
514 if (debug_level > 1) {
515 for (kx = 0; kx < grid_x; kx++) {
516 for (ky = 0; ky < grid_y; ky++) {
517 for (kz = 0; kz < grid_z; kz++) {
518 j = kz + grid_z * (ky + grid_y * kx);
519 fprintf(arena->debug_result, "Q[%d,%d,%d] = (%g, %g)\n", kx, ky, kz, pme->qarray[j][0], pme->qarray[j][1]);
525 /* Q is transformed by inverse FFT into qfarray */
526 fftw_execute(pme->plan1);
528 /* Dump Finv(Q) and structure factor */
529 if (debug_level > 1) {
530 fprintf(arena->debug_result, "kx ky kz FB_re FB_im S_re S_im Sa_re Sa_im\n");
531 for (kx = 0; kx < grid_x; kx++) {
532 for (ky = 0; ky < grid_y; ky++) {
533 for (kz = 0; kz < grid_z; kz++) {
535 j = kz + grid_z * (ky + grid_y * kx);
536 fprintf(arena->debug_result, "%2d %2d %2d ", kx, ky, kz);
537 bf[0] = pme->qfarray[j][0];
538 bf[1] = pme->qfarray[j][1];
539 s_complex_mul(bf, bf, pme->b0array[kx]);
540 s_complex_mul(bf, bf, pme->b0array[ky + grid_x]);
541 s_complex_mul(bf, bf, pme->b0array[kz + grid_x + grid_y]);
542 fprintf(arena->debug_result, "%g %g ", bf[0], bf[1]);
545 for (i = 0, ap = mol->atoms; i < mol->natoms; i++, ap = ATOM_NEXT(ap)) {
547 fftw_complex cw1, cw2;
549 TransformVec(&r, mol->cell->rtr, &ap->r);
550 kx0 = (kx <= grid_x / 2 ? kx : kx - grid_x);
551 ky0 = (ky <= grid_y / 2 ? ky : ky - grid_y);
552 kz0 = (kz <= grid_z / 2 ? kz : kz - grid_z);
553 t = 2 * PI * (kx0 * r.x + ky0 * r.y + kz0 * r.z);
554 m0 += ap->charge * cos(t);
555 m1 += ap->charge * sin(t);
556 /* Calc interpolated S(m) */
557 n0 = floor(r.x * grid_x - order) + 1;
558 n1 = floor(r.x * grid_x);
559 cw1[0] = cw1[1] = 0.0;
560 for (j = n0; j <= n1; j++) {
561 double w = 2 * PI * kx * j / grid_x;
562 t = s_calc_spline(order, r.x * grid_x - j);
563 cw1[0] += t * cos(w);
564 cw1[1] += t * sin(w);
566 s_complex_mul(cw2, cw1, pme->b0array[kx]);
567 n0 = floor(r.y * grid_y - order) + 1;
568 n1 = floor(r.y * grid_y);
569 cw1[0] = cw1[1] = 0.0;
570 for (j = n0; j <= n1; j++) {
571 double w = 2 * PI * ky * j / grid_y;
572 t = s_calc_spline(order, r.y * grid_y - j);
573 cw1[0] += t * cos(w);
574 cw1[1] += t * sin(w);
576 s_complex_mul(cw1, cw1, pme->b0array[ky + grid_x]);
577 s_complex_mul(cw2, cw2, cw1);
578 n0 = floor(r.z * grid_z - order) + 1;
579 n1 = floor(r.z * grid_z);
580 cw1[0] = cw1[1] = 0.0;
581 for (j = n0; j <= n1; j++) {
582 double w = 2 * PI * kz * j / grid_z;
583 t = s_calc_spline(order, r.z * grid_z - j);
584 cw1[0] += t * cos(w);
585 cw1[1] += t * sin(w);
587 s_complex_mul(cw1, cw1, pme->b0array[kz + grid_x + grid_y]);
588 s_complex_mul(cw2, cw2, cw1);
589 bf[0] += ap->charge * cw2[0];
590 bf[1] += ap->charge * cw2[1];
592 fprintf(arena->debug_result, "%g %g %g %g\n", m0, m1, bf[0], bf[1]);
598 /* C is built and B*C is multiplied into qfarray */
599 volume = TransformDeterminant(mol->cell->tr);
603 for (kx = 0; kx < grid_x; kx++) {
604 n0 = (kx <= grid_x / 2 ? kx : kx - grid_x);
605 for (ky = 0; ky < grid_y; ky++) {
606 n1 = (ky <= grid_y / 2 ? ky : ky - grid_y);
607 for (kz = 0; kz < grid_z; kz++) {
608 Transform *rtr = &(mol->cell->rtr);
611 n2 = (kz <= grid_z / 2 ? kz : kz - grid_z);
612 /* rtr[0,3,6], rtr[1,4,7], rtr[2,5,8] are the reciprocal unit cell vectors */
613 if (n0 == 0 && n1 == 0 && n2 == 0)
616 mv.x = (*rtr)[0] * n0 + (*rtr)[1] * n1 + (*rtr)[2] * n2;
617 mv.y = (*rtr)[3] * n0 + (*rtr)[4] * n1 + (*rtr)[5] * n2;
618 mv.z = (*rtr)[6] * n0 + (*rtr)[7] * n1 + (*rtr)[8] * n2;
620 d = exp(-PI * PI * d / beta2) / (PI * volume * d);
622 k = kz + grid_z * (ky + grid_y * kx);
624 bcp[k] = bp[kx] * bp[grid_x + ky] * bp[grid_x + grid_y + kz] * d;
625 m0 = pme->qfarray[k][0];
626 m1 = pme->qfarray[k][1];
627 pme->qarray[k][0] = m0; /* for debug */
628 pme->qarray[k][1] = m1; /* for debug */
629 *energy += (m0 * m0 + m1 * m1) * bcp[k];
630 pme->qfarray[k][0] = m0 * bcp[k];
631 pme->qfarray[k][1] = m1 * bcp[k];
635 *energy *= dielec_r * 0.5;
637 /* qfarray is transformed by FFT into qqarray */
638 fftw_execute(pme->plan2);
640 if (debug_level > 1) {
641 fprintf(arena->debug_result, "kx ky kz FB_re FB_im F2B2C b c bc QF_re QF_im\n");
642 for (kx = 0; kx < grid_x; kx++) {
643 for (ky = 0; ky < grid_y; ky++) {
644 for (kz = 0; kz < grid_z; kz++) {
646 j = kz + grid_z * (ky + grid_y * kx);
647 fprintf(arena->debug_result, "%2d %2d %2d ", kx, ky, kz);
648 bf[0] = pme->qarray[j][0];
649 bf[1] = pme->qarray[j][1];
650 s_complex_mul(bf, bf, pme->b0array[kx]);
651 s_complex_mul(bf, bf, pme->b0array[ky + grid_x]);
652 s_complex_mul(bf, bf, pme->b0array[kz + grid_x + grid_y]);
653 fprintf(arena->debug_result, "%g %g ", bf[0], bf[1]);
654 fprintf(arena->debug_result, "%g ", (bf[0] * bf[0] + bf[1] * bf[1]) * pme->carray[j]);
655 // fprintf(arena->debug_result, "%g %g ", pme->qarray[j][0] * pme->bcarray[j], pme->qarray[j][1] * pme->bcarray[j]);
656 fprintf(arena->debug_result, "%g %g %g ", pme->barray[kx] * pme->barray[ky + grid_x] * pme->barray[kz + grid_x + grid_y], pme->carray[j], pme->bcarray[j]);
657 fprintf(arena->debug_result, "%g %g\n", pme->qqarray[j][0], pme->qqarray[j][1]);
663 /* Calculate force */
664 memset(forces, 0, sizeof(Vector) * mol->natoms);
665 for (kx = 0; kx < grid_x; kx++) {
666 for (ky = 0; ky < grid_y; ky++) {
667 for (kz = 0; kz < grid_z; kz++) {
668 k = kz + grid_z * (ky + grid_y * kx);
670 for (i = 0; i < mol->natoms; i++) {
671 t = ATOM_AT_INDEX(mol->atoms, i)->charge * pme->qqarray[k][0];
672 forces[i].x += t * mp[kx * 2 + 1] * mp[(ky + grid_x) * 2] * mp[(kz + grid_x + grid_y) * 2];
673 forces[i].y += t * mp[kx * 2] * mp[(ky + grid_x) * 2 + 1] * mp[(kz + grid_x + grid_y) * 2];
674 forces[i].z += t * mp[kx * 2] * mp[(ky + grid_x) * 2] * mp[(kz + grid_x + grid_y) * 2 + 1];
675 mp += (grid_x + grid_y + grid_z) * 2;
681 /* Scale the force vectors and transform into cartesian */
683 memmove(&tf, &mol->cell->rtr, sizeof(Transform));
684 tf[9] = tf[10] = tf[11] = 0.0;
685 for (i = 0; i < mol->natoms; i++) {
687 VecScale(v, forces[i], dielec_r);
688 TransformVec(&forces[i], tf, &v);
692 if (debug_level > 0) {
693 fprintf(arena->debug_result, "PME reciprocal energy = %.9g\n", *energy * INTERNAL2KCAL);
694 fprintf(arena->debug_result, "PME reciprocal forces:\n");
695 for (i = 0; i < mol->natoms; i++)
696 fprintf(arena->debug_result, "%d %.9g %.9g %.9g\n", i, forces[i].x * INTERNAL2KCAL, forces[i].y * INTERNAL2KCAL, forces[i].z * INTERNAL2KCAL);
697 if (debug_level > 1) {
698 fprintf(arena->debug_result, "Grid values:\n");
699 for (i = 0; i < (grid_x + grid_y + grid_z); i++) {
700 fprintf(arena->debug_result, "%d %g %g\n", i, pme->marray[i * 2], pme->marray[i * 2 + 1]);
707 calc_ewald_force(MDArena *arena)
709 if (arena->use_ewald != 0) {
710 if (arena->use_ewald == 1)
711 calc_pme_force(arena);
712 else if (arena->use_ewald == 2)
713 calc_direct_ewald_force(arena);
714 else if (arena->use_ewald == -1) /* Direct sum of electrostatic (very slow) */
715 calc_direct_electrostatic(arena);
717 arena->energies[kPMEIndex] += arena->pme->self_correction;
718 if (arena->debug_result != NULL) {
719 fprintf(arena->debug_result, "%s Ewald reciprocal energy = %.9g\n", (arena->use_ewald == 1 ? "Particle Mesh" : "Direct"), (arena->energies[kPMEIndex] - arena->pme->self_correction) * INTERNAL2KCAL);
720 fprintf(arena->debug_result, "Self correction energy = %.9g\n", arena->pme->self_correction * INTERNAL2KCAL);
721 fprintf(arena->debug_result, "Net Ewald indirect energy = %.9g\n", arena->energies[kPMEIndex] * INTERNAL2KCAL);
728 pme_test(MDArena *arena)
730 s_initialize_spline_coeffs();
731 calc_pme_force(arena);
736 pme_release(MDArena *arena)
738 if (arena == NULL || arena->pme == NULL)
740 if (arena->pme->plan1 != 0)
741 fftw_destroy_plan(arena->pme->plan1);
742 if (arena->pme->plan2 != 0)
743 fftw_destroy_plan(arena->pme->plan2);
744 if (arena->pme->qarray != NULL)
745 fftw_free(arena->pme->qarray);
746 if (arena->pme->qqarray != NULL)
747 fftw_free(arena->pme->qqarray);
748 if (arena->pme->qfarray != NULL)
749 fftw_free(arena->pme->qfarray);
750 if (arena->pme->marray != NULL)
751 free(arena->pme->marray);
752 if (arena->pme->bcarray != NULL)
753 free(arena->pme->bcarray);
754 if (arena->pme->barray != NULL)
755 free(arena->pme->barray);
756 if (arena->pme->kxyz)
757 free(arena->pme->kxyz);
763 s_pme_spline_test(MDArena *arena)
766 exp(2*PI*i*m*x/K) ; target (S(m))
767 b(m)*Sum(k, spline(x - k)*exp(2*PI*i*m*k/K)) ; interpolation
768 b(m)*Fourier(k, m, Sum(n, spline(x - k - n*K))) ; Fourier
769 b(m) = exp(2*PI*i*(order-1)*m/K)/Sum(k=0..order-2, spline(k+1)*exp(2*PI*i*m*k/K))
770 Fourier(k, m, f(k)) = Sum(k, f(k)*exp(2*PI*i*m*k/K)) */
774 fftw_complex a1[DIM], a2[DIM], a3[DIM], a4[DIM], b[DIM], c1, c2;
775 double b2[DIM], c[DIM];
777 double len = 10.0; /* Unit cell dimension */
780 for (m = 0; m < DIM; m++) {
781 k = (m <= DIM / 2 ? m : m - DIM);
782 d = 2 * PI * k * x / kk;
786 for (m = 0; m < DIM; m++) {
788 for (k = 0; k < ORDER - 2; k++) {
789 d = 2 * PI * m * k / kk;
790 w = s_calc_spline(ORDER, k + 1.0);
795 d = c1[0] * c1[0] + c1[1] * c1[1];
798 d = 2 * PI * (ORDER - 1) * m / kk;
801 s_complex_mul(b[m], c2, c1);
803 for (m = 0; m < DIM; m++) {
804 n0 = floor(x - ORDER) + 1;
807 for (k = n0; k <= n1; k++) {
808 d = 2 * PI * m * k / kk;
809 w = s_calc_spline(ORDER, x - k);
813 s_complex_mul(a2[m], b[m], c1);
815 // b(m)*Fourier(k, m, Sum(n, spline(x - k - n*K))) ; Fourier
816 for (m = 0; m < DIM; m++) {
817 n0 = floor((x - m - ORDER) / kk) + 1;
818 n1 = floor((x - m) / kk);
820 for (k = n0; k <= n1; k++) {
821 w += s_calc_spline(ORDER, x - m - k * kk);
826 // Fourier(k, m, f(k)) = Sum(k, f(k)*exp(2*PI*i*m*k/K))
827 for (m = 0; m < DIM; m++) {
829 for (k = 0; k < DIM; k++) {
830 d = -2 * PI * m * k / kk; /* Inverse Fourier */
831 c1[0] += a3[k][0] * cos(d);
832 c1[1] += a3[k][0] * sin(d);
835 s_complex_mul(a4[m], b[m], c1); /* Finv(f(k))*b_conjugate should be S_conjugate */
839 // c = exp(-PI^2*|m|^2/(beta^2))/|m|^2)
840 for (m = 0; m < DIM; m++) {
841 b2[m] = b[m][0] * b[m][0] + b[m][1] * b[m][1];
842 w = (m <= DIM / 2 ? m : m - DIM) / len;
843 c[m] = exp(-PI * PI * w * w / (0.5 * 0.5)) / (w * w);
845 fprintf(stderr, "a1_re a1_im a2_re a2_im a3 a4_re a4_im b2c\n");
846 for (m = 0; m < DIM; m++) {
847 fprintf(stderr, "%.6g %.6g %.6g %.6g %.6g %.6g %.6g %.6g\n", a1[m][0], a1[m][1], a2[m][0], a2[m][1], a3[m][0], a4[m][0], a4[m][1], b2[m] * c[m]);
851 for (m = 1; m < DIM; m++) {
852 d += b2[m] * c[m] * (a1[m][0] * a1[m][0] + a1[m][1] * a1[m][1]);
853 w += b2[m] * c[m] * (a4[m][0] * a4[m][0] + a4[m][1] * a4[m][1]);
855 fprintf(stderr, "\nEnergy = %g %g\n", d, w);
859 pme_init(MDArena *arena)
862 Int xyz, x_y_z, i, j, k;
863 if (arena == NULL || arena->mol == NULL || arena->mol->cell == NULL) {
864 if (arena->pme != NULL)
868 if (arena->use_ewald == 2) {
870 if (arena->pme != NULL)
872 arena->pme = (MDPME *)calloc(sizeof(MDPME), 1);
873 if (arena->pme == NULL)
875 /* Only marray and kxyz is allocated (for force calculation) */
876 arena->pme->marray = (double *)malloc(sizeof(double) * 2 * arena->mol->natoms);
877 arena->pme->direct_limit = 1.29;
878 /* kxyz is initialized */
879 s_prepare_direct_ewald(arena);
881 s_initialize_spline_coeffs();
887 for (n = 3; n <= MAX_DIM_SPLINE; n++) {
888 for (x = 0.0; x <= n; x += 0.1) {
889 double y = s_calc_spline(n, x);
890 double yy = (x * s_calc_spline(n - 1, x) + (n - x) * s_calc_spline(n - 1, x - 1.0)) / (n - 1);
891 if (fabs(y - yy) > 1e-8) {
892 fprintf(stderr, "spline test failed n = %d x = %g y = %g yy = %g\n", n, x, y, yy);
898 s_pme_spline_test(arena);
901 xyz = arena->ewald_grid_x * arena->ewald_grid_y * arena->ewald_grid_z;
902 x_y_z = arena->ewald_grid_x + arena->ewald_grid_y + arena->ewald_grid_z;
904 if (arena->pme != NULL)
908 if (arena->pme == NULL) {
909 arena->pme = (MDPME *)calloc(sizeof(MDPME), 1);
910 if (arena->pme == NULL)
914 if (pme->grid_x != arena->ewald_grid_x || pme->grid_y != arena->ewald_grid_y || pme->grid_z != arena->ewald_grid_z || pme->natoms != arena->mol->natoms) {
915 /* Need to rebuild internal table */
916 if (pme->grid_x * pme->grid_y * pme->grid_z < xyz) {
917 if (pme->qarray != NULL)
918 fftw_free(pme->qarray);
919 pme->qarray = fftw_alloc_complex(xyz);
920 if (pme->qfarray != NULL)
921 fftw_free(pme->qfarray);
922 pme->qfarray = fftw_alloc_complex(xyz);
923 if (pme->qqarray != NULL)
924 fftw_free(pme->qqarray);
925 pme->qqarray = fftw_alloc_complex(xyz);
926 pme->bcarray = (double *)realloc(pme->bcarray, sizeof(double) * xyz);
927 pme->carray = (double *)realloc(pme->carray, sizeof(double) * xyz);
929 if (pme->b0array != NULL)
930 fftw_free(pme->b0array);
931 pme->b0array = fftw_alloc_complex(x_y_z);
932 pme->marray = (double *)realloc(pme->marray, sizeof(double) * x_y_z * 2 * arena->mol->natoms);
933 pme->barray = (double *)realloc(pme->barray, sizeof(double) * x_y_z);
934 pme->grid_x = arena->ewald_grid_x;
935 pme->grid_y = arena->ewald_grid_y;
936 pme->grid_z = arena->ewald_grid_z;
937 pme->natoms = arena->mol->natoms;
938 if (xyz != 0 && x_y_z != 0) {
939 if (pme->plan1 != NULL)
940 fftw_destroy_plan(pme->plan1);
941 if (pme->plan2 != NULL)
942 fftw_destroy_plan(pme->plan2);
943 pme->plan1 = fftw_plan_dft_3d(pme->grid_x, pme->grid_y, pme->grid_z, pme->qarray, pme->qfarray, FFTW_BACKWARD, FFTW_ESTIMATE);
944 pme->plan2 = fftw_plan_dft_3d(pme->grid_x, pme->grid_y, pme->grid_z, pme->qfarray, pme->qqarray, FFTW_FORWARD, FFTW_ESTIMATE);
946 pme->order = arena->ewald_order;
947 /* Should be even numbers in [4..MAX_DIM_SPLINE] */
950 if (pme->order > MAX_DIM_SPLINE)
951 pme->order = MAX_DIM_SPLINE;
952 pme->order -= pme->order % 2;
953 /* Initialize B array */
954 for (i = 0; i < 3; i++) {
957 case 0: grid_i = pme->grid_x; idx_ofs = 0; break;
958 case 1: grid_i = pme->grid_y; idx_ofs = pme->grid_x; break;
959 case 2: grid_i = pme->grid_z; idx_ofs = pme->grid_x + pme->grid_y; break;
961 for (j = 0; j < grid_i; j++) {
968 t = 2 * PI * (pme->order - 1) * j / grid_i;
972 for (k = 0; k < pme->order - 1; k++) {
974 t = 2 * PI * j * k / grid_i;
975 s = s_calc_spline(pme->order, k + 1);
980 t = 1.0 / (b2[0] * b2[0] + b2[1] * b2[1]);
983 s_complex_mul(b1, b1, b2);
985 pme->b0array[idx_ofs + j][0] = b1[0];
986 pme->b0array[idx_ofs + j][1] = b1[1];
987 pme->barray[idx_ofs + j] = b1[0] * b1[0] + b1[1] * b1[1];
992 /* Calculate self-correction term */
997 for (i = 0, ap = arena->mol->atoms; i < arena->mol->natoms; i++, ap = ATOM_NEXT(ap)) {
998 en += ap->charge * ap->charge;
1000 arena->pme->self_correction = -(COULOMBIC/arena->dielectric) * arena->ewald_beta * PI2R * en;