66fb961f03a2562ae2626eb13894c9efd641c426
[alexxy/gromacs.git] / src / tools / gmx_pme_error.c
1 /*
2  *                This source code is part of
3  *
4  *                 G   R   O   M   A   C   S
5  * 
6  *          GROningen MAchine for Chemical Simulations
7  * 
8  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
9  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
10  * Copyright (c) 2001-2008, The GROMACS development team,
11  * check out http://www.gromacs.org for more information.
12  
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  * 
18  * If you want to redistribute modifications, please consider that
19  * scientific software is very special. Version control is crucial -
20  * bugs must be traceable. We will be happy to consider code for
21  * inclusion in the official distribution, but derived work must not
22  * be called official GROMACS. Details are found in the README & COPYING
23  * files - if they are missing, get the official version at www.gromacs.org.
24  * 
25  * To help us fund GROMACS development, we humbly ask that you cite
26  * the papers on the package - you can find them in the top README file.
27  * 
28  * For more info, check our website at http://www.gromacs.org
29  * 
30  * And Hey:
31  * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
32  */
33 #include "statutil.h"
34 #include "typedefs.h"
35 #include "smalloc.h"
36 #include "vec.h"
37 #include "copyrite.h"
38 #include "tpxio.h"
39 #include "string2.h"
40 #include "readinp.h"
41 #include "calcgrid.h"
42 #include "checkpoint.h"
43 #include "gmx_ana.h"
44 #include "gmx_random.h"
45 #include "physics.h"
46 #include "mdatoms.h"
47 #include "coulomb.h"
48 #include "mtop_util.h"
49 #include "network.h"
50 #include "main.h"
51
52 /* We use the same defines as in mvdata.c here */
53 #define  block_bc(cr,   d) gmx_bcast(     sizeof(d),     &(d),(cr))
54 #define nblock_bc(cr,nr,d) gmx_bcast((nr)*sizeof((d)[0]), (d),(cr))
55 #define   snew_bc(cr,d,nr) { if (!MASTER(cr)) snew((d),(nr)); }
56 /* #define TAKETIME */
57 /* #define DEBUG  */
58 enum {
59   ddnoSEL, ddnoINTERLEAVE, ddnoPP_PME, ddnoCARTESIAN, ddnoNR
60 };
61
62 /* Enum for situations that can occur during log file parsing */
63 enum {
64     eParselogOK,
65     eParselogNotFound,
66     eParselogNoPerfData,
67     eParselogTerm,
68     eParselogResetProblem,
69     eParselogNr
70 };
71
72
73 typedef struct
74 {
75     int  nPMEnodes;       /* number of PME only nodes used in this test */
76     int  nx, ny, nz;      /* DD grid */
77     int  guessPME;        /* if nPMEnodes == -1, this is the guessed number of PME nodes */
78     float *Gcycles;        /* This can contain more than one value if doing multiple tests */
79     float Gcycles_Av;
80     float *ns_per_day;
81     float ns_per_day_Av;
82     float *PME_f_load;     /* PME mesh/force load average*/
83     float PME_f_load_Av;   /* Average average ;) ... */
84     char *mdrun_cmd_line; /* Mdrun command line used for this test */
85 } t_perf;
86
87
88 typedef struct
89 {
90     gmx_large_int_t orig_sim_steps;  /* Number of steps to be done in the real simulation  */
91     int  n_entries;             /* Number of entries in arrays                        */
92     real volume;                /* The volume of the box                              */
93     matrix recipbox;            /* The reciprocal box                                 */
94     int  natoms;                /* The number of atoms in the MD system               */
95     real *fac;                  /* The scaling factor                                 */
96     real *rcoulomb;             /* The coulomb radii [0...nr_inputfiles]              */
97     real *rvdw;                 /* The vdW radii                                      */
98     int  *nkx, *nky, *nkz;      /* Number of k vectors in each spatial dimension      */
99     real *fourier_sp;           /* Fourierspacing                                     */
100     real *ewald_rtol;           /* Real space tolerance for Ewald, determines         */
101                                 /* the real/reciprocal space relative weight          */
102     real *ewald_beta;           /* Splitting parameter [1/nm]                         */
103     real fracself;              /* fraction of particles for SI error                 */
104     real q2all;                 /* sum ( q ^2 )                                       */
105     real q2allnr;               /* nr of charges                                      */
106     int  *pme_order;            /* Interpolation order for PME (bsplines)             */
107     char **fn_out;              /* Name of the output tpr file                        */
108     real *e_dir;                /* Direct space part of PME error with these settings */ 
109     real *e_rec;                /* Reciprocal space part of PME error                 */ 
110     gmx_bool bTUNE;                 /* flag for tuning */
111 } t_inputinfo;
112
113
114 /* Returns TRUE when atom is charged */
115 static gmx_bool is_charge(real charge)
116 {
117     if (charge*charge > GMX_REAL_EPS)
118         return TRUE;
119     else 
120         return FALSE;
121 }
122
123
124 /* calculate charge density */
125 static void calc_q2all(
126         gmx_mtop_t *mtop,   /* molecular topology */
127         real *q2all, real *q2allnr)
128 {
129     int imol,iatom;  /* indices for loops */
130     real q2_all=0;   /* Sum of squared charges */
131     int  nrq_mol;    /* Number of charges in a single molecule */
132     int  nrq_all;    /* Total number of charges in the MD system */
133     real nrq_all_r;  /* No of charges in real format */
134     real qi,q2_mol;
135     gmx_moltype_t *molecule;
136     gmx_molblock_t *molblock;
137     
138 #ifdef DEBUG
139         fprintf(stderr, "\nCharge density:\n");
140 #endif
141     q2_all = 0.0;  /* total q squared */
142     nrq_all = 0;   /* total number of charges in the system */
143     for (imol=0; imol<mtop->nmolblock; imol++) /* Loop over molecule types */
144     {
145         q2_mol=0.0; /* q squared value of this molecule */
146         nrq_mol=0;  /* number of charges this molecule carries */
147         molecule = &(mtop->moltype[imol]);
148         molblock = &(mtop->molblock[imol]);
149         for (iatom=0; iatom<molblock->natoms_mol; iatom++) /* Loop over atoms in this molecule */
150         {
151             qi = molecule->atoms.atom[iatom].q; /* Charge of this atom */
152             /* Is this charge worth to be considered? */
153             if (is_charge(qi))
154             {
155                 q2_mol += qi*qi;
156                 nrq_mol++;                
157             }
158         }
159         /* Multiply with the number of molecules present of this type and add */
160         q2_all  += q2_mol*molblock->nmol;
161         nrq_all += nrq_mol*molblock->nmol;
162 #ifdef DEBUG
163         fprintf(stderr, "Molecule %2d (%5d atoms) q2_mol=%10.3e nr.mol.charges=%5d (%6dx)  q2_all=%10.3e  tot.charges=%d\n", 
164                 imol,molblock->natoms_mol,q2_mol,nrq_mol,molblock->nmol,q2_all,nrq_all);
165 #endif
166     }
167     nrq_all_r = nrq_all;
168
169     *q2all=q2_all;
170     *q2allnr=nrq_all;
171
172 }
173
174
175 /* Estimate the direct space part error of the SPME Ewald sum */
176 static real estimate_direct(
177         t_inputinfo *info
178         )
179 {
180     real e_dir=0;    /* Error estimate */
181     real beta=0;     /* Splitting parameter (1/nm) */
182     real r_coulomb=0;  /* Cut-off in direct space */
183     
184
185     beta      = info->ewald_beta[0];
186     r_coulomb = info->rcoulomb[0];
187                      
188     e_dir  = 2.0 * info->q2all * gmx_invsqrt( info->q2allnr  *  r_coulomb * info->volume );
189     e_dir *= exp (-beta*beta*r_coulomb*r_coulomb);
190     
191     return ONE_4PI_EPS0*e_dir;
192 }
193
194 #define SUMORDER 6
195
196 /* the following 4 functions determine polynomials required for the reciprocal error estimate */
197
198 static inline real eps_poly1(
199         real m,          /* grid coordinate in certain direction */
200         real K,          /* grid size in corresponding direction */
201         real n)          /* spline interpolation order of the SPME */
202 {
203     int i;
204     real nom=0;  /* nominator */
205     real denom=0; /* denominator */
206     real tmp=0;
207
208     if ( m == 0.0 )
209         return 0.0 ;
210
211     for(i=-SUMORDER ; i<0 ; i++)
212     {
213         tmp=m / K + i;
214         tmp*=2.0*M_PI;
215         nom+=pow( tmp , -n );
216     }
217
218     for(i=SUMORDER ; i>0 ; i--)
219     {
220         tmp=m / K + i;
221         tmp*=2.0*M_PI;
222         nom+=pow( tmp , -n );
223     }
224     
225     tmp=m / K;
226     tmp*=2.0*M_PI;
227     denom=pow( tmp , -n )+nom;
228
229     return -nom/denom;
230
231 }
232
233 static inline real eps_poly2(
234         real m,          /* grid coordinate in certain direction */
235         real K,          /* grid size in corresponding direction */
236         real n)          /* spline interpolation order of the SPME */
237 {
238     int i;
239     real nom=0;  /* nominator */
240     real denom=0; /* denominator */
241     real tmp=0;
242     
243     if ( m == 0.0 )
244         return 0.0 ;
245     
246     for(i=-SUMORDER ; i<0 ; i++)
247     {
248         tmp=m / K + i;
249         tmp*=2.0*M_PI;
250         nom+=pow( tmp , -2.0*n );
251     }
252
253     for(i=SUMORDER ; i>0 ; i--)
254     {
255         tmp=m / K + i;
256         tmp*=2.0*M_PI;
257         nom+=pow( tmp , -2.0*n );
258     }
259     
260     for(i=-SUMORDER ; i<SUMORDER+1 ; i++)
261     {
262         tmp=m / K + i;
263         tmp*=2.0*M_PI;
264         denom+=pow( tmp , -n );
265     }
266     tmp=eps_poly1(m,K,n);
267     return nom / denom / denom + tmp*tmp ; 
268
269 }
270
271 static inline real eps_poly3(
272         real m,          /* grid coordinate in certain direction */
273         real K,          /* grid size in corresponding direction */
274         real n)          /* spline interpolation order of the SPME */
275 {
276     int i;
277     real nom=0;  /* nominator */
278     real denom=0; /* denominator */
279     real tmp=0;
280
281     if ( m == 0.0 )
282         return 0.0 ;
283
284     for(i=-SUMORDER ; i<0 ; i++)
285     {
286         tmp=m / K + i;
287         tmp*=2.0*M_PI;
288         nom+= i * pow( tmp , -2.0*n );
289     }
290
291     for(i=SUMORDER ; i>0 ; i--)
292     {
293         tmp=m / K + i;
294         tmp*=2.0*M_PI;
295         nom+= i * pow( tmp , -2.0*n );
296     }
297     
298     for(i=-SUMORDER ; i<SUMORDER+1 ; i++)
299     {
300         tmp=m / K + i;
301         tmp*=2.0*M_PI;
302         denom+=pow( tmp , -n );
303     }
304
305     return 2.0 * M_PI * nom / denom / denom;
306
307 }
308
309 static inline real eps_poly4(
310         real m,          /* grid coordinate in certain direction */
311         real K,          /* grid size in corresponding direction */
312         real n)          /* spline interpolation order of the SPME */
313 {
314     int i;
315     real nom=0;  /* nominator */
316     real denom=0; /* denominator */
317     real tmp=0;
318
319     if ( m == 0.0 )
320         return 0.0 ;
321
322     for(i=-SUMORDER ; i<0 ; i++)
323     {
324         tmp=m / K + i;
325         tmp*=2.0*M_PI;
326         nom+= i * i * pow( tmp , -2.0*n );
327     }
328
329     for(i=SUMORDER ; i>0 ; i--)
330     {
331         tmp=m / K + i;
332         tmp*=2.0*M_PI;
333         nom+= i * i * pow( tmp , -2.0*n );
334     }
335     
336     for(i=-SUMORDER ; i<SUMORDER+1 ; i++)
337     {
338         tmp=m / K + i;
339         tmp*=2.0*M_PI;
340         denom+=pow( tmp , -n );
341     }
342
343     return 4.0 * M_PI * M_PI * nom / denom / denom;
344
345 }
346
347 static inline real eps_self(
348         real m,        /* grid coordinate in certain direction */
349         real K,        /* grid size in corresponding direction */
350         rvec rboxv,   /* reciprocal box vector */
351         real n,        /* spline interpolation order of the SPME */
352         rvec x)       /* coordinate of charge */
353 {
354     int i; 
355     real tmp=0; /* temporary variables for computations */
356     real tmp1=0; /* temporary variables for computations */
357     real tmp2=0; /* temporary variables for computations */
358     real rcoord=0; /* coordinate in certain reciprocal space direction */
359     real nom=0; /* nominator */
360     real denom=0; /* denominator */
361     
362     
363     if ( m == 0.0 )
364         return 0.0 ;
365
366     rcoord=iprod(rboxv,x);
367     
368                      
369     for(i=-SUMORDER;i<0;i++)
370     {
371         tmp=-sin(2.0 * M_PI * i * K * rcoord);
372         tmp1=2.0 * M_PI * m / K + 2.0 * M_PI * i; 
373         tmp2=pow(tmp1,-1.0*n);
374         nom+=tmp * tmp2 * i;
375         denom+=tmp2;
376     }
377
378     for(i=SUMORDER;i>0;i--)
379     {
380         tmp=-sin(2.0 * M_PI * i * K * rcoord);
381         tmp1=2.0 * M_PI * m / K + 2.0 * M_PI * i; 
382         tmp2=pow(tmp1,-1.0*n);
383         nom+=tmp * tmp2 * i;
384         denom+=tmp2;
385     }
386
387    
388     tmp=2.0 * M_PI * m / K;
389     tmp1=pow(tmp,-1.0*n);
390     denom+=tmp1;
391
392    return 2.0 * M_PI * nom / denom * K  ;
393
394 }
395
396 #undef SUMORDER
397
398 /* The following routine is just a copy from pme.c */
399
400 static void calc_recipbox(matrix box,matrix recipbox)
401 {
402   /* Save some time by assuming upper right part is zero */
403
404   real tmp=1.0/(box[XX][XX]*box[YY][YY]*box[ZZ][ZZ]);
405
406   recipbox[XX][XX]=box[YY][YY]*box[ZZ][ZZ]*tmp;
407   recipbox[XX][YY]=0;
408   recipbox[XX][ZZ]=0;
409   recipbox[YY][XX]=-box[YY][XX]*box[ZZ][ZZ]*tmp;
410   recipbox[YY][YY]=box[XX][XX]*box[ZZ][ZZ]*tmp;
411   recipbox[YY][ZZ]=0;
412   recipbox[ZZ][XX]=(box[YY][XX]*box[ZZ][YY]-box[YY][YY]*box[ZZ][XX])*tmp;
413   recipbox[ZZ][YY]=-box[ZZ][YY]*box[XX][XX]*tmp;
414   recipbox[ZZ][ZZ]=box[XX][XX]*box[YY][YY]*tmp;
415 }
416
417
418 /* Estimate the reciprocal space part error of the SPME Ewald sum. */
419 static real estimate_reciprocal(
420         t_inputinfo *info, 
421         rvec x[],           /* array of particles */
422         real q[],           /* array of charges */
423         int nr,             /* number of charges = size of the charge array */
424         FILE *fp_out,
425         gmx_bool bVerbose,
426         unsigned int seed,  /* The seed for the random number generator */
427         int *nsamples,      /* Return the number of samples used if Monte Carlo
428                              * algorithm is used for self energy error estimate */
429         t_commrec *cr)
430 {
431     real e_rec=0;   /* reciprocal error estimate */
432     real e_rec1=0;  /* Error estimate term 1*/
433     real e_rec2=0;  /* Error estimate term 2*/
434     real e_rec3=0;  /* Error estimate term 3 */
435     real e_rec3x=0; /* part of Error estimate term 3 in x */
436     real e_rec3y=0; /* part of Error estimate term 3 in y */
437     real e_rec3z=0; /* part of Error estimate term 3 in z */
438     int i,ci;
439     int nx,ny,nz;   /* grid coordinates */
440     real q2_all=0;  /* sum of squared charges */
441     rvec gridpx;    /* reciprocal grid point in x direction*/
442     rvec gridpxy;   /* reciprocal grid point in x and y direction*/
443     rvec gridp;     /* complete reciprocal grid point in 3 directions*/
444     rvec tmpvec;    /* template to create points from basis vectors */
445     rvec tmpvec2;   /* template to create points from basis vectors */
446     real coeff=0;   /* variable to compute coefficients of the error estimate */
447     real coeff2=0;   /* variable to compute coefficients of the error estimate */
448     real tmp=0;     /* variables to compute different factors from vectors */
449     real tmp1=0;
450     real tmp2=0;
451     gmx_bool bFraction;
452     
453     /* Random number generator */
454     gmx_rng_t rng=NULL;
455     int *numbers=NULL;
456
457     /* Index variables for parallel work distribution */
458     int startglobal,stopglobal;
459     int startlocal, stoplocal;
460     int x_per_core;
461     int xtot;
462
463 #ifdef TAKETIME
464     double t0=0.0;
465     double t1=0.0;
466 #endif
467
468     rng=gmx_rng_init(seed);
469
470     clear_rvec(gridpx);
471     clear_rvec(gridpxy);
472     clear_rvec(gridp);
473     clear_rvec(tmpvec);
474     clear_rvec(tmpvec2);
475
476     for(i=0;i<nr;i++)
477     {
478         q2_all += q[i]*q[i];
479     }
480     
481     /* Calculate indices for work distribution */
482     startglobal=-info->nkx[0]/2;
483     stopglobal = info->nkx[0]/2;
484     xtot = stopglobal*2+1;
485     if (PAR(cr))
486     {
487         x_per_core = ceil((real)xtot / (real)cr->nnodes);
488         startlocal = startglobal + x_per_core*cr->nodeid;
489         stoplocal = startlocal + x_per_core -1;
490         if (stoplocal > stopglobal)
491              stoplocal = stopglobal;
492     }
493     else
494     {
495         startlocal = startglobal;
496         stoplocal  = stopglobal;
497         x_per_core = xtot;
498     }
499 /*     
500 #ifdef GMX_LIB_MPI
501     MPI_Barrier(MPI_COMM_WORLD);
502 #endif
503 */
504
505 #ifdef GMX_LIB_MPI
506 #ifdef TAKETIME
507     if (MASTER(cr))
508         t0 = MPI_Wtime();
509 #endif
510 #endif
511     
512     if (MASTER(cr)){
513                          
514         fprintf(stderr, "Calculating reciprocal error part 1 ...");
515         
516     }
517
518     for(nx=startlocal; nx<=stoplocal; nx++)
519     {   
520         svmul(nx,info->recipbox[XX],gridpx);
521         for(ny=-info->nky[0]/2; ny<info->nky[0]/2+1; ny++)
522         {
523             svmul(ny,info->recipbox[YY],tmpvec);
524             rvec_add(gridpx,tmpvec,gridpxy);
525             for(nz=-info->nkz[0]/2; nz<info->nkz[0]/2+1; nz++)
526             {
527                 if (  0 == nx &&  0 == ny &&  0 == nz )
528                     continue;
529                 svmul(nz,info->recipbox[ZZ],tmpvec);
530                 rvec_add(gridpxy,tmpvec,gridp);
531                 tmp=norm2(gridp);
532                 coeff=exp(-1.0 * M_PI * M_PI * tmp / info->ewald_beta[0] / info->ewald_beta[0] ) ;
533                 coeff/= 2.0 * M_PI * info->volume * tmp;
534                 coeff2=tmp ;
535                 
536                 
537                 tmp=eps_poly2(nx,info->nkx[0],info->pme_order[0]);
538                 tmp+=eps_poly2(ny,info->nkx[0],info->pme_order[0]);
539                 tmp+=eps_poly2(nz,info->nkx[0],info->pme_order[0]);
540                 
541                 tmp1=eps_poly1(nx,info->nkx[0],info->pme_order[0]);
542                 tmp2=eps_poly1(ny,info->nky[0],info->pme_order[0]);
543                 
544                 tmp+=2.0 * tmp1 * tmp2;
545                 
546                 tmp1=eps_poly1(nz,info->nkz[0],info->pme_order[0]);
547                 tmp2=eps_poly1(ny,info->nky[0],info->pme_order[0]);
548                 
549                 tmp+=2.0 * tmp1 * tmp2;
550                 
551                 tmp1=eps_poly1(nz,info->nkz[0],info->pme_order[0]);
552                 tmp2=eps_poly1(nx,info->nkx[0],info->pme_order[0]);
553                 
554                 tmp+=2.0 * tmp1 * tmp2;
555                 
556                 tmp1=eps_poly1(nx,info->nkx[0],info->pme_order[0]);
557                 tmp1+=eps_poly1(ny,info->nky[0],info->pme_order[0]);
558                 tmp1+=eps_poly1(nz,info->nkz[0],info->pme_order[0]);
559                 
560                 tmp+= tmp1 * tmp1;
561                 
562                 e_rec1+= 32.0 * M_PI * M_PI * coeff * coeff * coeff2 * tmp  * q2_all * q2_all / nr ;
563
564                 tmp1=eps_poly3(nx,info->nkx[0],info->pme_order[0]);
565                 tmp1*=info->nkx[0];
566                 tmp2=iprod(gridp,info->recipbox[XX]);
567                 
568                 tmp=tmp1*tmp2;
569                 
570                 tmp1=eps_poly3(ny,info->nky[0],info->pme_order[0]);
571                 tmp1*=info->nky[0];
572                 tmp2=iprod(gridp,info->recipbox[YY]);
573                 
574                 tmp+=tmp1*tmp2;
575                 
576                 tmp1=eps_poly3(nz,info->nkz[0],info->pme_order[0]);
577                 tmp1*=info->nkz[0];
578                 tmp2=iprod(gridp,info->recipbox[ZZ]);
579                 
580                 tmp+=tmp1*tmp2;
581                 
582                 tmp*=4.0 * M_PI;
583                 
584                 tmp1=eps_poly4(nx,info->nkx[0],info->pme_order[0]);
585                 tmp1*=norm2(info->recipbox[XX]);
586                 tmp1*=info->nkx[0] * info->nkx[0];
587                 
588                 tmp+=tmp1;
589                 
590                 tmp1=eps_poly4(ny,info->nky[0],info->pme_order[0]);
591                 tmp1*=norm2(info->recipbox[YY]);
592                 tmp1*=info->nky[0] * info->nky[0];
593                 
594                 tmp+=tmp1;
595                 
596                 tmp1=eps_poly4(nz,info->nkz[0],info->pme_order[0]);
597                 tmp1*=norm2(info->recipbox[ZZ]);
598                 tmp1*=info->nkz[0] * info->nkz[0];
599                 
600                 tmp+=tmp1;
601                 
602                 e_rec2+= 4.0 * coeff * coeff * tmp * q2_all * q2_all / nr ;
603                 
604             }
605         }
606         if (MASTER(cr))
607             fprintf(stderr, "\rCalculating reciprocal error part 1 ... %3.0f%%", 100.0*(nx-startlocal+1)/(x_per_core));
608         
609     }
610
611     if (MASTER(cr))
612         fprintf(stderr, "\n");
613     
614     /* Use just a fraction of all charges to estimate the self energy error term? */
615     bFraction =  (info->fracself > 0.0) && (info->fracself < 1.0);
616
617     if (bFraction)
618     {
619         /* Here xtot is the number of samples taken for the Monte Carlo calculation
620          * of the average of term IV of equation 35 in Wang2010. Round up to a
621          * number of samples that is divisible by the number of nodes */
622         x_per_core  = ceil(info->fracself * nr / (real)cr->nnodes);
623         xtot = x_per_core * cr->nnodes;
624     }
625     else
626     {
627         /* In this case we use all nr particle positions */
628         xtot = nr;
629         x_per_core = ceil( (real)xtot / (real)cr->nnodes );
630     }
631
632     startlocal = x_per_core *  cr->nodeid;
633     stoplocal  = min(startlocal + x_per_core, xtot);  /* min needed if xtot == nr */
634
635     if (bFraction)
636     {
637         /* Make shure we get identical results in serial and parallel. Therefore,
638          * take the sample indices from a single, global random number array that
639          * is constructed on the master node and that only depends on the seed */
640         snew(numbers, xtot);
641         if (MASTER(cr))
642         {
643             for (i=0; i<xtot; i++)
644             {
645                 numbers[i] = floor(gmx_rng_uniform_real(rng) * nr );
646             }
647         }
648         /* Broadcast the random number array to the other nodes */
649         if (PAR(cr))
650         {
651             nblock_bc(cr,xtot,numbers);
652         }
653
654         if (bVerbose && MASTER(cr))
655         {
656             fprintf(stdout, "Using %d sample%s to approximate the self interaction error term",
657                     xtot, xtot==1?"":"s");
658             if (PAR(cr))
659                 fprintf(stdout, " (%d sample%s per node)", x_per_core, x_per_core==1?"":"s");
660             fprintf(stdout, ".\n");
661         }
662     }
663
664     /* Return the number of positions used for the Monte Carlo algorithm */
665     *nsamples = xtot;
666
667     for(i=startlocal;i<stoplocal;i++)
668     {
669         e_rec3x=0;
670         e_rec3y=0;
671         e_rec3z=0;
672
673         if (bFraction)
674         {
675             /* Randomly pick a charge */
676             ci = numbers[i];
677         }
678         else
679         {
680             /* Use all charges */
681             ci = i;
682         }
683
684         /* for(nx=startlocal; nx<=stoplocal; nx++)*/
685         for(nx=-info->nkx[0]/2; nx<info->nkx[0]/2+1; nx++) 
686         {   
687             svmul(nx,info->recipbox[XX],gridpx);
688             for(ny=-info->nky[0]/2; ny<info->nky[0]/2+1; ny++)
689             {
690                 svmul(ny,info->recipbox[YY],tmpvec);
691                 rvec_add(gridpx,tmpvec,gridpxy);
692                 for(nz=-info->nkz[0]/2; nz<info->nkz[0]/2+1; nz++)
693                 {
694                     
695                     if (  0 == nx && 0 == ny && 0 == nz)
696                         continue;
697                     
698                     svmul(nz,info->recipbox[ZZ],tmpvec);
699                     rvec_add(gridpxy,tmpvec,gridp);
700                     tmp=norm2(gridp);
701                     coeff=exp(-1.0 * M_PI * M_PI * tmp / info->ewald_beta[0] / info->ewald_beta[0] );
702                     coeff/= tmp ;
703                     e_rec3x+=coeff*eps_self(nx,info->nkx[0],info->recipbox[XX],info->pme_order[0],x[ci]);
704                     e_rec3y+=coeff*eps_self(ny,info->nky[0],info->recipbox[YY],info->pme_order[0],x[ci]);
705                     e_rec3z+=coeff*eps_self(nz,info->nkz[0],info->recipbox[ZZ],info->pme_order[0],x[ci]);
706
707                 }
708             }
709         }
710
711         clear_rvec(tmpvec2);
712
713         svmul(e_rec3x,info->recipbox[XX],tmpvec);
714         rvec_inc(tmpvec2,tmpvec);
715         svmul(e_rec3y,info->recipbox[YY],tmpvec);
716         rvec_inc(tmpvec2,tmpvec);
717         svmul(e_rec3z,info->recipbox[ZZ],tmpvec);
718         rvec_inc(tmpvec2,tmpvec);
719
720         e_rec3 += q[ci]*q[ci]*q[ci]*q[ci]*norm2(tmpvec2) / ( xtot * M_PI * info->volume * M_PI * info->volume);
721         if (MASTER(cr)){
722             fprintf(stderr, "\rCalculating reciprocal error part 2 ... %3.0f%%",
723                     100.0*(i+1)/stoplocal);
724
725         }
726     }
727
728     if (MASTER(cr))
729         fprintf(stderr, "\n");
730
731 #ifdef GMX_LIB_MPI
732 #ifdef TAKETIME
733     if (MASTER(cr))
734     {
735         t1= MPI_Wtime() - t0;
736         fprintf(fp_out, "Recip. err. est. took   : %lf s\n", t1);
737     }
738 #endif
739 #endif
740    
741 #ifdef DEBUG
742     if (PAR(cr))
743     {
744         fprintf(stderr, "Node %3d: nx=[%3d...%3d]  e_rec3=%e\n", 
745                 cr->nodeid, startlocal, stoplocal, e_rec3);
746     }
747 #endif
748
749     if (PAR(cr))
750     {
751         gmx_sum(1,&e_rec1,cr);
752         gmx_sum(1,&e_rec2,cr);
753         gmx_sum(1,&e_rec3,cr);
754     }
755     
756     /* e_rec1*=8.0 * q2_all / info->volume / info->volume / nr ;
757        e_rec2*=  q2_all / M_PI / M_PI / info->volume / info->volume / nr ;
758        e_rec3/= M_PI * M_PI * info->volume * info->volume * nr ; 
759      */
760     e_rec=sqrt(e_rec1+e_rec2+e_rec3);
761     
762     
763     return ONE_4PI_EPS0 * e_rec;
764 }
765
766
767 /* Allocate memory for the inputinfo struct: */
768 static void create_info(t_inputinfo *info)
769 {
770     snew(info->fac       , info->n_entries);
771     snew(info->rcoulomb  , info->n_entries);
772     snew(info->rvdw      , info->n_entries);
773     snew(info->nkx       , info->n_entries);
774     snew(info->nky       , info->n_entries);
775     snew(info->nkz       , info->n_entries);
776     snew(info->fourier_sp, info->n_entries);
777     snew(info->ewald_rtol, info->n_entries);
778     snew(info->ewald_beta, info->n_entries);
779     snew(info->pme_order , info->n_entries);
780     snew(info->fn_out    , info->n_entries);
781     snew(info->e_dir     , info->n_entries);
782     snew(info->e_rec     , info->n_entries);
783 }
784
785
786 /* Allocate and fill an array with coordinates and charges,
787  * returns the number of charges found
788  */
789 static int prepare_x_q(real *q[], rvec *x[], gmx_mtop_t *mtop, rvec x_orig[], t_commrec *cr)
790 {
791     int i,anr_global;
792     int nq; /* number of charged particles */
793     t_atom *atom;
794     
795     
796     if (MASTER(cr))
797     {
798         snew(*q, mtop->natoms);
799         snew(*x, mtop->natoms);
800         nq=0;
801         for (i=0; i<mtop->natoms; i++)
802         {
803             anr_global = i;
804             gmx_mtop_atomnr_to_atom(mtop,anr_global,&atom);
805             if (is_charge(atom->q))
806             {
807                 (*q)[nq] = atom->q;
808                 (*x)[nq][XX] = x_orig[i][XX];
809                 (*x)[nq][YY] = x_orig[i][YY];
810                 (*x)[nq][ZZ] = x_orig[i][ZZ];
811                 nq++;
812             }
813         }
814         /* Give back some unneeded memory */
815         srenew(*q, nq);
816         srenew(*x, nq);
817     }
818     /* Broadcast x and q in the parallel case */
819     if (PAR(cr))
820     {
821         /* Transfer the number of charges */
822         block_bc(cr,nq);
823         snew_bc(cr, *x, nq);
824         snew_bc(cr, *q, nq);
825         nblock_bc(cr,nq,*x);
826         nblock_bc(cr,nq,*q);
827     }
828     
829     return nq;
830 }
831
832
833
834 /* Read in the tpr file and save information we need later in info */
835 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)
836 {
837     read_tpx_state(fn_sim_tpr,ir,state,NULL,mtop);
838
839     /* The values of the original tpr input file are save in the first 
840      * place [0] of the arrays */
841     info->orig_sim_steps = ir->nsteps;
842     info->pme_order[0]   = ir->pme_order;
843     info->rcoulomb[0]    = ir->rcoulomb;
844     info->rvdw[0]        = ir->rvdw;        
845     info->nkx[0]         = ir->nkx;
846     info->nky[0]         = ir->nky;
847     info->nkz[0]         = ir->nkz;
848     info->ewald_rtol[0]  = ir->ewald_rtol;
849     info->fracself       = fracself;
850     if (user_beta > 0)
851         info->ewald_beta[0] = user_beta;
852     else
853         info->ewald_beta[0]  = calc_ewaldcoeff(info->rcoulomb[0],info->ewald_rtol[0]);
854
855     /* Check if PME was chosen */
856     if (EEL_PME(ir->coulombtype) == FALSE)
857         gmx_fatal(FARGS, "Can only do optimizations for simulations with PME");
858     
859     /* Check if rcoulomb == rlist, which is necessary for PME */
860     if (!(ir->rcoulomb == ir->rlist))
861         gmx_fatal(FARGS, "PME requires rcoulomb (%f) to be equal to rlist (%f).", ir->rcoulomb, ir->rlist);
862 }
863
864
865 /* Transfer what we need for parallelizing the reciprocal error estimate */
866 static void bcast_info(t_inputinfo *info, t_commrec *cr)
867 {
868     nblock_bc(cr, info->n_entries, info->nkx);
869     nblock_bc(cr, info->n_entries, info->nky);
870     nblock_bc(cr, info->n_entries, info->nkz);
871     nblock_bc(cr, info->n_entries, info->ewald_beta);
872     nblock_bc(cr, info->n_entries, info->pme_order);
873     nblock_bc(cr, info->n_entries, info->e_dir);
874     nblock_bc(cr, info->n_entries, info->e_rec);
875     block_bc(cr, info->volume);
876     block_bc(cr, info->recipbox);
877     block_bc(cr, info->natoms);
878     block_bc(cr, info->fracself);
879     block_bc(cr, info->bTUNE);
880     block_bc(cr, info->q2all);
881     block_bc(cr, info->q2allnr);
882 }
883
884
885 /* Estimate the error of the SPME Ewald sum. This estimate is based upon
886  * a) a homogeneous distribution of the charges
887  * b) a total charge of zero.
888  */
889 static void estimate_PME_error(t_inputinfo *info, t_state *state, 
890         gmx_mtop_t *mtop, FILE *fp_out, gmx_bool bVerbose, unsigned int seed,
891         t_commrec *cr)
892 {
893     rvec *x=NULL; /* The coordinates */
894     real *q=NULL; /* The charges     */
895     real  edir=0.0; /* real space error */
896     real  erec=0.0; /* reciprocal space error */
897     real  derr=0.0; /* difference of real and reciprocal space error */
898     real  derr0=0.0; /* difference of real and reciprocal space error */
899     real  beta=0.0; /* splitting parameter beta */
900     real  beta0=0.0; /* splitting parameter beta */
901     int ncharges; /* The number of atoms with charges */
902     int nsamples; /* The number of samples used for the calculation of the
903                    * self-energy error term */
904     int i=0;
905     
906     if (MASTER(cr))
907         fprintf(fp_out, "\n--- PME ERROR ESTIMATE ---\n");    
908
909     /* Prepare an x and q array with only the charged atoms */
910     ncharges = prepare_x_q(&q, &x, mtop, state->x, cr);
911     if (MASTER(cr))
912     {
913         calc_q2all(mtop, &(info->q2all), &(info->q2allnr));
914         info->ewald_rtol[0]=gmx_erfc(info->rcoulomb[0]*info->ewald_beta[0]);
915         /* Write some info to log file */
916         fprintf(fp_out, "Box volume              : %g nm^3\n", info->volume);
917         fprintf(fp_out, "Number of charged atoms : %d (total atoms %d)\n",ncharges, info->natoms);
918         fprintf(fp_out, "Coulomb radius          : %g nm\n", info->rcoulomb[0]);
919         fprintf(fp_out, "Ewald_rtol              : %g\n", info->ewald_rtol[0]);
920         fprintf(fp_out, "Ewald parameter beta    : %g\n", info->ewald_beta[0]);
921         fprintf(fp_out, "Interpolation order     : %d\n", info->pme_order[0]);
922         fprintf(fp_out, "Fourier grid (nx,ny,nz) : %d x %d x %d\n", 
923                 info->nkx[0],info->nky[0],info->nkz[0]);
924         fflush(fp_out);
925         
926     }
927
928     if (PAR(cr))
929         bcast_info(info, cr);
930
931
932     /* Calculate direct space error */
933     info->e_dir[0] = estimate_direct(info);
934
935     /* Calculate reciprocal space error */
936     info->e_rec[0] = estimate_reciprocal(info, x, q, ncharges, fp_out, bVerbose,
937                                          seed, &nsamples, cr);
938
939     if (PAR(cr))
940         bcast_info(info, cr);
941     
942     if (MASTER(cr))
943     {
944         fprintf(fp_out, "Direct space error est. : %10.3e kJ/(mol*nm)\n", info->e_dir[0]);
945         fprintf(fp_out, "Reciprocal sp. err. est.: %10.3e kJ/(mol*nm)\n", info->e_rec[0]);
946         fprintf(fp_out, "Self-energy error term was estimated using %d samples\n", nsamples);
947         fflush(fp_out);
948         fprintf(stderr, "Direct space error est. : %10.3e kJ/(mol*nm)\n", info->e_dir[0]);
949         fprintf(stderr, "Reciprocal sp. err. est.: %10.3e kJ/(mol*nm)\n", info->e_rec[0]);
950     }
951
952     i=0;
953
954     if (info->bTUNE)
955     {
956         if(MASTER(cr))
957             fprintf(stderr,"Starting tuning ...\n");
958         edir=info->e_dir[0];
959         erec=info->e_rec[0];
960         derr0=edir-erec;
961         beta0=info->ewald_beta[0];
962         if (derr>0.0)
963             info->ewald_beta[0]+=0.1;
964         else
965             info->ewald_beta[0]-=0.1;
966         info->e_dir[0] = estimate_direct(info);
967         info->e_rec[0] = estimate_reciprocal(info, x, q, ncharges, fp_out, bVerbose,
968                                              seed, &nsamples, cr);
969
970         if (PAR(cr))
971             bcast_info(info, cr);
972     
973         
974         edir=info->e_dir[0];
975         erec=info->e_rec[0];
976         derr=edir-erec;
977         while ( fabs(derr/min(erec,edir)) > 1e-4)
978         {
979     
980             beta=info->ewald_beta[0];
981             beta-=derr*(info->ewald_beta[0]-beta0)/(derr-derr0);
982             beta0=info->ewald_beta[0];
983             info->ewald_beta[0]=beta;
984             derr0=derr;
985
986             info->e_dir[0] = estimate_direct(info);
987             info->e_rec[0] = estimate_reciprocal(info, x, q, ncharges, fp_out, bVerbose,
988                                                  seed, &nsamples, cr);
989
990             if (PAR(cr))
991                 bcast_info(info, cr);
992             
993             edir=info->e_dir[0];
994             erec=info->e_rec[0];
995             derr=edir-erec;
996             
997             if (MASTER(cr))
998             {
999                 i++;
1000                 fprintf(stderr,"difference between real and rec. space error (step %d): %g\n",i,fabs(derr));
1001                 fprintf(stderr,"old beta: %f\n",beta0);
1002                 fprintf(stderr,"new beta: %f\n",beta);
1003             }
1004         }
1005
1006         info->ewald_rtol[0]=gmx_erfc(info->rcoulomb[0]*info->ewald_beta[0]);
1007
1008         if (MASTER(cr))
1009         {
1010             /* Write some info to log file */
1011             fflush(fp_out);
1012             fprintf(fp_out, "=========  After tuning ========\n");
1013             fprintf(fp_out, "Direct space error est. : %10.3e kJ/(mol*nm)\n", info->e_dir[0]);
1014             fprintf(fp_out, "Reciprocal sp. err. est.: %10.3e kJ/(mol*nm)\n", info->e_rec[0]);
1015             fprintf(stderr, "Direct space error est. : %10.3e kJ/(mol*nm)\n", info->e_dir[0]);
1016             fprintf(stderr, "Reciprocal sp. err. est.: %10.3e kJ/(mol*nm)\n", info->e_rec[0]);
1017             fprintf(fp_out, "Ewald_rtol              : %g\n", info->ewald_rtol[0]);
1018             fprintf(fp_out, "Ewald parameter beta    : %g\n", info->ewald_beta[0]);
1019             fflush(fp_out);
1020             
1021         }   
1022
1023     }
1024
1025 }
1026
1027
1028 int gmx_pme_error(int argc,char *argv[])
1029 {
1030     const char *desc[] = {
1031             "[TT]g_pme_error[tt] estimates the error of the electrostatic forces",
1032             "if using the sPME algorithm. The flag [TT]-tune[tt] will determine",
1033             "the splitting parameter such that the error is equally",
1034             "distributed over the real and reciprocal space part.",
1035             "The part of the error that stems from self interaction of the particles "
1036             "is computationally demanding. However, a good a approximation is to",
1037             "just use a fraction of the particles for this term which can be",
1038             "indicated by the flag [TT]-self[tt].[PAR]",
1039     };
1040
1041     real        fs=0.0;             /* 0 indicates: not set by the user */
1042     real        user_beta=-1.0;
1043     real        fracself=1.0;
1044     t_inputinfo info;
1045     t_state     state;     /* The state from the tpr input file */
1046     gmx_mtop_t  mtop;      /* The topology from the tpr input file */
1047     t_inputrec  *ir=NULL;  /* The inputrec from the tpr file */
1048     FILE        *fp=NULL;
1049     t_commrec   *cr;
1050     unsigned long PCA_Flags;
1051     gmx_bool        bTUNE=FALSE;
1052     gmx_bool    bVerbose=FALSE;
1053     int         seed=0;
1054
1055
1056     static t_filenm fnm[] = {
1057       { efTPX, "-s",     NULL,    ffREAD },
1058       { efOUT, "-o",    "error",  ffWRITE },
1059       { efTPX, "-so",   "tuned",  ffOPTWR }
1060     };
1061
1062     output_env_t oenv=NULL;
1063
1064     t_pargs pa[] = {
1065         { "-beta",     FALSE, etREAL, {&user_beta},
1066             "If positive, overwrite ewald_beta from [TT].tpr[tt] file with this value" },
1067         { "-tune",     FALSE, etBOOL, {&bTUNE},
1068             "Tune the splitting parameter such that the error is equally distributed between real and reciprocal space" },
1069         { "-self",     FALSE, etREAL, {&fracself},
1070             "If between 0.0 and 1.0, determine self interaction error from just this fraction of the charged particles" },
1071         { "-seed",     FALSE, etINT,  {&seed},
1072           "Random number seed used for Monte Carlo algorithm when [TT]-self[tt] is set to a value between 0.0 and 1.0" },
1073         { "-v",        FALSE, etBOOL, {&bVerbose},
1074             "Be loud and noisy" }
1075     };
1076
1077     
1078 #define NFILE asize(fnm)
1079     
1080     cr = init_par(&argc,&argv);
1081     
1082 #ifdef GMX_LIB_MPI
1083     MPI_Barrier(MPI_COMM_WORLD);
1084 #endif
1085
1086     if (MASTER(cr))
1087       CopyRight(stderr,argv[0]);
1088     
1089     PCA_Flags = PCA_NOEXIT_ON_ARGS;
1090     PCA_Flags |= (MASTER(cr) ? 0 : PCA_QUIET);
1091     
1092     parse_common_args(&argc,argv,PCA_Flags,
1093                       NFILE,fnm,asize(pa),pa,asize(desc),desc,
1094                       0,NULL,&oenv);        
1095
1096     if (!bTUNE)
1097         bTUNE = opt2bSet("-so",NFILE,fnm);
1098
1099     info.n_entries = 1;
1100     
1101     /* Allocate memory for the inputinfo struct: */
1102     create_info(&info);
1103     info.fourier_sp[0] = fs;
1104     
1105     /* Read in the tpr file and open logfile for reading */
1106     if (MASTER(cr))
1107     {
1108         snew(ir,1);
1109         read_tpr_file(opt2fn("-s",NFILE,fnm), &info, &state, &mtop, ir, user_beta,fracself);
1110
1111         fp=fopen(opt2fn("-o",NFILE,fnm),"w");
1112     }
1113     
1114     /* Check consistency if the user provided fourierspacing */
1115     if (fs > 0 && MASTER(cr))
1116     {
1117         /* Recalculate the grid dimensions using fourierspacing from user input */
1118         info.nkx[0] = 0;
1119         info.nky[0] = 0;
1120         info.nkz[0] = 0;
1121         calc_grid(stdout,state.box,info.fourier_sp[0],&(info.nkx[0]),&(info.nky[0]),&(info.nkz[0]));
1122         if ( (ir->nkx != info.nkx[0]) || (ir->nky != info.nky[0]) || (ir->nkz != info.nkz[0]) )
1123             gmx_fatal(FARGS, "Wrong fourierspacing %f nm, input file grid = %d x %d x %d, computed grid = %d x %d x %d", 
1124                       fs,ir->nkx,ir->nky,ir->nkz,info.nkx[0],info.nky[0],info.nkz[0]);
1125     }
1126     
1127     /* Estimate (S)PME force error */
1128
1129     /* Determine the volume of the simulation box */
1130     if (MASTER(cr))
1131     {
1132         info.volume = det(state.box);
1133         calc_recipbox(state.box,info.recipbox);
1134         info.natoms = mtop.natoms;
1135         info.bTUNE  = bTUNE;
1136     }   
1137
1138     if (PAR(cr))
1139         bcast_info(&info, cr);
1140     
1141     /* Get an error estimate of the input tpr file and do some tuning if requested */
1142     estimate_PME_error(&info, &state, &mtop, fp, bVerbose, seed, cr);
1143     
1144     if (MASTER(cr))
1145     {
1146         /* Write out optimized tpr file if requested */
1147         if ( opt2bSet("-so",NFILE,fnm) || bTUNE )
1148         {
1149             ir->ewald_rtol=info.ewald_rtol[0];
1150             write_tpx_state(opt2fn("-so",NFILE,fnm),ir,&state,&mtop);
1151         }
1152         please_cite(fp,"Wang2010");
1153         fclose(fp);
1154     }
1155     
1156     gmx_finalize_par();
1157     
1158     return 0;
1159 }