real numerical_deriv(int nx,real x[],real y[],real fity[],real combined[],real dy[], real tendInt,int nsmooth) { FILE *tmpfp; int i,nbegin,i0,i1; real fac,fx,fy,integralSmth; nbegin = calc_nbegin(nx,x,tendInt); if (nsmooth == 0) { for(i=0; (i<nbegin); i++) combined[i]=y[i]; fac = y[nbegin]/fity[nbegin]; printf("scaling fitted curve by %g\n",fac); for(i=nbegin; (i<nx); i++) combined[i]=fity[i]*fac; } else { i0 = max(0,nbegin); i1 = min(nx-1,nbegin+nsmooth); printf("Making smooth transition from %d thru %d\n",i0,i1); for(i=0; (i<i0); i++) combined[i]=y[i]; for(i=i0; (i<=i1); i++) { fx = (i1-i)/(real)(i1-i0); fy = (i-i0)/(real)(i1-i0); if (debug) fprintf(debug,"x: %g factors for smoothing: %10g %10g\n",x[i],fx,fy); combined[i] = fx*y[i] + fy*fity[i]; } for(i=i1+1; (i<nx); i++) combined[i]=fity[i]; } tmpfp = ffopen("integral_smth.xvg","w"); integralSmth=print_and_integrate(tmpfp,nx,x[1]-x[0],combined,NULL,1); printf("SMOOTH integral = %10.5e\n",integralSmth); dy[0] = (combined[1]-combined[0])/(x[1]-x[0]); for(i=1; (i<nx-1); i++) { dy[i] = (combined[i+1]-combined[i-1])/(x[i+1]-x[i-1]); } dy[nx-1] = (combined[nx-1]-combined[nx-2])/(x[nx-1]-x[nx-2]); for(i=0; (i<nx); i++) dy[i] *= -1; return integralSmth; }
int gmx_dielectric(int argc, char *argv[]) { const char *desc[] = { "[THISMODULE] calculates frequency dependent dielectric constants", "from the autocorrelation function of the total dipole moment in", "your simulation. This ACF can be generated by [gmx-dipoles].", "The functional forms of the available functions are:[PAR]", "One parameter: y = [EXP]-a[SUB]1[sub] x[exp],[BR]", "Two parameters: y = a[SUB]2[sub] [EXP]-a[SUB]1[sub] x[exp],[BR]", "Three parameters: y = a[SUB]2[sub] [EXP]-a[SUB]1[sub] x[exp] + (1 - a[SUB]2[sub]) [EXP]-a[SUB]3[sub] x[exp].[BR]", "Start values for the fit procedure can be given on the command line.", "It is also possible to fix parameters at their start value, use [TT]-fix[tt]", "with the number of the parameter you want to fix.", "[PAR]", "Three output files are generated, the first contains the ACF,", "an exponential fit to it with 1, 2 or 3 parameters, and the", "numerical derivative of the combination data/fit.", "The second file contains the real and imaginary parts of the", "frequency-dependent dielectric constant, the last gives a plot", "known as the Cole-Cole plot, in which the imaginary", "component is plotted as a function of the real component.", "For a pure exponential relaxation (Debye relaxation) the latter", "plot should be one half of a circle." }; t_filenm fnm[] = { { efXVG, "-f", "dipcorr", ffREAD }, { efXVG, "-d", "deriv", ffWRITE }, { efXVG, "-o", "epsw", ffWRITE }, { efXVG, "-c", "cole", ffWRITE } }; #define NFILE asize(fnm) output_env_t oenv; int i, j, nx, ny, nxtail, eFitFn, nfitparm; real dt, integral, fitintegral, *fitparms, fac, rffac; double **yd; real **y; const char *legend[] = { "Correlation", "Std. Dev.", "Fit", "Combined", "Derivative" }; static int fix = 0, bFour = 0, bX = 1, nsmooth = 3; static real tendInt = 5.0, tbegin = 5.0, tend = 500.0; static real A = 0.5, tau1 = 10.0, tau2 = 1.0, eps0 = 80, epsRF = 78.5, tail = 500.0; real lambda; t_pargs pa[] = { { "-fft", FALSE, etBOOL, {&bFour}, "use fast fourier transform for correlation function" }, { "-x1", FALSE, etBOOL, {&bX}, "use first column as [IT]x[it]-axis rather than first data set" }, { "-eint", FALSE, etREAL, {&tendInt}, "Time to end the integration of the data and start to use the fit"}, { "-bfit", FALSE, etREAL, {&tbegin}, "Begin time of fit" }, { "-efit", FALSE, etREAL, {&tend}, "End time of fit" }, { "-tail", FALSE, etREAL, {&tail}, "Length of function including data and tail from fit" }, { "-A", FALSE, etREAL, {&A}, "Start value for fit parameter A" }, { "-tau1", FALSE, etREAL, {&tau1}, "Start value for fit parameter [GRK]tau[grk]1" }, { "-tau2", FALSE, etREAL, {&tau2}, "Start value for fit parameter [GRK]tau[grk]2" }, { "-eps0", FALSE, etREAL, {&eps0}, "[GRK]epsilon[grk]0 of your liquid" }, { "-epsRF", FALSE, etREAL, {&epsRF}, "[GRK]epsilon[grk] of the reaction field used in your simulation. A value of 0 means infinity." }, { "-fix", FALSE, etINT, {&fix}, "Fix parameters at their start values, A (2), tau1 (1), or tau2 (4)" }, { "-ffn", FALSE, etENUM, {s_ffn}, "Fit function" }, { "-nsmooth", FALSE, etINT, {&nsmooth}, "Number of points for smoothing" } }; if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW | PCA_BE_NICE, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv)) { return 0; } please_cite(stdout, "Spoel98a"); printf("WARNING: non-polarizable models can never yield an infinite\n" "dielectric constant that is different from 1. This is incorrect\n" "in the reference given above (Spoel98a).\n\n"); nx = read_xvg(opt2fn("-f", NFILE, fnm), &yd, &ny); dt = yd[0][1] - yd[0][0]; nxtail = min(tail/dt, nx); printf("Read data set containing %d colums and %d rows\n", ny, nx); printf("Assuming (from data) that timestep is %g, nxtail = %d\n", dt, nxtail); snew(y, 6); for (i = 0; (i < ny); i++) { snew(y[i], max(nx, nxtail)); } for (i = 0; (i < nx); i++) { y[0][i] = yd[0][i]; for (j = 1; (j < ny); j++) { y[j][i] = yd[j][i]; } } if (nxtail > nx) { for (i = nx; (i < nxtail); i++) { y[0][i] = dt*i+y[0][0]; for (j = 1; (j < ny); j++) { y[j][i] = 0.0; } } nx = nxtail; } /* We have read a file WITHOUT standard deviations, so we make our own... */ if (ny == 2) { printf("Creating standard deviation numbers ...\n"); srenew(y, 3); snew(y[2], nx); fac = 1.0/((real)nx); for (i = 0; (i < nx); i++) { y[2][i] = fac; } } eFitFn = sffn2effn(s_ffn); nfitparm = nfp_ffn[eFitFn]; snew(fitparms, 4); fitparms[0] = tau1; if (nfitparm > 1) { fitparms[1] = A; } if (nfitparm > 2) { fitparms[2] = tau2; } snew(y[3], nx); snew(y[4], nx); snew(y[5], nx); integral = print_and_integrate(NULL, calc_nbegin(nx, y[0], tbegin), dt, y[1], NULL, 1); integral += do_lmfit(nx, y[1], y[2], dt, y[0], tbegin, tend, oenv, TRUE, eFitFn, fitparms, fix); for (i = 0; i < nx; i++) { y[3][i] = fit_function(eFitFn, fitparms, y[0][i]); } if (epsRF == 0) { /* This means infinity! */ lambda = 0; rffac = 1; } else { lambda = (eps0 - 1.0)/(2*epsRF - 1.0); rffac = (2*epsRF+eps0)/(2*epsRF+1); } printf("DATA INTEGRAL: %5.1f, tauD(old) = %5.1f ps, " "tau_slope = %5.1f, tau_slope,D = %5.1f ps\n", integral, integral*rffac, fitparms[0], fitparms[0]*rffac); printf("tau_D from tau1 = %8.3g , eps(Infty) = %8.3f\n", fitparms[0]*(1 + fitparms[1]*lambda), 1 + ((1 - fitparms[1])*(eps0 - 1))/(1 + fitparms[1]*lambda)); fitintegral = numerical_deriv(nx, y[0], y[1], y[3], y[4], y[5], tendInt, nsmooth); printf("FIT INTEGRAL (tau_M): %5.1f, tau_D = %5.1f\n", fitintegral, fitintegral*rffac); /* Now we have the negative gradient of <Phi(0) Phi(t)> */ write_xvg(opt2fn("-d", NFILE, fnm), "Data", nx-1, 6, y, legend, oenv); /* Do FFT and analysis */ do_four(opt2fn("-o", NFILE, fnm), opt2fn("-c", NFILE, fnm), nx-1, y[0], y[5], eps0, epsRF, oenv); do_view(oenv, opt2fn("-o", NFILE, fnm), "-nxy"); do_view(oenv, opt2fn("-c", NFILE, fnm), NULL); do_view(oenv, opt2fn("-d", NFILE, fnm), "-nxy"); return 0; }
real fit_acf(int ncorr, int fitfn, const gmx_output_env_t *oenv, gmx_bool bVerbose, real tbeginfit, real tendfit, real dt, real c1[], real *fit) { double fitparm[3]; double tStart, tail_corr, sum, sumtot = 0, c_start, ct_estimate; real *sig; int i, j, jmax, nf_int; gmx_bool bPrint; bPrint = bVerbose || bDebugMode(); if (bPrint) { printf("COR:\n"); } if (tendfit <= 0) { tendfit = ncorr*dt; } nf_int = std::min(ncorr, (int)(tendfit/dt)); sum = print_and_integrate(debug, nf_int, dt, c1, NULL, 1); if (bPrint) { printf("COR: Correlation time (plain integral from %6.3f to %6.3f ps) = %8.5f ps\n", 0.0, dt*nf_int, sum); printf("COR: Relaxation times are computed as fit to an exponential:\n"); printf("COR: %s\n", effnDescription(fitfn)); printf("COR: Fit to correlation function from %6.3f ps to %6.3f ps, results in a\n", tbeginfit, std::min(ncorr*dt, tendfit)); } tStart = 0; if (bPrint) { printf("COR:%11s%11s%11s%11s%11s%11s%11s\n", "Fit from", "Integral", "Tail Value", "Sum (ps)", " a1 (ps)", (effnNparams(fitfn) >= 2) ? " a2 ()" : "", (effnNparams(fitfn) >= 3) ? " a3 (ps)" : ""); } snew(sig, ncorr); if (tbeginfit > 0) { jmax = 3; } else { jmax = 1; } for (j = 0; ((j < jmax) && (tStart < tendfit) && (tStart < ncorr*dt)); j++) { /* Estimate the correlation time for better fitting */ c_start = -1; ct_estimate = 0; for (i = 0; (i < ncorr) && (dt*i < tStart || c1[i] > 0); i++) { if (c_start < 0) { if (dt*i >= tStart) { c_start = c1[i]; ct_estimate = 0.5*c1[i]; } } else { ct_estimate += c1[i]; } } if (c_start > 0) { ct_estimate *= dt/c_start; } else { /* The data is strange, so we need to choose somehting */ ct_estimate = tendfit; } if (debug) { fprintf(debug, "tStart %g ct_estimate: %g\n", tStart, ct_estimate); } if (fitfn == effnEXPEXP) { fitparm[0] = 0.002*ncorr*dt; fitparm[1] = 0.95; fitparm[2] = 0.2*ncorr*dt; } else { /* Good initial guess, this increases the probability of convergence */ fitparm[0] = ct_estimate; fitparm[1] = 1.0; fitparm[2] = 1.0; } /* Generate more or less appropriate sigma's */ for (i = 0; i < ncorr; i++) { sig[i] = sqrt(ct_estimate+dt*i); } nf_int = std::min(ncorr, (int)((tStart+1e-4)/dt)); sum = print_and_integrate(debug, nf_int, dt, c1, NULL, 1); tail_corr = do_lmfit(ncorr, c1, sig, dt, NULL, tStart, tendfit, oenv, bDebugMode(), fitfn, fitparm, 0, NULL); sumtot = sum+tail_corr; if (fit && ((jmax == 1) || (j == 1))) { double mfp[3]; for (i = 0; (i < 3); i++) { mfp[i] = fitparm[i]; } for (i = 0; (i < ncorr); i++) { fit[i] = lmcurves[fitfn](i*dt, mfp); } } if (bPrint) { printf("COR:%11.4e%11.4e%11.4e%11.4e", tStart, sum, tail_corr, sumtot); for (i = 0; (i < effnNparams(fitfn)); i++) { printf(" %11.4e", fitparm[i]); } printf("\n"); } tStart += tbeginfit; } sfree(sig); return sumtot; }
void low_do_autocorr(const char *fn,const output_env_t oenv,const char *title, int nframes,int nitem,int nout,real **c1, real dt,unsigned long mode,int nrestart, gmx_bool bAver,gmx_bool bNormalize, gmx_bool bVerbose,real tbeginfit,real tendfit, int eFitFn,int nskip) { FILE *fp,*gp=NULL; int i,k,nfour; real *csum; real *ctmp,*fit; real c0,sum,Ct2av,Ctav; gmx_bool bFour = acf.bFour; /* Check flags and parameters */ nout = get_acfnout(); if (nout == -1) nout = acf.nout = (nframes+1)/2; else if (nout > nframes) nout=nframes; if (MODE(eacCos) && MODE(eacVector)) gmx_fatal(FARGS,"Incompatible options bCos && bVector (%s, %d)", __FILE__,__LINE__); if ((MODE(eacP3) || MODE(eacRcross)) && bFour) { fprintf(stderr,"Can't combine mode %lu with FFT, turning off FFT\n",mode); bFour = FALSE; } if (MODE(eacNormal) && MODE(eacVector)) gmx_fatal(FARGS,"Incompatible mode bits: normal and vector (or Legendre)"); /* Print flags and parameters */ if (bVerbose) { printf("Will calculate %s of %d thingies for %d frames\n", title ? title : "autocorrelation",nitem,nframes); printf("bAver = %s, bFour = %s bNormalize= %s\n", bool_names[bAver],bool_names[bFour],bool_names[bNormalize]); printf("mode = %lu, dt = %g, nrestart = %d\n",mode,dt,nrestart); } if (bFour) { c0 = log((double)nframes)/log(2.0); k = c0; if (k < c0) k++; k++; nfour = 1<<k; if (debug) fprintf(debug,"Using FFT to calculate %s, #points for FFT = %d\n", title,nfour); /* Allocate temp arrays */ snew(csum,nfour); snew(ctmp,nfour); } else { nfour = 0; /* To keep the compiler happy */ snew(csum,nframes); snew(ctmp,nframes); } /* Loop over items (e.g. molecules or dihedrals) * In this loop the actual correlation functions are computed, but without * normalizing them. */ k = max(1,pow(10,(int)(log(nitem)/log(100)))); for(i=0; i<nitem; i++) { if (bVerbose && ((i%k==0 || i==nitem-1))) fprintf(stderr,"\rThingie %d",i+1); if (bFour) do_four_core(mode,nfour,nframes,nframes,c1[i],csum,ctmp); else do_ac_core(nframes,nout,ctmp,c1[i],nrestart,mode); } if (bVerbose) fprintf(stderr,"\n"); sfree(ctmp); sfree(csum); if (fn) { snew(fit,nout); fp=xvgropen(fn,title,"Time (ps)","C(t)",oenv); } else { fit = NULL; fp = NULL; } if (bAver) { if (nitem > 1) average_acf(bVerbose,nframes,nitem,c1); if (bNormalize) normalize_acf(nout,c1[0]); if (eFitFn != effnNONE) { fit_acf(nout,eFitFn,oenv,fn!=NULL,tbeginfit,tendfit,dt,c1[0],fit); sum = print_and_integrate(fp,nout,dt,c1[0],fit,1); } else { sum = print_and_integrate(fp,nout,dt,c1[0],NULL,1); if (bVerbose) printf("Correlation time (integral over corrfn): %g (ps)\n",sum); } } else { /* Not averaging. Normalize individual ACFs */ Ctav = Ct2av = 0; if (debug) gp = xvgropen("ct-distr.xvg","Correlation times","item","time (ps)",oenv); for(i=0; i<nitem; i++) { if (bNormalize) normalize_acf(nout,c1[i]); if (eFitFn != effnNONE) { fit_acf(nout,eFitFn,oenv,fn!=NULL,tbeginfit,tendfit,dt,c1[i],fit); sum = print_and_integrate(fp,nout,dt,c1[i],fit,1); } else { sum = print_and_integrate(fp,nout,dt,c1[i],NULL,1); if (debug) fprintf(debug, "CORRelation time (integral over corrfn %d): %g (ps)\n", i,sum); } Ctav += sum; Ct2av += sum*sum; if (debug) fprintf(gp,"%5d %.3f\n",i,sum); } if (debug) ffclose(gp); if (nitem > 1) { Ctav /= nitem; Ct2av /= nitem; printf("Average correlation time %.3f Std. Dev. %.3f Error %.3f (ps)\n", Ctav,sqrt((Ct2av - sqr(Ctav))), sqrt((Ct2av - sqr(Ctav))/(nitem-1))); } } if (fp) ffclose(fp); sfree(fit); }
real fit_acf(int ncorr,int fitfn,const output_env_t oenv,gmx_bool bVerbose, real tbeginfit,real tendfit,real dt,real c1[],real *fit) { real fitparm[3]; real tStart,tail_corr,sum,sumtot=0,ct_estimate,*sig; int i,j,jmax,nf_int; gmx_bool bPrint; bPrint = bVerbose || bDebugMode(); if (bPrint) printf("COR:\n"); if (tendfit <= 0) tendfit = ncorr*dt; nf_int = min(ncorr,(int)(tendfit/dt)); sum = print_and_integrate(debug,nf_int,dt,c1,NULL,1); /* Estimate the correlation time for better fitting */ ct_estimate = 0.5*c1[0]; for(i=1; (i<ncorr) && (c1[i]>0); i++) ct_estimate += c1[i]; ct_estimate *= dt/c1[0]; if (bPrint) { printf("COR: Correlation time (plain integral from %6.3f to %6.3f ps) = %8.5f ps\n", 0.0,dt*nf_int,sum); printf("COR: Relaxation times are computed as fit to an exponential:\n"); printf("COR: %s\n",longs_ffn[fitfn]); printf("COR: Fit to correlation function from %6.3f ps to %6.3f ps, results in a\n",tbeginfit,min(ncorr*dt,tendfit)); } tStart = 0; if (bPrint) printf("COR:%11s%11s%11s%11s%11s%11s%11s\n", "Fit from","Integral","Tail Value","Sum (ps)"," a1 (ps)", (nfp_ffn[fitfn]>=2) ? " a2 ()" : "", (nfp_ffn[fitfn]>=3) ? " a3 (ps)" : ""); if (tbeginfit > 0) jmax = 3; else jmax = 1; if (fitfn == effnEXP3) { fitparm[0] = 0.002*ncorr*dt; fitparm[1] = 0.95; fitparm[2] = 0.2*ncorr*dt; } else { /* Good initial guess, this increases the probability of convergence */ fitparm[0] = ct_estimate; fitparm[1] = 1.0; fitparm[2] = 1.0; } /* Generate more or less appropriate sigma's */ snew(sig,ncorr); for(i=0; i<ncorr; i++) sig[i] = sqrt(ct_estimate+dt*i); for(j=0; ((j<jmax) && (tStart < tendfit)); j++) { /* Use the previous fitparm as starting values for the next fit */ nf_int = min(ncorr,(int)((tStart+1e-4)/dt)); sum = print_and_integrate(debug,nf_int,dt,c1,NULL,1); tail_corr = do_lmfit(ncorr,c1,sig,dt,NULL,tStart,tendfit,oenv, bDebugMode(),fitfn,fitparm,0); sumtot = sum+tail_corr; if (fit && ((jmax == 1) || (j == 1))) for(i=0; (i<ncorr); i++) fit[i] = fit_function(fitfn,fitparm,i*dt); if (bPrint) { printf("COR:%11.4e%11.4e%11.4e%11.4e",tStart,sum,tail_corr,sumtot); for(i=0; (i<nfp_ffn[fitfn]); i++) printf(" %11.4e",fitparm[i]); printf("\n"); } tStart += tbeginfit; } sfree(sig); return sumtot; }
static void do_rdf(char *fnNDX,char *fnTPS,char *fnTRX, char *fnRDF,char *fnCNRDF, char *fnHQ, bool bCM,char **rdft,bool bXY,bool bPBC,bool bNormalize, real cutoff,real binwidth,real fade,int ng) { FILE *fp; int status; char outf1[STRLEN],outf2[STRLEN]; char title[STRLEN],gtitle[STRLEN]; int g,natoms,i,j,k,nbin,j0,j1,n,nframes; int **count; char **grpname; int *isize,isize_cm=0,nrdf=0,max_i,isize0,isize_g; atom_id **index,*index_cm=NULL; #if (defined SIZEOF_LONG_LONG_INT) && (SIZEOF_LONG_LONG_INT >= 8) long long int *sum; #else double *sum; #endif real t,rmax2,cut2,r,r2,invhbinw,normfac; real segvol,spherevol,prev_spherevol,**rdf; rvec *x,dx,*x0=NULL,*x_i1,xi; real *inv_segvol,invvol,invvol_sum,rho; bool *bExcl,bTop,bNonSelfExcl; matrix box,box_pbc; int **npairs; atom_id ix,jx,***pairs; t_topology *top=NULL; int ePBC=-1; t_block *mols=NULL; t_blocka *excl; t_atom *atom=NULL; t_pbc pbc; int *is=NULL,**coi=NULL,cur,mol,i1,res,a; excl=NULL; if (fnTPS) { snew(top,1); bTop=read_tps_conf(fnTPS,title,top,&ePBC,&x,NULL,box,TRUE); if (bTop && !bCM) /* get exclusions from topology */ excl = &(top->excls); } snew(grpname,ng+1); snew(isize,ng+1); snew(index,ng+1); fprintf(stderr,"\nSelect a reference group and %d group%s\n", ng,ng==1?"":"s"); if (fnTPS) { get_index(&(top->atoms),fnNDX,ng+1,isize,index,grpname); atom = top->atoms.atom; } else { rd_index(fnNDX,ng+1,isize,index,grpname); } if (rdft[0][0] != 'a') { /* Split up all the groups in molecules or residues */ switch (rdft[0][0]) { case 'm': mols = &top->mols; break; case 'r': atom = top->atoms.atom; break; default: gmx_fatal(FARGS,"Unknown rdf option '%s'",rdft[0]); } snew(is,ng+1); snew(coi,ng+1); for(g=(bCM ? 1 : 0); g<ng+1; g++) { snew(coi[g],isize[g]+1); is[g] = 0; cur = -1; mol = 0; for(i=0; i<isize[g]; i++) { a = index[g][i]; if (rdft[0][0] == 'm') { /* Check if the molecule number has changed */ i1 = mols->index[mol+1]; while(a >= i1) { mol++; i1 = mols->index[mol+1]; } if (mol != cur) { coi[g][is[g]++] = i; cur = mol; } } else if (rdft[0][0] == 'r') { /* Check if the residue number has changed */ res = atom[a].resnr; if (res != cur) { coi[g][is[g]++] = i; cur = res; } } } coi[g][is[g]] = i; srenew(coi[g],is[g]+1); printf("Group '%s' of %d atoms consists of %d %s\n", grpname[g],isize[g],is[g], (rdft[0][0]=='m' ? "molecules" : "residues")); } } else if (bCM) { snew(is,1); snew(coi,1); } if (bCM) { is[0] = 1; snew(coi[0],is[0]+1); coi[0][0] = 0; coi[0][1] = isize[0]; isize0 = is[0]; snew(x0,isize0); } else if (rdft[0][0] != 'a') { isize0 = is[0]; snew(x0,isize0); } else { isize0 = isize[0]; } natoms=read_first_x(&status,fnTRX,&t,&x,box); if ( !natoms ) gmx_fatal(FARGS,"Could not read coordinates from statusfile\n"); if (fnTPS) /* check with topology */ if ( natoms > top->atoms.nr ) gmx_fatal(FARGS,"Trajectory (%d atoms) does not match topology (%d atoms)", natoms,top->atoms.nr); /* check with index groups */ for (i=0; i<ng+1; i++) for (j=0; j<isize[i]; j++) if ( index[i][j] >= natoms ) gmx_fatal(FARGS,"Atom index (%d) in index group %s (%d atoms) larger " "than number of atoms in trajectory (%d atoms)", index[i][j],grpname[i],isize[i],natoms); /* initialize some handy things */ copy_mat(box,box_pbc); if (bXY) { check_box_c(box); /* Make sure the z-height does not influence the cut-off */ box_pbc[ZZ][ZZ] = 2*max(box[XX][XX],box[YY][YY]); } if (bPBC) rmax2 = 0.99*0.99*max_cutoff2(bXY ? epbcXY : epbcXYZ,box_pbc); else rmax2 = sqr(3*max(box[XX][XX],max(box[YY][YY],box[ZZ][ZZ]))); if (debug) fprintf(debug,"rmax2 = %g\n",rmax2); /* We use the double amount of bins, so we can correctly * write the rdf and rdf_cn output at i*binwidth values. */ nbin = (int)(sqrt(rmax2) * 2 / binwidth); invhbinw = 2.0 / binwidth; cut2 = sqr(cutoff); snew(count,ng); snew(pairs,ng); snew(npairs,ng); snew(bExcl,natoms); max_i = 0; for(g=0; g<ng; g++) { if (isize[g+1] > max_i) max_i = isize[g+1]; /* this is THE array */ snew(count[g],nbin+1); /* make pairlist array for groups and exclusions */ snew(pairs[g],isize[0]); snew(npairs[g],isize[0]); for(i=0; i<isize[0]; i++) { /* We can only have exclusions with atomic rdfs */ if (!(bCM || rdft[0][0] != 'a')) { ix = index[0][i]; for(j=0; j < natoms; j++) bExcl[j] = FALSE; /* exclusions? */ if (excl) for( j = excl->index[ix]; j < excl->index[ix+1]; j++) bExcl[excl->a[j]]=TRUE; k = 0; snew(pairs[g][i], isize[g+1]); bNonSelfExcl = FALSE; for(j=0; j<isize[g+1]; j++) { jx = index[g+1][j]; if (!bExcl[jx]) pairs[g][i][k++]=jx; else if (ix != jx) /* Check if we have exclusions other than self exclusions */ bNonSelfExcl = TRUE; } if (bNonSelfExcl) { npairs[g][i]=k; srenew(pairs[g][i],npairs[g][i]); } else { /* Save a LOT of memory and some cpu cycles */ npairs[g][i]=-1; sfree(pairs[g][i]); } } else { npairs[g][i]=-1; } } } sfree(bExcl); snew(x_i1,max_i); nframes = 0; invvol_sum = 0; do { /* Must init pbc every step because of pressure coupling */ copy_mat(box,box_pbc); if (bPBC) { if (top != NULL) rm_pbc(&top->idef,ePBC,natoms,box,x,x); if (bXY) { check_box_c(box); clear_rvec(box_pbc[ZZ]); } set_pbc(&pbc,ePBC,box_pbc); if (bXY) /* Set z-size to 1 so we get the surface iso the volume */ box_pbc[ZZ][ZZ] = 1; } invvol = 1/det(box_pbc); invvol_sum += invvol; if (bCM) { /* Calculate center of mass of the whole group */ calc_comg(is[0],coi[0],index[0],TRUE ,atom,x,x0); } else if (rdft[0][0] != 'a') { calc_comg(is[0],coi[0],index[0],rdft[0][6]=='m',atom,x,x0); } for(g=0; g<ng; g++) { if (rdft[0][0] == 'a') { /* Copy the indexed coordinates to a continuous array */ for(i=0; i<isize[g+1]; i++) copy_rvec(x[index[g+1][i]],x_i1[i]); } else { /* Calculate the COMs/COGs and store in x_i1 */ calc_comg(is[g+1],coi[g+1],index[g+1],rdft[0][6]=='m',atom,x,x_i1); } for(i=0; i<isize0; i++) { if (bCM || rdft[0][0] != 'a') { copy_rvec(x0[i],xi); } else { copy_rvec(x[index[0][i]],xi); } if (rdft[0][0] == 'a' && npairs[g][i] >= 0) { /* Expensive loop, because of indexing */ for(j=0; j<npairs[g][i]; j++) { jx=pairs[g][i][j]; if (bPBC) pbc_dx(&pbc,xi,x[jx],dx); else rvec_sub(xi,x[jx],dx); if (bXY) r2 = dx[XX]*dx[XX] + dx[YY]*dx[YY]; else r2=iprod(dx,dx); if (r2>cut2 && r2<=rmax2) count[g][(int)(sqrt(r2)*invhbinw)]++; } } else { /* Cheaper loop, no exclusions */ if (rdft[0][0] == 'a') isize_g = isize[g+1]; else isize_g = is[g+1]; for(j=0; j<isize_g; j++) { if (bPBC) pbc_dx(&pbc,xi,x_i1[j],dx); else rvec_sub(xi,x_i1[j],dx); if (bXY) r2 = dx[XX]*dx[XX] + dx[YY]*dx[YY]; else r2=iprod(dx,dx); if (r2>cut2 && r2<=rmax2) count[g][(int)(sqrt(r2)*invhbinw)]++; } } } } nframes++; } while (read_next_x(status,&t,natoms,x,box)); fprintf(stderr,"\n"); close_trj(status); sfree(x); /* Average volume */ invvol = invvol_sum/nframes; /* Calculate volume of sphere segments or length of circle segments */ snew(inv_segvol,(nbin+1)/2); prev_spherevol=0; for(i=0; (i<(nbin+1)/2); i++) { r = (i + 0.5)*binwidth; if (bXY) { spherevol=M_PI*r*r; } else { spherevol=(4.0/3.0)*M_PI*r*r*r; } segvol=spherevol-prev_spherevol; inv_segvol[i]=1.0/segvol; prev_spherevol=spherevol; } snew(rdf,ng); for(g=0; g<ng; g++) { /* We have to normalize by dividing by the number of frames */ if (rdft[0][0] == 'a') normfac = 1.0/(nframes*invvol*isize0*isize[g+1]); else normfac = 1.0/(nframes*invvol*isize0*is[g+1]); /* Do the normalization */ nrdf = max((nbin+1)/2,1+2*fade/binwidth); snew(rdf[g],nrdf); for(i=0; i<(nbin+1)/2; i++) { r = i*binwidth; if (i == 0) j = count[g][0]; else j = count[g][i*2-1] + count[g][i*2]; if ((fade > 0) && (r >= fade)) rdf[g][i] = 1 + (j*inv_segvol[i]*normfac-1)*exp(-16*sqr(r/fade-1)); else { if (bNormalize) rdf[g][i] = j*inv_segvol[i]*normfac; else rdf[g][i] = j/(binwidth*isize0*nframes); } } for( ; (i<nrdf); i++) rdf[g][i] = 1.0; } if (rdft[0][0] == 'a') { sprintf(gtitle,"Radial distribution"); } else { sprintf(gtitle,"Radial distribution of %s %s", rdft[0][0]=='m' ? "molecule" : "residue", rdft[0][6]=='m' ? "COM" : "COG"); } fp=xvgropen(fnRDF,gtitle,"r",""); if (ng==1) { if (bPrintXvgrCodes()) fprintf(fp,"@ subtitle \"%s%s - %s\"\n", grpname[0],bCM ? " COM" : "",grpname[1]); } else { if (bPrintXvgrCodes()) fprintf(fp,"@ subtitle \"reference %s%s\"\n", grpname[0],bCM ? " COM" : ""); xvgr_legend(fp,ng,grpname+1); } for(i=0; (i<nrdf); i++) { fprintf(fp,"%10g",i*binwidth); for(g=0; g<ng; g++) fprintf(fp," %10g",rdf[g][i]); fprintf(fp,"\n"); } ffclose(fp); do_view(fnRDF,NULL); /* h(Q) function: fourier transform of rdf */ if (fnHQ) { int nhq = 401; real *hq,*integrand,Q; /* Get a better number density later! */ rho = isize[1]*invvol; snew(hq,nhq); snew(integrand,nrdf); for(i=0; (i<nhq); i++) { Q = i*0.5; integrand[0] = 0; for(j=1; (j<nrdf); j++) { r = j*binwidth; integrand[j] = (Q == 0) ? 1.0 : sin(Q*r)/(Q*r); integrand[j] *= 4.0*M_PI*rho*r*r*(rdf[0][j]-1.0); } hq[i] = print_and_integrate(debug,nrdf,binwidth,integrand,NULL,0); } fp=xvgropen(fnHQ,"h(Q)","Q(/nm)","h(Q)"); for(i=0; (i<nhq); i++) fprintf(fp,"%10g %10g\n",i*0.5,hq[i]); ffclose(fp); do_view(fnHQ,NULL); sfree(hq); sfree(integrand); } if (fnCNRDF) { normfac = 1.0/(isize0*nframes); fp=xvgropen(fnCNRDF,"Cumulative Number RDF","r","number"); if (ng==1) { if (bPrintXvgrCodes()) fprintf(fp,"@ subtitle \"%s-%s\"\n",grpname[0],grpname[1]); } else { if (bPrintXvgrCodes()) fprintf(fp,"@ subtitle \"reference %s\"\n",grpname[0]); xvgr_legend(fp,ng,grpname+1); } snew(sum,ng); for(i=0; (i<=nbin/2); i++) { fprintf(fp,"%10g",i*binwidth); for(g=0; g<ng; g++) { fprintf(fp," %10g",(real)((double)sum[g]*normfac)); if (i*2+1 < nbin) sum[g] += count[g][i*2] + count[g][i*2+1]; } fprintf(fp,"\n"); } ffclose(fp); sfree(sum); do_view(fnCNRDF,NULL); } for(g=0; g<ng; g++) sfree(rdf[g]); sfree(rdf); }
void low_do_autocorr(const char *fn, const gmx_output_env_t *oenv, const char *title, int nframes, int nitem, int nout, real **c1, real dt, unsigned long mode, int nrestart, gmx_bool bAver, gmx_bool bNormalize, gmx_bool bVerbose, real tbeginfit, real tendfit, int eFitFn) { FILE *fp, *gp = NULL; int i; real *csum; real *ctmp, *fit; real sum, Ct2av, Ctav; gmx_bool bFour = acf.bFour; /* Check flags and parameters */ nout = get_acfnout(); if (nout == -1) { nout = acf.nout = (nframes+1)/2; } else if (nout > nframes) { nout = nframes; } if (MODE(eacCos) && MODE(eacVector)) { gmx_fatal(FARGS, "Incompatible options bCos && bVector (%s, %d)", __FILE__, __LINE__); } if ((MODE(eacP3) || MODE(eacRcross)) && bFour) { if (bVerbose) { fprintf(stderr, "Can't combine mode %lu with FFT, turning off FFT\n", mode); } bFour = FALSE; } if (MODE(eacNormal) && MODE(eacVector)) { gmx_fatal(FARGS, "Incompatible mode bits: normal and vector (or Legendre)"); } /* Print flags and parameters */ if (bVerbose) { printf("Will calculate %s of %d thingies for %d frames\n", title ? title : "autocorrelation", nitem, nframes); printf("bAver = %s, bFour = %s bNormalize= %s\n", gmx::boolToString(bAver), gmx::boolToString(bFour), gmx::boolToString(bNormalize)); printf("mode = %lu, dt = %g, nrestart = %d\n", mode, dt, nrestart); } /* Allocate temp arrays */ snew(csum, nframes); snew(ctmp, nframes); /* Loop over items (e.g. molecules or dihedrals) * In this loop the actual correlation functions are computed, but without * normalizing them. */ for (int i = 0; i < nitem; i++) { if (bVerbose && (((i % 100) == 0) || (i == nitem-1))) { fprintf(stderr, "\rThingie %d", i+1); fflush(stderr); } if (bFour) { do_four_core(mode, nframes, c1[i], csum, ctmp); } else { do_ac_core(nframes, nout, ctmp, c1[i], nrestart, mode); } } if (bVerbose) { fprintf(stderr, "\n"); } sfree(ctmp); sfree(csum); if (fn) { snew(fit, nout); fp = xvgropen(fn, title, "Time (ps)", "C(t)", oenv); } else { fit = NULL; fp = NULL; } if (bAver) { if (nitem > 1) { average_acf(bVerbose, nframes, nitem, c1); } if (bNormalize) { normalize_acf(nout, c1[0]); } if (eFitFn != effnNONE) { fit_acf(nout, eFitFn, oenv, fn != NULL, tbeginfit, tendfit, dt, c1[0], fit); sum = print_and_integrate(fp, nout, dt, c1[0], fit, 1); } else { sum = print_and_integrate(fp, nout, dt, c1[0], NULL, 1); } if (bVerbose) { printf("Correlation time (integral over corrfn): %g (ps)\n", sum); } } else { /* Not averaging. Normalize individual ACFs */ Ctav = Ct2av = 0; if (debug) { gp = xvgropen("ct-distr.xvg", "Correlation times", "item", "time (ps)", oenv); } for (i = 0; i < nitem; i++) { if (bNormalize) { normalize_acf(nout, c1[i]); } if (eFitFn != effnNONE) { fit_acf(nout, eFitFn, oenv, fn != NULL, tbeginfit, tendfit, dt, c1[i], fit); sum = print_and_integrate(fp, nout, dt, c1[i], fit, 1); } else { sum = print_and_integrate(fp, nout, dt, c1[i], NULL, 1); if (debug) { fprintf(debug, "CORRelation time (integral over corrfn %d): %g (ps)\n", i, sum); } } Ctav += sum; Ct2av += sum*sum; if (debug) { fprintf(gp, "%5d %.3f\n", i, sum); } } if (debug) { xvgrclose(gp); } if (nitem > 1) { Ctav /= nitem; Ct2av /= nitem; printf("Average correlation time %.3f Std. Dev. %.3f Error %.3f (ps)\n", Ctav, std::sqrt((Ct2av - gmx::square(Ctav))), std::sqrt((Ct2av - gmx::square(Ctav))/(nitem-1))); } } if (fp) { xvgrclose(fp); } sfree(fit); }