2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2008, The GROMACS development team,
6 * check out http://www.gromacs.org for more information.
7 * Copyright (c) 2012,2013, by the GROMACS development team, led by
8 * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9 * others, as listed in the AUTHORS file in the top-level source
10 * directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
47 #include "checkpoint.h"
49 #include "gmx_random.h"
53 #include "mtop_util.h"
57 /* We use the same defines as in mvdata.c here */
58 #define block_bc(cr, d) gmx_bcast( sizeof(d), &(d),(cr))
59 #define nblock_bc(cr,nr,d) gmx_bcast((nr)*sizeof((d)[0]), (d),(cr))
60 #define snew_bc(cr,d,nr) { if (!MASTER(cr)) snew((d),(nr)); }
61 /* #define TAKETIME */
64 ddnoSEL, ddnoINTERLEAVE, ddnoPP_PME, ddnoCARTESIAN, ddnoNR
67 /* Enum for situations that can occur during log file parsing */
73 eParselogResetProblem,
80 int nPMEnodes; /* number of PME only nodes used in this test */
81 int nx, ny, nz; /* DD grid */
82 int guessPME; /* if nPMEnodes == -1, this is the guessed number of PME nodes */
83 float *Gcycles; /* This can contain more than one value if doing multiple tests */
87 float *PME_f_load; /* PME mesh/force load average*/
88 float PME_f_load_Av; /* Average average ;) ... */
89 char *mdrun_cmd_line; /* Mdrun command line used for this test */
95 gmx_large_int_t orig_sim_steps; /* Number of steps to be done in the real simulation */
96 int n_entries; /* Number of entries in arrays */
97 real volume; /* The volume of the box */
98 matrix recipbox; /* The reciprocal box */
99 int natoms; /* The number of atoms in the MD system */
100 real *fac; /* The scaling factor */
101 real *rcoulomb; /* The coulomb radii [0...nr_inputfiles] */
102 real *rvdw; /* The vdW radii */
103 int *nkx, *nky, *nkz; /* Number of k vectors in each spatial dimension */
104 real *fourier_sp; /* Fourierspacing */
105 real *ewald_rtol; /* Real space tolerance for Ewald, determines */
106 /* the real/reciprocal space relative weight */
107 real *ewald_beta; /* Splitting parameter [1/nm] */
108 real fracself; /* fraction of particles for SI error */
109 real q2all; /* sum ( q ^2 ) */
110 real q2allnr; /* nr of charges */
111 int *pme_order; /* Interpolation order for PME (bsplines) */
112 char **fn_out; /* Name of the output tpr file */
113 real *e_dir; /* Direct space part of PME error with these settings */
114 real *e_rec; /* Reciprocal space part of PME error */
115 gmx_bool bTUNE; /* flag for tuning */
119 /* Returns TRUE when atom is charged */
120 static gmx_bool is_charge(real charge)
122 if (charge*charge > GMX_REAL_EPS)
129 /* calculate charge density */
130 static void calc_q2all(
131 gmx_mtop_t *mtop, /* molecular topology */
132 real *q2all, real *q2allnr)
134 int imol,iatom; /* indices for loops */
135 real q2_all=0; /* Sum of squared charges */
136 int nrq_mol; /* Number of charges in a single molecule */
137 int nrq_all; /* Total number of charges in the MD system */
138 real nrq_all_r; /* No of charges in real format */
140 gmx_moltype_t *molecule;
141 gmx_molblock_t *molblock;
144 fprintf(stderr, "\nCharge density:\n");
146 q2_all = 0.0; /* total q squared */
147 nrq_all = 0; /* total number of charges in the system */
148 for (imol=0; imol<mtop->nmolblock; imol++) /* Loop over molecule types */
150 q2_mol=0.0; /* q squared value of this molecule */
151 nrq_mol=0; /* number of charges this molecule carries */
152 molecule = &(mtop->moltype[imol]);
153 molblock = &(mtop->molblock[imol]);
154 for (iatom=0; iatom<molblock->natoms_mol; iatom++) /* Loop over atoms in this molecule */
156 qi = molecule->atoms.atom[iatom].q; /* Charge of this atom */
157 /* Is this charge worth to be considered? */
164 /* Multiply with the number of molecules present of this type and add */
165 q2_all += q2_mol*molblock->nmol;
166 nrq_all += nrq_mol*molblock->nmol;
168 fprintf(stderr, "Molecule %2d (%5d atoms) q2_mol=%10.3e nr.mol.charges=%5d (%6dx) q2_all=%10.3e tot.charges=%d\n",
169 imol,molblock->natoms_mol,q2_mol,nrq_mol,molblock->nmol,q2_all,nrq_all);
180 /* Estimate the direct space part error of the SPME Ewald sum */
181 static real estimate_direct(
185 real e_dir=0; /* Error estimate */
186 real beta=0; /* Splitting parameter (1/nm) */
187 real r_coulomb=0; /* Cut-off in direct space */
190 beta = info->ewald_beta[0];
191 r_coulomb = info->rcoulomb[0];
193 e_dir = 2.0 * info->q2all * gmx_invsqrt( info->q2allnr * r_coulomb * info->volume );
194 e_dir *= exp (-beta*beta*r_coulomb*r_coulomb);
196 return ONE_4PI_EPS0*e_dir;
201 /* the following 4 functions determine polynomials required for the reciprocal error estimate */
203 static inline real eps_poly1(
204 real m, /* grid coordinate in certain direction */
205 real K, /* grid size in corresponding direction */
206 real n) /* spline interpolation order of the SPME */
209 real nom=0; /* nominator */
210 real denom=0; /* denominator */
216 for(i=-SUMORDER ; i<0 ; i++)
220 nom+=pow( tmp , -n );
223 for(i=SUMORDER ; i>0 ; i--)
227 nom+=pow( tmp , -n );
232 denom=pow( tmp , -n )+nom;
238 static inline real eps_poly2(
239 real m, /* grid coordinate in certain direction */
240 real K, /* grid size in corresponding direction */
241 real n) /* spline interpolation order of the SPME */
244 real nom=0; /* nominator */
245 real denom=0; /* denominator */
251 for(i=-SUMORDER ; i<0 ; i++)
255 nom+=pow( tmp , -2.0*n );
258 for(i=SUMORDER ; i>0 ; i--)
262 nom+=pow( tmp , -2.0*n );
265 for(i=-SUMORDER ; i<SUMORDER+1 ; i++)
269 denom+=pow( tmp , -n );
271 tmp=eps_poly1(m,K,n);
272 return nom / denom / denom + tmp*tmp ;
276 static inline real eps_poly3(
277 real m, /* grid coordinate in certain direction */
278 real K, /* grid size in corresponding direction */
279 real n) /* spline interpolation order of the SPME */
282 real nom=0; /* nominator */
283 real denom=0; /* denominator */
289 for(i=-SUMORDER ; i<0 ; i++)
293 nom+= i * pow( tmp , -2.0*n );
296 for(i=SUMORDER ; i>0 ; i--)
300 nom+= i * pow( tmp , -2.0*n );
303 for(i=-SUMORDER ; i<SUMORDER+1 ; i++)
307 denom+=pow( tmp , -n );
310 return 2.0 * M_PI * nom / denom / denom;
314 static inline real eps_poly4(
315 real m, /* grid coordinate in certain direction */
316 real K, /* grid size in corresponding direction */
317 real n) /* spline interpolation order of the SPME */
320 real nom=0; /* nominator */
321 real denom=0; /* denominator */
327 for(i=-SUMORDER ; i<0 ; i++)
331 nom+= i * i * pow( tmp , -2.0*n );
334 for(i=SUMORDER ; i>0 ; i--)
338 nom+= i * i * pow( tmp , -2.0*n );
341 for(i=-SUMORDER ; i<SUMORDER+1 ; i++)
345 denom+=pow( tmp , -n );
348 return 4.0 * M_PI * M_PI * nom / denom / denom;
352 static inline real eps_self(
353 real m, /* grid coordinate in certain direction */
354 real K, /* grid size in corresponding direction */
355 rvec rboxv, /* reciprocal box vector */
356 real n, /* spline interpolation order of the SPME */
357 rvec x) /* coordinate of charge */
360 real tmp=0; /* temporary variables for computations */
361 real tmp1=0; /* temporary variables for computations */
362 real tmp2=0; /* temporary variables for computations */
363 real rcoord=0; /* coordinate in certain reciprocal space direction */
364 real nom=0; /* nominator */
365 real denom=0; /* denominator */
371 rcoord=iprod(rboxv,x);
374 for(i=-SUMORDER;i<0;i++)
376 tmp=-sin(2.0 * M_PI * i * K * rcoord);
377 tmp1=2.0 * M_PI * m / K + 2.0 * M_PI * i;
378 tmp2=pow(tmp1,-1.0*n);
383 for(i=SUMORDER;i>0;i--)
385 tmp=-sin(2.0 * M_PI * i * K * rcoord);
386 tmp1=2.0 * M_PI * m / K + 2.0 * M_PI * i;
387 tmp2=pow(tmp1,-1.0*n);
393 tmp=2.0 * M_PI * m / K;
394 tmp1=pow(tmp,-1.0*n);
397 return 2.0 * M_PI * nom / denom * K ;
403 /* The following routine is just a copy from pme.c */
405 static void calc_recipbox(matrix box,matrix recipbox)
407 /* Save some time by assuming upper right part is zero */
409 real tmp=1.0/(box[XX][XX]*box[YY][YY]*box[ZZ][ZZ]);
411 recipbox[XX][XX]=box[YY][YY]*box[ZZ][ZZ]*tmp;
414 recipbox[YY][XX]=-box[YY][XX]*box[ZZ][ZZ]*tmp;
415 recipbox[YY][YY]=box[XX][XX]*box[ZZ][ZZ]*tmp;
417 recipbox[ZZ][XX]=(box[YY][XX]*box[ZZ][YY]-box[YY][YY]*box[ZZ][XX])*tmp;
418 recipbox[ZZ][YY]=-box[ZZ][YY]*box[XX][XX]*tmp;
419 recipbox[ZZ][ZZ]=box[XX][XX]*box[YY][YY]*tmp;
423 /* Estimate the reciprocal space part error of the SPME Ewald sum. */
424 static real estimate_reciprocal(
426 rvec x[], /* array of particles */
427 real q[], /* array of charges */
428 int nr, /* number of charges = size of the charge array */
431 unsigned int seed, /* The seed for the random number generator */
432 int *nsamples, /* Return the number of samples used if Monte Carlo
433 * algorithm is used for self energy error estimate */
436 real e_rec=0; /* reciprocal error estimate */
437 real e_rec1=0; /* Error estimate term 1*/
438 real e_rec2=0; /* Error estimate term 2*/
439 real e_rec3=0; /* Error estimate term 3 */
440 real e_rec3x=0; /* part of Error estimate term 3 in x */
441 real e_rec3y=0; /* part of Error estimate term 3 in y */
442 real e_rec3z=0; /* part of Error estimate term 3 in z */
444 int nx,ny,nz; /* grid coordinates */
445 real q2_all=0; /* sum of squared charges */
446 rvec gridpx; /* reciprocal grid point in x direction*/
447 rvec gridpxy; /* reciprocal grid point in x and y direction*/
448 rvec gridp; /* complete reciprocal grid point in 3 directions*/
449 rvec tmpvec; /* template to create points from basis vectors */
450 rvec tmpvec2; /* template to create points from basis vectors */
451 real coeff=0; /* variable to compute coefficients of the error estimate */
452 real coeff2=0; /* variable to compute coefficients of the error estimate */
453 real tmp=0; /* variables to compute different factors from vectors */
458 /* Random number generator */
462 /* Index variables for parallel work distribution */
463 int startglobal,stopglobal;
464 int startlocal, stoplocal;
473 rng=gmx_rng_init(seed);
486 /* Calculate indices for work distribution */
487 startglobal=-info->nkx[0]/2;
488 stopglobal = info->nkx[0]/2;
489 xtot = stopglobal*2+1;
492 x_per_core = ceil((real)xtot / (real)cr->nnodes);
493 startlocal = startglobal + x_per_core*cr->nodeid;
494 stoplocal = startlocal + x_per_core -1;
495 if (stoplocal > stopglobal)
496 stoplocal = stopglobal;
500 startlocal = startglobal;
501 stoplocal = stopglobal;
506 MPI_Barrier(MPI_COMM_WORLD);
519 fprintf(stderr, "Calculating reciprocal error part 1 ...");
523 for(nx=startlocal; nx<=stoplocal; nx++)
525 svmul(nx,info->recipbox[XX],gridpx);
526 for(ny=-info->nky[0]/2; ny<info->nky[0]/2+1; ny++)
528 svmul(ny,info->recipbox[YY],tmpvec);
529 rvec_add(gridpx,tmpvec,gridpxy);
530 for(nz=-info->nkz[0]/2; nz<info->nkz[0]/2+1; nz++)
532 if ( 0 == nx && 0 == ny && 0 == nz )
534 svmul(nz,info->recipbox[ZZ],tmpvec);
535 rvec_add(gridpxy,tmpvec,gridp);
537 coeff=exp(-1.0 * M_PI * M_PI * tmp / info->ewald_beta[0] / info->ewald_beta[0] ) ;
538 coeff/= 2.0 * M_PI * info->volume * tmp;
542 tmp=eps_poly2(nx,info->nkx[0],info->pme_order[0]);
543 tmp+=eps_poly2(ny,info->nkx[0],info->pme_order[0]);
544 tmp+=eps_poly2(nz,info->nkx[0],info->pme_order[0]);
546 tmp1=eps_poly1(nx,info->nkx[0],info->pme_order[0]);
547 tmp2=eps_poly1(ny,info->nky[0],info->pme_order[0]);
549 tmp+=2.0 * tmp1 * tmp2;
551 tmp1=eps_poly1(nz,info->nkz[0],info->pme_order[0]);
552 tmp2=eps_poly1(ny,info->nky[0],info->pme_order[0]);
554 tmp+=2.0 * tmp1 * tmp2;
556 tmp1=eps_poly1(nz,info->nkz[0],info->pme_order[0]);
557 tmp2=eps_poly1(nx,info->nkx[0],info->pme_order[0]);
559 tmp+=2.0 * tmp1 * tmp2;
561 tmp1=eps_poly1(nx,info->nkx[0],info->pme_order[0]);
562 tmp1+=eps_poly1(ny,info->nky[0],info->pme_order[0]);
563 tmp1+=eps_poly1(nz,info->nkz[0],info->pme_order[0]);
567 e_rec1+= 32.0 * M_PI * M_PI * coeff * coeff * coeff2 * tmp * q2_all * q2_all / nr ;
569 tmp1=eps_poly3(nx,info->nkx[0],info->pme_order[0]);
571 tmp2=iprod(gridp,info->recipbox[XX]);
575 tmp1=eps_poly3(ny,info->nky[0],info->pme_order[0]);
577 tmp2=iprod(gridp,info->recipbox[YY]);
581 tmp1=eps_poly3(nz,info->nkz[0],info->pme_order[0]);
583 tmp2=iprod(gridp,info->recipbox[ZZ]);
589 tmp1=eps_poly4(nx,info->nkx[0],info->pme_order[0]);
590 tmp1*=norm2(info->recipbox[XX]);
591 tmp1*=info->nkx[0] * info->nkx[0];
595 tmp1=eps_poly4(ny,info->nky[0],info->pme_order[0]);
596 tmp1*=norm2(info->recipbox[YY]);
597 tmp1*=info->nky[0] * info->nky[0];
601 tmp1=eps_poly4(nz,info->nkz[0],info->pme_order[0]);
602 tmp1*=norm2(info->recipbox[ZZ]);
603 tmp1*=info->nkz[0] * info->nkz[0];
607 e_rec2+= 4.0 * coeff * coeff * tmp * q2_all * q2_all / nr ;
612 fprintf(stderr, "\rCalculating reciprocal error part 1 ... %3.0f%%", 100.0*(nx-startlocal+1)/(x_per_core));
617 fprintf(stderr, "\n");
619 /* Use just a fraction of all charges to estimate the self energy error term? */
620 bFraction = (info->fracself > 0.0) && (info->fracself < 1.0);
624 /* Here xtot is the number of samples taken for the Monte Carlo calculation
625 * of the average of term IV of equation 35 in Wang2010. Round up to a
626 * number of samples that is divisible by the number of nodes */
627 x_per_core = ceil(info->fracself * nr / (real)cr->nnodes);
628 xtot = x_per_core * cr->nnodes;
632 /* In this case we use all nr particle positions */
634 x_per_core = ceil( (real)xtot / (real)cr->nnodes );
637 startlocal = x_per_core * cr->nodeid;
638 stoplocal = min(startlocal + x_per_core, xtot); /* min needed if xtot == nr */
642 /* Make shure we get identical results in serial and parallel. Therefore,
643 * take the sample indices from a single, global random number array that
644 * is constructed on the master node and that only depends on the seed */
648 for (i=0; i<xtot; i++)
650 numbers[i] = floor(gmx_rng_uniform_real(rng) * nr );
653 /* Broadcast the random number array to the other nodes */
656 nblock_bc(cr,xtot,numbers);
659 if (bVerbose && MASTER(cr))
661 fprintf(stdout, "Using %d sample%s to approximate the self interaction error term",
662 xtot, xtot==1?"":"s");
664 fprintf(stdout, " (%d sample%s per node)", x_per_core, x_per_core==1?"":"s");
665 fprintf(stdout, ".\n");
669 /* Return the number of positions used for the Monte Carlo algorithm */
672 for(i=startlocal;i<stoplocal;i++)
680 /* Randomly pick a charge */
685 /* Use all charges */
689 /* for(nx=startlocal; nx<=stoplocal; nx++)*/
690 for(nx=-info->nkx[0]/2; nx<info->nkx[0]/2+1; nx++)
692 svmul(nx,info->recipbox[XX],gridpx);
693 for(ny=-info->nky[0]/2; ny<info->nky[0]/2+1; ny++)
695 svmul(ny,info->recipbox[YY],tmpvec);
696 rvec_add(gridpx,tmpvec,gridpxy);
697 for(nz=-info->nkz[0]/2; nz<info->nkz[0]/2+1; nz++)
700 if ( 0 == nx && 0 == ny && 0 == nz)
703 svmul(nz,info->recipbox[ZZ],tmpvec);
704 rvec_add(gridpxy,tmpvec,gridp);
706 coeff=exp(-1.0 * M_PI * M_PI * tmp / info->ewald_beta[0] / info->ewald_beta[0] );
708 e_rec3x+=coeff*eps_self(nx,info->nkx[0],info->recipbox[XX],info->pme_order[0],x[ci]);
709 e_rec3y+=coeff*eps_self(ny,info->nky[0],info->recipbox[YY],info->pme_order[0],x[ci]);
710 e_rec3z+=coeff*eps_self(nz,info->nkz[0],info->recipbox[ZZ],info->pme_order[0],x[ci]);
718 svmul(e_rec3x,info->recipbox[XX],tmpvec);
719 rvec_inc(tmpvec2,tmpvec);
720 svmul(e_rec3y,info->recipbox[YY],tmpvec);
721 rvec_inc(tmpvec2,tmpvec);
722 svmul(e_rec3z,info->recipbox[ZZ],tmpvec);
723 rvec_inc(tmpvec2,tmpvec);
725 e_rec3 += q[ci]*q[ci]*q[ci]*q[ci]*norm2(tmpvec2) / ( xtot * M_PI * info->volume * M_PI * info->volume);
727 fprintf(stderr, "\rCalculating reciprocal error part 2 ... %3.0f%%",
728 100.0*(i+1)/stoplocal);
734 fprintf(stderr, "\n");
740 t1= MPI_Wtime() - t0;
741 fprintf(fp_out, "Recip. err. est. took : %lf s\n", t1);
749 fprintf(stderr, "Node %3d: nx=[%3d...%3d] e_rec3=%e\n",
750 cr->nodeid, startlocal, stoplocal, e_rec3);
756 gmx_sum(1,&e_rec1,cr);
757 gmx_sum(1,&e_rec2,cr);
758 gmx_sum(1,&e_rec3,cr);
761 /* e_rec1*=8.0 * q2_all / info->volume / info->volume / nr ;
762 e_rec2*= q2_all / M_PI / M_PI / info->volume / info->volume / nr ;
763 e_rec3/= M_PI * M_PI * info->volume * info->volume * nr ;
765 e_rec=sqrt(e_rec1+e_rec2+e_rec3);
768 return ONE_4PI_EPS0 * e_rec;
772 /* Allocate memory for the inputinfo struct: */
773 static void create_info(t_inputinfo *info)
775 snew(info->fac , info->n_entries);
776 snew(info->rcoulomb , info->n_entries);
777 snew(info->rvdw , info->n_entries);
778 snew(info->nkx , info->n_entries);
779 snew(info->nky , info->n_entries);
780 snew(info->nkz , info->n_entries);
781 snew(info->fourier_sp, info->n_entries);
782 snew(info->ewald_rtol, info->n_entries);
783 snew(info->ewald_beta, info->n_entries);
784 snew(info->pme_order , info->n_entries);
785 snew(info->fn_out , info->n_entries);
786 snew(info->e_dir , info->n_entries);
787 snew(info->e_rec , info->n_entries);
791 /* Allocate and fill an array with coordinates and charges,
792 * returns the number of charges found
794 static int prepare_x_q(real *q[], rvec *x[], gmx_mtop_t *mtop, rvec x_orig[], t_commrec *cr)
797 int nq; /* number of charged particles */
798 gmx_mtop_atomloop_all_t aloop;
804 snew(*q, mtop->natoms);
805 snew(*x, mtop->natoms);
808 aloop = gmx_mtop_atomloop_all_init(mtop);
810 while (gmx_mtop_atomloop_all_next(aloop,&i,&atom))
812 if (is_charge(atom->q))
815 (*x)[nq][XX] = x_orig[i][XX];
816 (*x)[nq][YY] = x_orig[i][YY];
817 (*x)[nq][ZZ] = x_orig[i][ZZ];
821 /* Give back some unneeded memory */
825 /* Broadcast x and q in the parallel case */
828 /* Transfer the number of charges */
841 /* Read in the tpr file and save information we need later in info */
842 static void read_tpr_file(const char *fn_sim_tpr, t_inputinfo *info, t_state *state, gmx_mtop_t *mtop, t_inputrec *ir, real user_beta, real fracself)
844 read_tpx_state(fn_sim_tpr,ir,state,NULL,mtop);
846 /* The values of the original tpr input file are save in the first
847 * place [0] of the arrays */
848 info->orig_sim_steps = ir->nsteps;
849 info->pme_order[0] = ir->pme_order;
850 info->rcoulomb[0] = ir->rcoulomb;
851 info->rvdw[0] = ir->rvdw;
852 info->nkx[0] = ir->nkx;
853 info->nky[0] = ir->nky;
854 info->nkz[0] = ir->nkz;
855 info->ewald_rtol[0] = ir->ewald_rtol;
856 info->fracself = fracself;
858 info->ewald_beta[0] = user_beta;
860 info->ewald_beta[0] = calc_ewaldcoeff(info->rcoulomb[0],info->ewald_rtol[0]);
862 /* Check if PME was chosen */
863 if (EEL_PME(ir->coulombtype) == FALSE)
864 gmx_fatal(FARGS, "Can only do optimizations for simulations with PME");
866 /* Check if rcoulomb == rlist, which is necessary for PME */
867 if (!(ir->rcoulomb == ir->rlist))
868 gmx_fatal(FARGS, "PME requires rcoulomb (%f) to be equal to rlist (%f).", ir->rcoulomb, ir->rlist);
872 /* Transfer what we need for parallelizing the reciprocal error estimate */
873 static void bcast_info(t_inputinfo *info, t_commrec *cr)
875 nblock_bc(cr, info->n_entries, info->nkx);
876 nblock_bc(cr, info->n_entries, info->nky);
877 nblock_bc(cr, info->n_entries, info->nkz);
878 nblock_bc(cr, info->n_entries, info->ewald_beta);
879 nblock_bc(cr, info->n_entries, info->pme_order);
880 nblock_bc(cr, info->n_entries, info->e_dir);
881 nblock_bc(cr, info->n_entries, info->e_rec);
882 block_bc(cr, info->volume);
883 block_bc(cr, info->recipbox);
884 block_bc(cr, info->natoms);
885 block_bc(cr, info->fracself);
886 block_bc(cr, info->bTUNE);
887 block_bc(cr, info->q2all);
888 block_bc(cr, info->q2allnr);
892 /* Estimate the error of the SPME Ewald sum. This estimate is based upon
893 * a) a homogeneous distribution of the charges
894 * b) a total charge of zero.
896 static void estimate_PME_error(t_inputinfo *info, t_state *state,
897 gmx_mtop_t *mtop, FILE *fp_out, gmx_bool bVerbose, unsigned int seed,
900 rvec *x=NULL; /* The coordinates */
901 real *q=NULL; /* The charges */
902 real edir=0.0; /* real space error */
903 real erec=0.0; /* reciprocal space error */
904 real derr=0.0; /* difference of real and reciprocal space error */
905 real derr0=0.0; /* difference of real and reciprocal space error */
906 real beta=0.0; /* splitting parameter beta */
907 real beta0=0.0; /* splitting parameter beta */
908 int ncharges; /* The number of atoms with charges */
909 int nsamples; /* The number of samples used for the calculation of the
910 * self-energy error term */
914 fprintf(fp_out, "\n--- PME ERROR ESTIMATE ---\n");
916 /* Prepare an x and q array with only the charged atoms */
917 ncharges = prepare_x_q(&q, &x, mtop, state->x, cr);
920 calc_q2all(mtop, &(info->q2all), &(info->q2allnr));
921 info->ewald_rtol[0]=gmx_erfc(info->rcoulomb[0]*info->ewald_beta[0]);
922 /* Write some info to log file */
923 fprintf(fp_out, "Box volume : %g nm^3\n", info->volume);
924 fprintf(fp_out, "Number of charged atoms : %d (total atoms %d)\n",ncharges, info->natoms);
925 fprintf(fp_out, "Coulomb radius : %g nm\n", info->rcoulomb[0]);
926 fprintf(fp_out, "Ewald_rtol : %g\n", info->ewald_rtol[0]);
927 fprintf(fp_out, "Ewald parameter beta : %g\n", info->ewald_beta[0]);
928 fprintf(fp_out, "Interpolation order : %d\n", info->pme_order[0]);
929 fprintf(fp_out, "Fourier grid (nx,ny,nz) : %d x %d x %d\n",
930 info->nkx[0],info->nky[0],info->nkz[0]);
936 bcast_info(info, cr);
939 /* Calculate direct space error */
940 info->e_dir[0] = estimate_direct(info);
942 /* Calculate reciprocal space error */
943 info->e_rec[0] = estimate_reciprocal(info, x, q, ncharges, fp_out, bVerbose,
944 seed, &nsamples, cr);
947 bcast_info(info, cr);
951 fprintf(fp_out, "Direct space error est. : %10.3e kJ/(mol*nm)\n", info->e_dir[0]);
952 fprintf(fp_out, "Reciprocal sp. err. est.: %10.3e kJ/(mol*nm)\n", info->e_rec[0]);
953 fprintf(fp_out, "Self-energy error term was estimated using %d samples\n", nsamples);
955 fprintf(stderr, "Direct space error est. : %10.3e kJ/(mol*nm)\n", info->e_dir[0]);
956 fprintf(stderr, "Reciprocal sp. err. est.: %10.3e kJ/(mol*nm)\n", info->e_rec[0]);
964 fprintf(stderr,"Starting tuning ...\n");
968 beta0=info->ewald_beta[0];
970 info->ewald_beta[0]+=0.1;
972 info->ewald_beta[0]-=0.1;
973 info->e_dir[0] = estimate_direct(info);
974 info->e_rec[0] = estimate_reciprocal(info, x, q, ncharges, fp_out, bVerbose,
975 seed, &nsamples, cr);
978 bcast_info(info, cr);
984 while ( fabs(derr/min(erec,edir)) > 1e-4)
987 beta=info->ewald_beta[0];
988 beta-=derr*(info->ewald_beta[0]-beta0)/(derr-derr0);
989 beta0=info->ewald_beta[0];
990 info->ewald_beta[0]=beta;
993 info->e_dir[0] = estimate_direct(info);
994 info->e_rec[0] = estimate_reciprocal(info, x, q, ncharges, fp_out, bVerbose,
995 seed, &nsamples, cr);
998 bcast_info(info, cr);
1000 edir=info->e_dir[0];
1001 erec=info->e_rec[0];
1007 fprintf(stderr,"difference between real and rec. space error (step %d): %g\n",i,fabs(derr));
1008 fprintf(stderr,"old beta: %f\n",beta0);
1009 fprintf(stderr,"new beta: %f\n",beta);
1013 info->ewald_rtol[0]=gmx_erfc(info->rcoulomb[0]*info->ewald_beta[0]);
1017 /* Write some info to log file */
1019 fprintf(fp_out, "========= After tuning ========\n");
1020 fprintf(fp_out, "Direct space error est. : %10.3e kJ/(mol*nm)\n", info->e_dir[0]);
1021 fprintf(fp_out, "Reciprocal sp. err. est.: %10.3e kJ/(mol*nm)\n", info->e_rec[0]);
1022 fprintf(stderr, "Direct space error est. : %10.3e kJ/(mol*nm)\n", info->e_dir[0]);
1023 fprintf(stderr, "Reciprocal sp. err. est.: %10.3e kJ/(mol*nm)\n", info->e_rec[0]);
1024 fprintf(fp_out, "Ewald_rtol : %g\n", info->ewald_rtol[0]);
1025 fprintf(fp_out, "Ewald parameter beta : %g\n", info->ewald_beta[0]);
1035 int gmx_pme_error(int argc,char *argv[])
1037 const char *desc[] = {
1038 "[TT]g_pme_error[tt] estimates the error of the electrostatic forces",
1039 "if using the sPME algorithm. The flag [TT]-tune[tt] will determine",
1040 "the splitting parameter such that the error is equally",
1041 "distributed over the real and reciprocal space part.",
1042 "The part of the error that stems from self interaction of the particles "
1043 "is computationally demanding. However, a good a approximation is to",
1044 "just use a fraction of the particles for this term which can be",
1045 "indicated by the flag [TT]-self[tt].[PAR]",
1048 real fs=0.0; /* 0 indicates: not set by the user */
1049 real user_beta=-1.0;
1052 t_state state; /* The state from the tpr input file */
1053 gmx_mtop_t mtop; /* The topology from the tpr input file */
1054 t_inputrec *ir=NULL; /* The inputrec from the tpr file */
1057 unsigned long PCA_Flags;
1058 gmx_bool bTUNE=FALSE;
1059 gmx_bool bVerbose=FALSE;
1063 static t_filenm fnm[] = {
1064 { efTPX, "-s", NULL, ffREAD },
1065 { efOUT, "-o", "error", ffWRITE },
1066 { efTPX, "-so", "tuned", ffOPTWR }
1069 output_env_t oenv=NULL;
1072 { "-beta", FALSE, etREAL, {&user_beta},
1073 "If positive, overwrite ewald_beta from [TT].tpr[tt] file with this value" },
1074 { "-tune", FALSE, etBOOL, {&bTUNE},
1075 "Tune the splitting parameter such that the error is equally distributed between real and reciprocal space" },
1076 { "-self", FALSE, etREAL, {&fracself},
1077 "If between 0.0 and 1.0, determine self interaction error from just this fraction of the charged particles" },
1078 { "-seed", FALSE, etINT, {&seed},
1079 "Random number seed used for Monte Carlo algorithm when [TT]-self[tt] is set to a value between 0.0 and 1.0" },
1080 { "-v", FALSE, etBOOL, {&bVerbose},
1081 "Be loud and noisy" }
1085 #define NFILE asize(fnm)
1087 cr = init_par(&argc,&argv);
1090 MPI_Barrier(MPI_COMM_WORLD);
1094 CopyRight(stderr,argv[0]);
1096 PCA_Flags = PCA_NOEXIT_ON_ARGS;
1097 PCA_Flags |= (MASTER(cr) ? 0 : PCA_QUIET);
1099 parse_common_args(&argc,argv,PCA_Flags,
1100 NFILE,fnm,asize(pa),pa,asize(desc),desc,
1104 bTUNE = opt2bSet("-so",NFILE,fnm);
1108 /* Allocate memory for the inputinfo struct: */
1110 info.fourier_sp[0] = fs;
1112 /* Read in the tpr file and open logfile for reading */
1116 read_tpr_file(opt2fn("-s",NFILE,fnm), &info, &state, &mtop, ir, user_beta,fracself);
1118 fp=fopen(opt2fn("-o",NFILE,fnm),"w");
1121 /* Check consistency if the user provided fourierspacing */
1122 if (fs > 0 && MASTER(cr))
1124 /* Recalculate the grid dimensions using fourierspacing from user input */
1128 calc_grid(stdout,state.box,info.fourier_sp[0],&(info.nkx[0]),&(info.nky[0]),&(info.nkz[0]));
1129 if ( (ir->nkx != info.nkx[0]) || (ir->nky != info.nky[0]) || (ir->nkz != info.nkz[0]) )
1130 gmx_fatal(FARGS, "Wrong fourierspacing %f nm, input file grid = %d x %d x %d, computed grid = %d x %d x %d",
1131 fs,ir->nkx,ir->nky,ir->nkz,info.nkx[0],info.nky[0],info.nkz[0]);
1134 /* Estimate (S)PME force error */
1136 /* Determine the volume of the simulation box */
1139 info.volume = det(state.box);
1140 calc_recipbox(state.box,info.recipbox);
1141 info.natoms = mtop.natoms;
1146 bcast_info(&info, cr);
1148 /* Get an error estimate of the input tpr file and do some tuning if requested */
1149 estimate_PME_error(&info, &state, &mtop, fp, bVerbose, seed, cr);
1153 /* Write out optimized tpr file if requested */
1154 if ( opt2bSet("-so",NFILE,fnm) || bTUNE )
1156 ir->ewald_rtol=info.ewald_rtol[0];
1157 write_tpx_state(opt2fn("-so",NFILE,fnm),ir,&state,&mtop);
1159 please_cite(fp,"Wang2010");