/* Estimate the reciprocal space part error of the SPME Ewald sum. */
static real estimate_reciprocal(
        t_inputinfo *info, 
        rvec x[],           /* array of particles */
        real q[],           /* array of charges */
        int nr,             /* number of charges = size of the charge array */
        FILE *fp_out,
        gmx_bool bVerbose,
        unsigned int seed,  /* The seed for the random number generator */
        int *nsamples,      /* Return the number of samples used if Monte Carlo
                             * algorithm is used for self energy error estimate */
        t_commrec *cr)
{
    real e_rec=0;   /* reciprocal error estimate */
    real e_rec1=0;  /* Error estimate term 1*/
    real e_rec2=0;  /* Error estimate term 2*/
    real e_rec3=0;  /* Error estimate term 3 */
    real e_rec3x=0; /* part of Error estimate term 3 in x */
    real e_rec3y=0; /* part of Error estimate term 3 in y */
    real e_rec3z=0; /* part of Error estimate term 3 in z */
    int i,ci;
    int nx,ny,nz;   /* grid coordinates */
    real q2_all=0;  /* sum of squared charges */
    rvec gridpx;    /* reciprocal grid point in x direction*/
    rvec gridpxy;   /* reciprocal grid point in x and y direction*/
    rvec gridp;     /* complete reciprocal grid point in 3 directions*/
    rvec tmpvec;    /* template to create points from basis vectors */
    rvec tmpvec2;   /* template to create points from basis vectors */
    real coeff=0;   /* variable to compute coefficients of the error estimate */
    real coeff2=0;   /* variable to compute coefficients of the error estimate */
    real tmp=0;     /* variables to compute different factors from vectors */
    real tmp1=0;
    real tmp2=0;
    gmx_bool bFraction;
    
    /* Random number generator */
    gmx_rng_t rng=NULL;
    int *numbers=NULL;

    /* Index variables for parallel work distribution */
    int startglobal,stopglobal;
    int startlocal, stoplocal;
    int x_per_core;
    int xtot;

#ifdef TAKETIME
    double t0=0.0;
    double t1=0.0;
#endif

    rng=gmx_rng_init(seed);

    clear_rvec(gridpx);
    clear_rvec(gridpxy);
    clear_rvec(gridp);
    clear_rvec(tmpvec);
    clear_rvec(tmpvec2);

    for(i=0;i<nr;i++)
    {
        q2_all += q[i]*q[i];
    }
    
    /* Calculate indices for work distribution */
    startglobal=-info->nkx[0]/2;
    stopglobal = info->nkx[0]/2;
    xtot = stopglobal*2+1;
    if (PAR(cr))
    {
        x_per_core = ceil((real)xtot / (real)cr->nnodes);
        startlocal = startglobal + x_per_core*cr->nodeid;
        stoplocal = startlocal + x_per_core -1;
        if (stoplocal > stopglobal)
             stoplocal = stopglobal;
    }
    else
    {
        startlocal = startglobal;
        stoplocal  = stopglobal;
        x_per_core = xtot;
    }
/*     
#ifdef GMX_LIB_MPI
    MPI_Barrier(MPI_COMM_WORLD);
#endif
*/

#ifdef GMX_LIB_MPI
#ifdef TAKETIME
    if (MASTER(cr))
        t0 = MPI_Wtime();
#endif
#endif
    
    if (MASTER(cr)){
                         
        fprintf(stderr, "Calculating reciprocal error part 1 ...");
        
    }

    for(nx=startlocal; nx<=stoplocal; nx++)
    {   
        svmul(nx,info->recipbox[XX],gridpx);
        for(ny=-info->nky[0]/2; ny<info->nky[0]/2+1; ny++)
        {
            svmul(ny,info->recipbox[YY],tmpvec);
            rvec_add(gridpx,tmpvec,gridpxy);
            for(nz=-info->nkz[0]/2; nz<info->nkz[0]/2+1; nz++)
            {
                if (  0 == nx &&  0 == ny &&  0 == nz )
                    continue;
                svmul(nz,info->recipbox[ZZ],tmpvec);
                rvec_add(gridpxy,tmpvec,gridp);
                tmp=norm2(gridp);
                coeff=exp(-1.0 * M_PI * M_PI * tmp / info->ewald_beta[0] / info->ewald_beta[0] ) ;
                coeff/= 2.0 * M_PI * info->volume * tmp;
                coeff2=tmp ;
                
                
                tmp=eps_poly2(nx,info->nkx[0],info->pme_order[0]);
                tmp+=eps_poly2(ny,info->nkx[0],info->pme_order[0]);
                tmp+=eps_poly2(nz,info->nkx[0],info->pme_order[0]);
                
                tmp1=eps_poly1(nx,info->nkx[0],info->pme_order[0]);
                tmp2=eps_poly1(ny,info->nky[0],info->pme_order[0]);
                
                tmp+=2.0 * tmp1 * tmp2;
                
                tmp1=eps_poly1(nz,info->nkz[0],info->pme_order[0]);
                tmp2=eps_poly1(ny,info->nky[0],info->pme_order[0]);
                
                tmp+=2.0 * tmp1 * tmp2;
                
                tmp1=eps_poly1(nz,info->nkz[0],info->pme_order[0]);
                tmp2=eps_poly1(nx,info->nkx[0],info->pme_order[0]);
                
                tmp+=2.0 * tmp1 * tmp2;
                
                tmp1=eps_poly1(nx,info->nkx[0],info->pme_order[0]);
                tmp1+=eps_poly1(ny,info->nky[0],info->pme_order[0]);
                tmp1+=eps_poly1(nz,info->nkz[0],info->pme_order[0]);
                
                tmp+= tmp1 * tmp1;
                
                e_rec1+= 32.0 * M_PI * M_PI * coeff * coeff * coeff2 * tmp  * q2_all * q2_all / nr ;

                tmp1=eps_poly3(nx,info->nkx[0],info->pme_order[0]);
                tmp1*=info->nkx[0];
                tmp2=iprod(gridp,info->recipbox[XX]);
                
                tmp=tmp1*tmp2;
                
                tmp1=eps_poly3(ny,info->nky[0],info->pme_order[0]);
                tmp1*=info->nky[0];
                tmp2=iprod(gridp,info->recipbox[YY]);
                
                tmp+=tmp1*tmp2;
                
                tmp1=eps_poly3(nz,info->nkz[0],info->pme_order[0]);
                tmp1*=info->nkz[0];
                tmp2=iprod(gridp,info->recipbox[ZZ]);
                
                tmp+=tmp1*tmp2;
                
                tmp*=4.0 * M_PI;
                
                tmp1=eps_poly4(nx,info->nkx[0],info->pme_order[0]);
                tmp1*=norm2(info->recipbox[XX]);
                tmp1*=info->nkx[0] * info->nkx[0];
                
                tmp+=tmp1;
                
                tmp1=eps_poly4(ny,info->nky[0],info->pme_order[0]);
                tmp1*=norm2(info->recipbox[YY]);
                tmp1*=info->nky[0] * info->nky[0];
                
                tmp+=tmp1;
                
                tmp1=eps_poly4(nz,info->nkz[0],info->pme_order[0]);
                tmp1*=norm2(info->recipbox[ZZ]);
                tmp1*=info->nkz[0] * info->nkz[0];
                
                tmp+=tmp1;
                
                e_rec2+= 4.0 * coeff * coeff * tmp * q2_all * q2_all / nr ;
                
            }
        }
        if (MASTER(cr))
            fprintf(stderr, "\rCalculating reciprocal error part 1 ... %3.0f%%", 100.0*(nx-startlocal+1)/(x_per_core));
        
    }

    if (MASTER(cr))
        fprintf(stderr, "\n");
    
    /* Use just a fraction of all charges to estimate the self energy error term? */
    bFraction =  (info->fracself > 0.0) && (info->fracself < 1.0);

    if (bFraction)
    {
        /* Here xtot is the number of samples taken for the Monte Carlo calculation
         * of the average of term IV of equation 35 in Wang2010. Round up to a
         * number of samples that is divisible by the number of nodes */
        x_per_core  = ceil(info->fracself * nr / (real)cr->nnodes);
        xtot = x_per_core * cr->nnodes;
    }
    else
    {
        /* In this case we use all nr particle positions */
        xtot = nr;
        x_per_core = ceil( (real)xtot / (real)cr->nnodes );
    }

    startlocal = x_per_core *  cr->nodeid;
    stoplocal  = min(startlocal + x_per_core, xtot);  /* min needed if xtot == nr */

    if (bFraction)
    {
        /* Make shure we get identical results in serial and parallel. Therefore,
         * take the sample indices from a single, global random number array that
         * is constructed on the master node and that only depends on the seed */
        snew(numbers, xtot);
        if (MASTER(cr))
        {
            for (i=0; i<xtot; i++)
            {
                numbers[i] = floor(gmx_rng_uniform_real(rng) * nr );
            }
        }
        /* Broadcast the random number array to the other nodes */
        if (PAR(cr))
        {
            nblock_bc(cr,xtot,numbers);
        }

        if (bVerbose && MASTER(cr))
        {
            fprintf(stdout, "Using %d sample%s to approximate the self interaction error term",
                    xtot, xtot==1?"":"s");
            if (PAR(cr))
                fprintf(stdout, " (%d sample%s per node)", x_per_core, x_per_core==1?"":"s");
            fprintf(stdout, ".\n");
        }
    }

    /* Return the number of positions used for the Monte Carlo algorithm */
    *nsamples = xtot;

    for(i=startlocal;i<stoplocal;i++)
    {
        e_rec3x=0;
        e_rec3y=0;
        e_rec3z=0;

        if (bFraction)
        {
            /* Randomly pick a charge */
            ci = numbers[i];
        }
        else
        {
            /* Use all charges */
            ci = i;
        }

        /* for(nx=startlocal; nx<=stoplocal; nx++)*/
        for(nx=-info->nkx[0]/2; nx<info->nkx[0]/2+1; nx++) 
        {   
            svmul(nx,info->recipbox[XX],gridpx);
            for(ny=-info->nky[0]/2; ny<info->nky[0]/2+1; ny++)
            {
                svmul(ny,info->recipbox[YY],tmpvec);
                rvec_add(gridpx,tmpvec,gridpxy);
                for(nz=-info->nkz[0]/2; nz<info->nkz[0]/2+1; nz++)
                {
                    
                    if (  0 == nx && 0 == ny && 0 == nz)
                        continue;
                    
                    svmul(nz,info->recipbox[ZZ],tmpvec);
                    rvec_add(gridpxy,tmpvec,gridp);
                    tmp=norm2(gridp);
                    coeff=exp(-1.0 * M_PI * M_PI * tmp / info->ewald_beta[0] / info->ewald_beta[0] );
                    coeff/= tmp ;
                    e_rec3x+=coeff*eps_self(nx,info->nkx[0],info->recipbox[XX],info->pme_order[0],x[ci]);
                    e_rec3y+=coeff*eps_self(ny,info->nky[0],info->recipbox[YY],info->pme_order[0],x[ci]);
                    e_rec3z+=coeff*eps_self(nz,info->nkz[0],info->recipbox[ZZ],info->pme_order[0],x[ci]);

                }
            }
        }

        clear_rvec(tmpvec2);

        svmul(e_rec3x,info->recipbox[XX],tmpvec);
        rvec_inc(tmpvec2,tmpvec);
        svmul(e_rec3y,info->recipbox[YY],tmpvec);
        rvec_inc(tmpvec2,tmpvec);
        svmul(e_rec3z,info->recipbox[ZZ],tmpvec);
        rvec_inc(tmpvec2,tmpvec);

        e_rec3 += q[ci]*q[ci]*q[ci]*q[ci]*norm2(tmpvec2) / ( xtot * M_PI * info->volume * M_PI * info->volume);
        if (MASTER(cr)){
            fprintf(stderr, "\rCalculating reciprocal error part 2 ... %3.0f%%",
                    100.0*(i+1)/stoplocal);

        }
    }

    if (MASTER(cr))
        fprintf(stderr, "\n");

#ifdef GMX_LIB_MPI
#ifdef TAKETIME
    if (MASTER(cr))
    {
        t1= MPI_Wtime() - t0;
        fprintf(fp_out, "Recip. err. est. took   : %lf s\n", t1);
    }
#endif
#endif
   
#ifdef DEBUG
    if (PAR(cr))
    {
        fprintf(stderr, "Node %3d: nx=[%3d...%3d]  e_rec3=%e\n", 
                cr->nodeid, startlocal, stoplocal, e_rec3);
    }
#endif

    if (PAR(cr))
    {
        gmx_sum(1,&e_rec1,cr);
        gmx_sum(1,&e_rec2,cr);
        gmx_sum(1,&e_rec3,cr);
    }
    
    /* e_rec1*=8.0 * q2_all / info->volume / info->volume / nr ;
       e_rec2*=  q2_all / M_PI / M_PI / info->volume / info->volume / nr ;
       e_rec3/= M_PI * M_PI * info->volume * info->volume * nr ; 
     */
    e_rec=sqrt(e_rec1+e_rec2+e_rec3);
    
    
    return ONE_4PI_EPS0 * e_rec;
}
Esempio n. 2
0
/* Estimate the reciprocal space part error of the SPME Ewald sum. */
static real estimate_reciprocal(
        t_inputinfo *info, 
        rvec x[],           /* array of particles */
        real q[],           /* array of charges */
        int nr,             /* number of charges = size of the charge array */
        FILE *fp_out,
        t_commrec *cr)
{
    real e_rec=0;   /* reciprocal error estimate */
    real e_rec1=0;  /* Error estimate term 1*/
    real e_rec2=0;  /* Error estimate term 2*/
    real e_rec3=0;  /* Error estimate term 3 */
    real e_rec3x=0; /* part of Error estimate term 3 in x */
    real e_rec3y=0; /* part of Error estimate term 3 in y */
    real e_rec3z=0; /* part of Error estimate term 3 in z */
    int i,ci;
    int nx,ny,nz;   /* grid coordinates */
    real q2_all=0;  /* sum of squared charges */
    rvec gridpx;    /* reciprocal grid point in x direction*/
    rvec gridpxy;   /* reciprocal grid point in x and y direction*/
    rvec gridp;     /* complete reciprocal grid point in 3 directions*/
    rvec tmpvec;    /* template to create points from basis vectors */
    rvec tmpvec2;   /* template to create points from basis vectors */
    real coeff=0;   /* variable to compute coefficients of the error estimate */
    real coeff2=0;   /* variable to compute coefficients of the error estimate */
    real tmp=0;     /* variables to compute different factors from vectors */
    real tmp1=0;
    real tmp2=0;
    real xtmp=0;
    real ytmp=0;
    real ztmp=0;
    double ewald_error;
    
    /* Random number generator */
    
    gmx_rng_t rng=NULL;
    /*rng=gmx_rng_init(gmx_rng_make_seed());  */

    /* Index variables for parallel work distribution */
    int startglobal,stopglobal;
    int startlocal, stoplocal;
    int x_per_core;
    int nrsamples;
    real xtot;    

/* #define TAKETIME */
#ifdef TAKETIME
    double t0=0.0;
    double t1=0.0;
    double t2=0.0;
#endif

    rng=gmx_rng_init(cr->nodeid);

    clear_rvec(gridpx);
    clear_rvec(gridpxy);
    clear_rvec(gridp);
    clear_rvec(tmpvec);
    clear_rvec(tmpvec2);

    for(i=0;i<nr;i++)
    {
        q2_all += q[i]*q[i];
    }
    
    /* Calculate indices for work distribution */
    startglobal=-info->nkx[0]/2;
    stopglobal = info->nkx[0]/2;
    xtot = stopglobal*2+1;
    if (PAR(cr))
    {
        x_per_core = ceil(xtot / cr->nnodes);
        startlocal = startglobal + x_per_core*cr->nodeid;
        stoplocal = startlocal + x_per_core -1;
        if (stoplocal > stopglobal)
             stoplocal = stopglobal;
    }
    else
    {
        startlocal = startglobal;
        stoplocal  = stopglobal;
        x_per_core = xtot;
    }
/*     
#ifdef GMX_MPI
    MPI_Barrier(MPI_COMM_WORLD);
#endif
*/

#ifdef TAKETIME
    if (MASTER(cr))
        t0 = MPI_Wtime();
#endif
    
    if (MASTER(cr)){
                         
        fprintf(stderr, "Calculating reciprocal error part 1 ...");
        
    }

    for(nx=startlocal; nx<=stoplocal; nx++)
    {   
        svmul(nx,info->recipbox[XX],gridpx);
        for(ny=-info->nky[0]/2; ny<info->nky[0]/2+1; ny++)
        {
            svmul(ny,info->recipbox[YY],tmpvec);
            rvec_add(gridpx,tmpvec,gridpxy);
            for(nz=-info->nkz[0]/2; nz<info->nkz[0]/2+1; nz++)
            {
                if (  0 == nx &&  0 == ny &&  0 == nz )
                    continue;
                svmul(nz,info->recipbox[ZZ],tmpvec);
                rvec_add(gridpxy,tmpvec,gridp);
                tmp=norm2(gridp);
                coeff=exp(-1.0 * M_PI * M_PI * tmp / info->ewald_beta[0] / info->ewald_beta[0] ) ;
                coeff/= 2.0 * M_PI * info->volume * tmp;
                coeff2=tmp ;
                
                
                tmp=eps_poly2(nx,info->nkx[0],info->pme_order[0]);
                tmp+=eps_poly2(ny,info->nkx[0],info->pme_order[0]);
                tmp+=eps_poly2(nz,info->nkx[0],info->pme_order[0]);
                
                tmp1=eps_poly1(nx,info->nkx[0],info->pme_order[0]);
                tmp2=eps_poly1(ny,info->nky[0],info->pme_order[0]);
                
                tmp+=2.0 * tmp1 * tmp2;
                
                tmp1=eps_poly1(nz,info->nkz[0],info->pme_order[0]);
                tmp2=eps_poly1(ny,info->nky[0],info->pme_order[0]);
                
                tmp+=2.0 * tmp1 * tmp2;
                
                tmp1=eps_poly1(nz,info->nkz[0],info->pme_order[0]);
                tmp2=eps_poly1(nx,info->nkx[0],info->pme_order[0]);
                
                tmp+=2.0 * tmp1 * tmp2;
                
                tmp1=eps_poly1(nx,info->nkx[0],info->pme_order[0]);
                tmp1+=eps_poly1(ny,info->nky[0],info->pme_order[0]);
                tmp1+=eps_poly1(nz,info->nkz[0],info->pme_order[0]);
                
                tmp+= tmp1 * tmp1;
                
                e_rec1+= 32.0 * M_PI * M_PI * coeff * coeff * coeff2 * tmp  * q2_all * q2_all / nr ;

                tmp1=eps_poly3(nx,info->nkx[0],info->pme_order[0]);
                tmp1*=info->nkx[0];
                tmp2=iprod(gridp,info->recipbox[XX]);
                
                tmp=tmp1*tmp2;
                
                tmp1=eps_poly3(ny,info->nky[0],info->pme_order[0]);
                tmp1*=info->nky[0];
                tmp2=iprod(gridp,info->recipbox[YY]);
                
                tmp+=tmp1*tmp2;
                
                tmp1=eps_poly3(nz,info->nkz[0],info->pme_order[0]);
                tmp1*=info->nkz[0];
                tmp2=iprod(gridp,info->recipbox[ZZ]);
                
                tmp+=tmp1*tmp2;
                
                tmp*=4.0 * M_PI;
                
                tmp1=eps_poly4(nx,info->nkx[0],info->pme_order[0]);
                tmp1*=norm2(info->recipbox[XX]);
                tmp1*=info->nkx[0] * info->nkx[0];
                
                tmp+=tmp1;
                
                tmp1=eps_poly4(ny,info->nky[0],info->pme_order[0]);
                tmp1*=norm2(info->recipbox[YY]);
                tmp1*=info->nky[0] * info->nky[0];
                
                tmp+=tmp1;
                
                tmp1=eps_poly4(nz,info->nkz[0],info->pme_order[0]);
                tmp1*=norm2(info->recipbox[ZZ]);
                tmp1*=info->nkz[0] * info->nkz[0];
                
                tmp+=tmp1;
                
                e_rec2+= 4.0 * coeff * coeff * tmp * q2_all * q2_all / nr ;
                
            }
        }
        if (MASTER(cr))
            fprintf(stderr, "\rCalculating reciprocal error part 1 ... %3.0f%%", 100.0*(nx-startlocal+1)/(x_per_core));
        
    }

/* 
#ifdef GMX_MPI
    MPI_Barrier(MPI_COMM_WORLD);
#endif
*/

    if (MASTER(cr))
        fprintf(stderr, "\n");
    if (info->fracself>0)
    {
        nrsamples=ceil(info->fracself*nr);
    }
    else
    {
        nrsamples=nr;
    }
    
    
    xtot=nrsamples;


    startglobal=0;
    stopglobal=nr;

    if(PAR(cr))
    {
        x_per_core=ceil(xtot/cr->nnodes);
        startlocal=startglobal+x_per_core*cr->nodeid;
        stoplocal=startglobal+x_per_core*(cr->nodeid+1);
        if (stoplocal>stopglobal)
            stoplocal=stopglobal;
    }
    else
    {
        startlocal=startglobal;
        stoplocal=stopglobal;
        x_per_core=xtot;
    }



    for(i=startlocal;i<stoplocal;i++)
    {
        e_rec3x=0;
        e_rec3y=0;
        e_rec3z=0;

        if (info->fracself<0) {
            ci=i;
        }else {
            ci=floor(gmx_rng_uniform_real(rng) * nr );
            if (ci==nr)
            {
                ci=nr-1;
            }
        }

        /* for(nx=startlocal; nx<=stoplocal; nx++)*/
        for(nx=-info->nkx[0]/2; nx<info->nkx[0]/2+1; nx++) 
        {   
            svmul(nx,info->recipbox[XX],gridpx);
            for(ny=-info->nky[0]/2; ny<info->nky[0]/2+1; ny++)
            {
                svmul(ny,info->recipbox[YY],tmpvec);
                rvec_add(gridpx,tmpvec,gridpxy);
                for(nz=-info->nkz[0]/2; nz<info->nkz[0]/2+1; nz++)
                {
                    
                    if (  0 == nx && 0 == ny && 0 == nz)
                        continue;
                    
                    svmul(nz,info->recipbox[ZZ],tmpvec);
                    rvec_add(gridpxy,tmpvec,gridp);
                    tmp=norm2(gridp);
                    coeff=exp(-1.0 * M_PI * M_PI * tmp / info->ewald_beta[0] / info->ewald_beta[0] );
                    coeff/= tmp ;
                    e_rec3x+=coeff*eps_self(nx,info->nkx[0],info->recipbox[XX],info->pme_order[0],x[ci]);
                    e_rec3y+=coeff*eps_self(ny,info->nky[0],info->recipbox[YY],info->pme_order[0],x[ci]);
                    e_rec3z+=coeff*eps_self(nz,info->nkz[0],info->recipbox[ZZ],info->pme_order[0],x[ci]);

                }
            }
        }

        clear_rvec(tmpvec2);

        svmul(e_rec3x,info->recipbox[XX],tmpvec);
        rvec_inc(tmpvec2,tmpvec);
        svmul(e_rec3y,info->recipbox[YY],tmpvec);
        rvec_inc(tmpvec2,tmpvec);
        svmul(e_rec3z,info->recipbox[ZZ],tmpvec);
        rvec_inc(tmpvec2,tmpvec);

        e_rec3 += q[ci]*q[ci]*q[ci]*q[ci]*norm2(tmpvec2) / ( nrsamples * M_PI * info->volume * M_PI * info->volume); 
        if (MASTER(cr)){
            fprintf(stderr, "\rCalculating reciprocal error part 2 ... %3.0f%%",
                    100.0*(i+1)/stoplocal);

        }
       
    }

    if (MASTER(cr))
        fprintf(stderr, "\n");


#ifdef TAKETIME
    if (MASTER(cr))
    {
        t1= MPI_Wtime() - t0;
        fprintf(fp_out, "Recip. err. est. took   : %lf s\n", t1);
    }
#endif
   
#ifdef DEBUG
    if (PAR(cr))
    {
        fprintf(stderr, "Node %3d: nx=[%3d...%3d]  e_rec3=%e\n", 
                cr->nodeid, startlocal, stoplocal, e_rec3);
    }
#endif
   

/*
#ifdef GMX_MPI
    MPI_Barrier(MPI_COMM_WORLD);
#endif
  */ 

#ifdef TAKETIME
    if (MASTER(cr))
    {
        t2= MPI_Wtime() - t0;
        fprintf(fp_out, "barrier   : %lf s\n", t2-t1);
    }
#endif

    if (PAR(cr))
    {
        gmx_sum(1,&e_rec1,cr);
        gmx_sum(1,&e_rec2,cr);
        gmx_sum(1,&e_rec3,cr);
    }
    
#ifdef TAKETIME
    if (MASTER(cr))
        fprintf(fp_out, "final reduce : %lf s\n", MPI_Wtime() - t0-t2);
#endif
    /* e_rec1*=8.0 * q2_all / info->volume / info->volume / nr ;
       e_rec2*=  q2_all / M_PI / M_PI / info->volume / info->volume / nr ;
       e_rec3/= M_PI * M_PI * info->volume * info->volume * nr ; 
     */
    e_rec=sqrt(e_rec1+e_rec2+e_rec3);
    
    
    return ONE_4PI_EPS0 * e_rec;
}