static void do_dihcorr(const char *fn,int nf,int ndih,real **dih,real dt,
		       int nlist,t_dlist dlist[],real time[],int maxchi,
		       gmx_bool bPhi,gmx_bool bPsi,gmx_bool bChi,gmx_bool bOmega,
                       const output_env_t oenv)
{
  char name1[256],name2[256];
  int  i,j,Xi;
  
  do_autocorr(fn,oenv,"Dihedral Autocorrelation Function",
	      nf,ndih,dih,dt,eacCos,FALSE);
  /* Dump em all */
  j=0;
  for(i=0; (i<nlist); i++) {
    if (bPhi)
      print_one(oenv,"corrphi",dlist[i].name,"Phi ACF for", "C(t)", nf/2,time,
                          dih[j]);
    j++;
  }
  for(i=0; (i<nlist); i++) {
    if (bPsi)
      print_one(oenv,"corrpsi",dlist[i].name,"Psi ACF for","C(t)",nf/2,time,
                dih[j]);
    j++;
  }
  for(i=0; (i<nlist); i++) {
    if (has_dihedral(edOmega,&dlist[i])) {
      if (bOmega)
	print_one(oenv,"corromega",dlist[i].name,"Omega ACF for","C(t)",
                  nf/2,time,dih[j]);
      j++;
    }
  }
  for(Xi=0; (Xi<maxchi); Xi++) {
    sprintf(name1, "corrchi%d", Xi+1);
    sprintf(name2, "Chi%d ACF for", Xi+1);
    for(i=0; (i<nlist); i++) {
      if (dlist[i].atm.Cn[Xi+3] != -1) {
	if (bChi)
	  print_one(oenv,name1,dlist[i].name,name2,"C(t)",nf/2,time,dih[j]);
	j++;
      }
    }
  }
  fprintf(stderr,"\n");
}
int gmx_rotacf(int argc,char *argv[])
{
  static char *desc[] = {
    "g_rotacf calculates the rotational correlation function",
    "for molecules. Three atoms (i,j,k) must be given in the index",
    "file, defining two vectors ij and jk. The rotational acf",
    "is calculated as the autocorrelation function of the vector",
    "n = ij x jk, i.e. the cross product of the two vectors.",
    "Since three atoms span a plane, the order of the three atoms",
    "does not matter. Optionally, controlled by the -d switch, you can",
    "calculate the rotational correlation function for linear molecules",
    "by specifying two atoms (i,j) in the index file.",
    "[PAR]",
    "EXAMPLES[PAR]",
    "g_rotacf -P 1 -nparm 2 -fft -n index -o rotacf-x-P1",
    "-fa expfit-x-P1 -beginfit 2.5 -endfit 20.0[PAR]",
    "This will calculate the rotational correlation function using a first",
    "order Legendre polynomial of the angle of a vector defined by the index",
    "file. The correlation function will be fitted from 2.5 ps till 20.0 ps",
    "to a two parameter exponential",


    ""
  };
  static bool bVec    = FALSE,bAver=TRUE;

  t_pargs pa[] = {
    { "-d",   FALSE, etBOOL, {&bVec},
      "Use index doublets (vectors) for correlation function instead of triplets (planes)" },
    { "-aver",FALSE, etBOOL, {&bAver},
      "Average over molecules" }
  };

  int        status,isize;
  atom_id    *index;
  char       *grpname;
  rvec       *x,*x_s;
  matrix     box;
  real       **c1;
  rvec       xij,xjk,n;
  int        i,m,teller,n_alloc,natoms,nvec,ai,aj,ak;
  unsigned long mode;
  real       t,t0,t1,dt;
  t_topology *top;
  int        ePBC;
  t_filenm   fnm[] = {
    { efTRX, "-f", NULL,  ffREAD  },
    { efTPX, NULL, NULL,  ffREAD },
    { efNDX, NULL, NULL,  ffREAD  },
    { efXVG, "-o", "rotacf",  ffWRITE }
  };
#define NFILE asize(fnm)
  int     npargs;
  t_pargs *ppa;
  
  CopyRight(stderr,argv[0]);
  npargs = asize(pa);
  ppa    = add_acf_pargs(&npargs,pa);
  
  parse_common_args(&argc,argv,PCA_CAN_VIEW | PCA_CAN_TIME | PCA_BE_NICE,
		    NFILE,fnm,npargs,ppa,asize(desc),desc,0,NULL);
  
  rd_index(ftp2fn(efNDX,NFILE,fnm),1,&isize,&index,&grpname);
  
  if (bVec) 
    nvec = isize/2;
  else
    nvec = isize/3;
  
  if (((isize % 3) != 0) && !bVec)
    gmx_fatal(FARGS,"number of index elements not multiple of 3, "
		"these can not be atom triplets\n");
  if (((isize % 2) != 0) && bVec)
    gmx_fatal(FARGS,"number of index elements not multiple of 2, "
		"these can not be atom doublets\n");
  
  top=read_top(ftp2fn(efTPX,NFILE,fnm),&ePBC);
  
  snew(c1,nvec);
  for (i=0; (i<nvec); i++)
    c1[i]=NULL;
  n_alloc=0;

  natoms=read_first_x(&status,ftp2fn(efTRX,NFILE,fnm),&t,&x,box);
  snew(x_s,natoms);
  
  /* Start the loop over frames */
  t1 = t0 = t;
  teller  = 0;
  do {
    if (teller >= n_alloc) {
      n_alloc+=100;
      for (i=0; (i<nvec); i++)
	srenew(c1[i],DIM*n_alloc);
    }
    t1 = t;
    
    /* Remove periodicity */
    rm_pbc(&(top->idef),ePBC,natoms,box,x,x_s);
    
    /* Compute crossproducts for all vectors, if triplets.
     * else, just get the vectors in case of doublets.
     */
    if (bVec == FALSE) {
      for (i=0; (i<nvec); i++) {
	ai=index[3*i];
	aj=index[3*i+1];
	ak=index[3*i+2];
	rvec_sub(x_s[ai],x_s[aj],xij);
	rvec_sub(x_s[aj],x_s[ak],xjk);
	cprod(xij,xjk,n);
	for(m=0; (m<DIM); m++)
	  c1[i][DIM*teller+m]=n[m];
      }
    }
    else {
      for (i=0; (i<nvec); i++) {
	ai=index[2*i];
	aj=index[2*i+1];
	rvec_sub(x_s[ai],x_s[aj],n);
	for(m=0; (m<DIM); m++)
	  c1[i][DIM*teller+m]=n[m];
      }
    }
    /* Increment loop counter */
    teller++;
  } while (read_next_x(status,&t,natoms,x,box));  
  close_trj(status); 
  fprintf(stderr,"\nDone with trajectory\n");
  
  /* Autocorrelation function */
  if (teller < 2)
    fprintf(stderr,"Not enough frames for correlation function\n");
  else {
    dt=(t1 - t0)/(teller-1);
    
    mode = eacVector;
    
    do_autocorr(ftp2fn(efXVG,NFILE,fnm),"Rotational Correlation Function",
		teller,nvec,c1,dt,mode,bAver);
  }

  do_view(ftp2fn(efXVG,NFILE,fnm),NULL);
    
  thanx(stderr);
    
  return 0;
}
Exemple #3
0
int gmx_velacc(int argc, char *argv[])
{
    const char     *desc[] = {
        "[THISMODULE] computes the velocity autocorrelation function.",
        "When the [TT]-m[tt] option is used, the momentum autocorrelation",
        "function is calculated.[PAR]",
        "With option [TT]-mol[tt] the velocity autocorrelation function of",
        "molecules is calculated. In this case the index group should consist",
        "of molecule numbers instead of atom numbers.[PAR]",
        "Be sure that your trajectory contains frames with velocity information",
        "(i.e. [TT]nstvout[tt] was set in your original [REF].mdp[ref] file),",
        "and that the time interval between data collection points is",
        "much shorter than the time scale of the autocorrelation."
    };

    static gmx_bool bMass = FALSE, bMol = FALSE, bRecip = TRUE;
    t_pargs         pa[]  = {
        { "-m", FALSE, etBOOL, {&bMass},
          "Calculate the momentum autocorrelation function" },
        { "-recip", FALSE, etBOOL, {&bRecip},
          "Use cm^-1 on X-axis instead of 1/ps for spectra." },
        { "-mol", FALSE, etBOOL, {&bMol},
          "Calculate the velocity acf of molecules" }
    };

    t_topology      top;
    int             ePBC = -1;
    t_trxframe      fr;
    matrix          box;
    gmx_bool        bTPS = FALSE, bTop = FALSE;
    int             gnx;
    int            *index;
    char           *grpname;
    /* t0, t1 are the beginning and end time respectively.
     * dt is the time step, mass is temp variable for atomic mass.
     */
    real              t0, t1, dt, mass;
    t_trxstatus      *status;
    int               counter, n_alloc, i, j, counter_dim, k, l;
    rvec              mv_mol;
    /* Array for the correlation function */
    real            **c1;
    real             *normm = NULL;
    gmx_output_env_t *oenv;

#define NHISTO 360

    t_filenm  fnm[] = {
        { efTRN, "-f",    NULL,   ffREAD  },
        { efTPS, NULL,    NULL,   ffOPTRD },
        { efNDX, NULL,    NULL,   ffOPTRD },
        { efXVG, "-o",    "vac",  ffWRITE },
        { efXVG, "-os",   "spectrum", ffOPTWR }
    };
#define NFILE asize(fnm)
    int       npargs;
    t_pargs  *ppa;

    npargs = asize(pa);
    ppa    = add_acf_pargs(&npargs, pa);
    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME,
                           NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv))
    {
        sfree(ppa);
        return 0;
    }

    if (bMol || bMass)
    {
        bTPS = ftp2bSet(efTPS, NFILE, fnm) || !ftp2bSet(efNDX, NFILE, fnm);
    }

    if (bTPS)
    {
        bTop = read_tps_conf(ftp2fn(efTPS, NFILE, fnm), &top, &ePBC, NULL, NULL, box,
                             TRUE);
        get_index(&top.atoms, ftp2fn_null(efNDX, NFILE, fnm), 1, &gnx, &index, &grpname);
    }
    else
    {
        rd_index(ftp2fn(efNDX, NFILE, fnm), 1, &gnx, &index, &grpname);
    }

    if (bMol)
    {
        if (!bTop)
        {
            gmx_fatal(FARGS, "Need a topology to determine the molecules");
        }
        snew(normm, top.atoms.nr);
        precalc(top, normm);
        index_atom2mol(&gnx, index, &top.mols);
    }

    /* Correlation stuff */
    snew(c1, gnx);
    for (i = 0; (i < gnx); i++)
    {
        c1[i] = NULL;
    }

    read_first_frame(oenv, &status, ftp2fn(efTRN, NFILE, fnm), &fr, TRX_NEED_V);
    t0 = fr.time;

    n_alloc = 0;
    counter = 0;
    do
    {
        if (counter >= n_alloc)
        {
            n_alloc += 100;
            for (i = 0; i < gnx; i++)
            {
                srenew(c1[i], DIM*n_alloc);
            }
        }
        counter_dim = DIM*counter;
        if (bMol)
        {
            for (i = 0; i < gnx; i++)
            {
                clear_rvec(mv_mol);
                k = top.mols.index[index[i]];
                l = top.mols.index[index[i]+1];
                for (j = k; j < l; j++)
                {
                    if (bMass)
                    {
                        mass = top.atoms.atom[j].m;
                    }
                    else
                    {
                        mass = normm[j];
                    }
                    mv_mol[XX] += mass*fr.v[j][XX];
                    mv_mol[YY] += mass*fr.v[j][YY];
                    mv_mol[ZZ] += mass*fr.v[j][ZZ];
                }
                c1[i][counter_dim+XX] = mv_mol[XX];
                c1[i][counter_dim+YY] = mv_mol[YY];
                c1[i][counter_dim+ZZ] = mv_mol[ZZ];
            }
        }
        else
        {
            for (i = 0; i < gnx; i++)
            {
                if (bMass)
                {
                    mass = top.atoms.atom[index[i]].m;
                }
                else
                {
                    mass = 1;
                }
                c1[i][counter_dim+XX] = mass*fr.v[index[i]][XX];
                c1[i][counter_dim+YY] = mass*fr.v[index[i]][YY];
                c1[i][counter_dim+ZZ] = mass*fr.v[index[i]][ZZ];
            }
        }

        t1 = fr.time;

        counter++;
    }
    while (read_next_frame(oenv, status, &fr));

    close_trj(status);

    if (counter >= 4)
    {
        /* Compute time step between frames */
        dt = (t1-t0)/(counter-1);
        do_autocorr(opt2fn("-o", NFILE, fnm), oenv,
                    bMass ?
                    "Momentum Autocorrelation Function" :
                    "Velocity Autocorrelation Function",
                    counter, gnx, c1, dt, eacVector, TRUE);

        do_view(oenv, opt2fn("-o", NFILE, fnm), "-nxy");

        if (opt2bSet("-os", NFILE, fnm))
        {
            calc_spectrum(counter/2, (real *) (c1[0]), (t1-t0)/2, opt2fn("-os", NFILE, fnm),
                          oenv, bRecip);
            do_view(oenv, opt2fn("-os", NFILE, fnm), "-nxy");
        }
    }
    else
    {
        fprintf(stderr, "Not enough frames in trajectory - no output generated.\n");
    }

    return 0;
}
Exemple #4
0
int gmx_analyze(int argc,char *argv[])
{
  static const char *desc[] = {
    "g_analyze reads an ascii file and analyzes data sets.",
    "A line in the input file may start with a time",
    "(see option [TT]-time[tt]) and any number of y values may follow.",
    "Multiple sets can also be",
    "read when they are seperated by & (option [TT]-n[tt]),",
    "in this case only one y value is read from each line.",
    "All lines starting with # and @ are skipped.",
    "All analyses can also be done for the derivative of a set",
    "(option [TT]-d[tt]).[PAR]",

    "All options, except for [TT]-av[tt] and [TT]-power[tt] assume that the",
    "points are equidistant in time.[PAR]",

    "g_analyze always shows the average and standard deviation of each",
    "set. For each set it also shows the relative deviation of the third",
    "and forth cumulant from those of a Gaussian distribution with the same",
    "standard deviation.[PAR]",

    "Option [TT]-ac[tt] produces the autocorrelation function(s).[PAR]",
    
    "Option [TT]-cc[tt] plots the resemblance of set i with a cosine of",
    "i/2 periods. The formula is:[BR]"
    "2 (int0-T y(t) cos(i pi t) dt)^2 / int0-T y(t) y(t) dt[BR]",
    "This is useful for principal components obtained from covariance",
    "analysis, since the principal components of random diffusion are",
    "pure cosines.[PAR]",
    
    "Option [TT]-msd[tt] produces the mean square displacement(s).[PAR]",
    
    "Option [TT]-dist[tt] produces distribution plot(s).[PAR]",
    
    "Option [TT]-av[tt] produces the average over the sets.",
    "Error bars can be added with the option [TT]-errbar[tt].",
    "The errorbars can represent the standard deviation, the error",
    "(assuming the points are independent) or the interval containing",
    "90% of the points, by discarding 5% of the points at the top and",
    "the bottom.[PAR]",
    
    "Option [TT]-ee[tt] produces error estimates using block averaging.",
    "A set is divided in a number of blocks and averages are calculated for",
    "each block. The error for the total average is calculated from",
    "the variance between averages of the m blocks B_i as follows:",
    "error^2 = Sum (B_i - <B>)^2 / (m*(m-1)).",
    "These errors are plotted as a function of the block size.",
    "Also an analytical block average curve is plotted, assuming",
    "that the autocorrelation is a sum of two exponentials.",
    "The analytical curve for the block average is:[BR]",
    "f(t) = sigma sqrt(2/T (  a   (tau1 ((exp(-t/tau1) - 1) tau1/t + 1)) +[BR]",
    "                       (1-a) (tau2 ((exp(-t/tau2) - 1) tau2/t + 1)))),[BR]"
    "where T is the total time.",
    "a, tau1 and tau2 are obtained by fitting f^2(t) to error^2.",
    "When the actual block average is very close to the analytical curve,",
    "the error is sigma*sqrt(2/T (a tau1 + (1-a) tau2)).",
    "The complete derivation is given in",
    "B. Hess, J. Chem. Phys. 116:209-217, 2002.[PAR]",

    "Option [TT]-filter[tt] prints the RMS high-frequency fluctuation",
    "of each set and over all sets with respect to a filtered average.",
    "The filter is proportional to cos(pi t/len) where t goes from -len/2",
    "to len/2. len is supplied with the option [TT]-filter[tt].",
    "This filter reduces oscillations with period len/2 and len by a factor",
    "of 0.79 and 0.33 respectively.[PAR]",

    "Option [TT]-g[tt] fits the data to the function given with option",
    "[TT]-fitfn[tt].[PAR]",
    
    "Option [TT]-power[tt] fits the data to b t^a, which is accomplished",
    "by fitting to a t + b on log-log scale. All points after the first",
    "zero or negative value are ignored.[PAR]"
    
    "Option [TT]-luzar[tt] performs a Luzar & Chandler kinetics analysis",
    "on output from [TT]g_hbond[tt]. The input file can be taken directly",
    "from [TT]g_hbond -ac[tt], and then the same result should be produced."
  };
  static real tb=-1,te=-1,frac=0.5,filtlen=0,binwidth=0.1,aver_start=0;
  static bool bHaveT=TRUE,bDer=FALSE,bSubAv=TRUE,bAverCorr=FALSE,bXYdy=FALSE;
  static bool bEESEF=FALSE,bEENLC=FALSE,bEeFitAc=FALSE,bPower=FALSE;
  static bool bIntegrate=FALSE,bRegression=FALSE,bLuzar=FALSE,bLuzarError=FALSE; 
  static int  nsets_in=1,d=1,nb_min=4,resol=10;
  static real temp=298.15,fit_start=1,smooth_tail_start=-1;
  
  /* must correspond to enum avbar* declared at beginning of file */
  static const char *avbar_opt[avbarNR+1] = { 
    NULL, "none", "stddev", "error", "90", NULL
  };

  t_pargs pa[] = {
    { "-time",    FALSE, etBOOL, {&bHaveT},
      "Expect a time in the input" },
    { "-b",       FALSE, etREAL, {&tb},
      "First time to read from set" },
    { "-e",       FALSE, etREAL, {&te},
      "Last time to read from set" },
    { "-n",       FALSE, etINT, {&nsets_in},
      "Read # sets seperated by &" },
    { "-d",       FALSE, etBOOL, {&bDer},
	"Use the derivative" },
    { "-dp",      FALSE, etINT, {&d}, 
      "HIDDENThe derivative is the difference over # points" },
    { "-bw",      FALSE, etREAL, {&binwidth},
      "Binwidth for the distribution" },
    { "-errbar",  FALSE, etENUM, {avbar_opt},
      "Error bars for -av" },
    { "-integrate",FALSE,etBOOL, {&bIntegrate},
      "Integrate data function(s) numerically using trapezium rule" },
    { "-aver_start",FALSE, etREAL, {&aver_start},
      "Start averaging the integral from here" },
    { "-xydy",    FALSE, etBOOL, {&bXYdy},
      "Interpret second data set as error in the y values for integrating" },
    { "-regression",FALSE,etBOOL,{&bRegression},
      "Perform a linear regression analysis on the data" },
    { "-luzar",   FALSE, etBOOL, {&bLuzar},
      "Do a Luzar and Chandler analysis on a correlation function and related as produced by g_hbond. When in addition the -xydy flag is given the second and fourth column will be interpreted as errors in c(t) and n(t)." },
    { "-temp",    FALSE, etREAL, {&temp},
      "Temperature for the Luzar hydrogen bonding kinetics analysis" },
    { "-fitstart", FALSE, etREAL, {&fit_start},
      "Time (ps) from which to start fitting the correlation functions in order to obtain the forward and backward rate constants for HB breaking and formation" }, 
    { "-smooth",FALSE, etREAL, {&smooth_tail_start},
      "If >= 0, the tail of the ACF will be smoothed by fitting it to an exponential function: y = A exp(-x/tau)" },
    { "-nbmin",   FALSE, etINT, {&nb_min},
      "HIDDENMinimum number of blocks for block averaging" },
    { "-resol", FALSE, etINT, {&resol},
      "HIDDENResolution for the block averaging, block size increases with"
    " a factor 2^(1/#)" },
    { "-eeexpfit", FALSE, etBOOL, {&bEESEF},
      "HIDDENAlways use a single exponential fit for the error estimate" },
    { "-eenlc", FALSE, etBOOL, {&bEENLC},
      "HIDDENAllow a negative long-time correlation" },
    { "-eefitac", FALSE, etBOOL, {&bEeFitAc},
      "HIDDENAlso plot analytical block average using a autocorrelation fit" },
    { "-filter",  FALSE, etREAL, {&filtlen},
      "Print the high-frequency fluctuation after filtering with a cosine filter of length #" },
    { "-power", FALSE, etBOOL, {&bPower},
      "Fit data to: b t^a" },
    { "-subav", FALSE, etBOOL, {&bSubAv},
      "Subtract the average before autocorrelating" },
    { "-oneacf", FALSE, etBOOL, {&bAverCorr},
      "Calculate one ACF over all sets" }
  };
#define NPA asize(pa)

  FILE     *out,*out_fit;
  int      n,nlast,s,nset,i,j=0;
  real     **val,*t,dt,tot,error;
  double   *av,*sig,cum1,cum2,cum3,cum4,db;
  char     *acfile,*msdfile,*ccfile,*distfile,*avfile,*eefile,*fitfile;
  
  t_filenm fnm[] = { 
    { efXVG, "-f",    "graph",    ffREAD   },
    { efXVG, "-ac",   "autocorr", ffOPTWR  },
    { efXVG, "-msd",  "msd",      ffOPTWR  },
    { efXVG, "-cc",   "coscont",  ffOPTWR  },
    { efXVG, "-dist", "distr",    ffOPTWR  },
    { efXVG, "-av",   "average",  ffOPTWR  },
    { efXVG, "-ee",   "errest",   ffOPTWR  },
    { efLOG, "-g",    "fitlog",   ffOPTWR  }
  }; 
#define NFILE asize(fnm) 

  int     npargs;
  t_pargs *ppa;

  npargs = asize(pa); 
  ppa    = add_acf_pargs(&npargs,pa);
  
  CopyRight(stderr,argv[0]); 
  parse_common_args(&argc,argv,PCA_CAN_VIEW,
		    NFILE,fnm,npargs,ppa,asize(desc),desc,0,NULL); 

  acfile   = opt2fn_null("-ac",NFILE,fnm);
  msdfile  = opt2fn_null("-msd",NFILE,fnm);
  ccfile   = opt2fn_null("-cc",NFILE,fnm);
  distfile = opt2fn_null("-dist",NFILE,fnm);
  avfile   = opt2fn_null("-av",NFILE,fnm);
  eefile   = opt2fn_null("-ee",NFILE,fnm);
  if (opt2parg_bSet("-fitfn",npargs,ppa)) 
    fitfile  = opt2fn("-g",NFILE,fnm);
  else
    fitfile  = opt2fn_null("-g",NFILE,fnm);
    
  val=read_xvg_time(opt2fn("-f",NFILE,fnm),bHaveT,
		    opt2parg_bSet("-b",npargs,ppa),tb,
		    opt2parg_bSet("-e",npargs,ppa),te,
		    nsets_in,&nset,&n,&dt,&t);
  printf("Read %d sets of %d points, dt = %g\n\n",nset,n,dt);
  
  if (bDer) {
    printf("Calculating the derivative as (f[i+%d]-f[i])/(%d*dt)\n\n",
	    d,d);
    n -= d;
    for(s=0; s<nset; s++)
      for(i=0; (i<n); i++)
	val[s][i] = (val[s][i+d]-val[s][i])/(d*dt);
  }
  if (bIntegrate) {
    real sum,stddev;
    printf("Calculating the integral using the trapezium rule\n");
    
    if (bXYdy) {
      sum = evaluate_integral(n,t,val[0],val[1],aver_start,&stddev);
      printf("Integral %10.3f +/- %10.5f\n",sum,stddev);
    }
    else {
      for(s=0; s<nset; s++) {
	sum = evaluate_integral(n,t,val[s],NULL,aver_start,&stddev);
	printf("Integral %d  %10.5f  +/- %10.5f\n",s+1,sum,stddev);
      }
    }
  }
  if (fitfile) {
    out_fit = ffopen(fitfile,"w");
    if (bXYdy && nset>=2) {
      do_fit(out_fit,0,TRUE,n,t,val,npargs,ppa);
    } else {
      for(s=0; s<nset; s++)
	do_fit(out_fit,s,FALSE,n,t,val,npargs,ppa);
    }
    fclose(out_fit);
  }

  printf("                                      std. dev.    relative deviation of\n");
  printf("                       standard       ---------   cumulants from those of\n");
  printf("set      average       deviation      sqrt(n-1)   a Gaussian distribition\n");
  printf("                                                      cum. 3   cum. 4\n");
  snew(av,nset);
  snew(sig,nset);
  for(s=0; (s<nset); s++) {
    cum1 = 0;
    cum2 = 0;
    cum3 = 0;
    cum4 = 0;
    for(i=0; (i<n); i++)
      cum1 += val[s][i];
    cum1 /= n;
    for(i=0; (i<n); i++) {
      db = val[s][i]-cum1;
      cum2 += db*db;
      cum3 += db*db*db;
      cum4 += db*db*db*db;
    }
    cum2  /= n;
    cum3  /= n;
    cum4  /= n;
    av[s]  = cum1;
    sig[s] = sqrt(cum2);
    if (n > 1)
      error = sqrt(cum2/(n-1));
    else
      error = 0;
    printf("SS%d  %13.6e   %12.6e   %12.6e      %6.3f   %6.3f\n",
	   s+1,av[s],sig[s],error,
	   sig[s] ? cum3/(sig[s]*sig[s]*sig[s]*sqrt(8/M_PI)) : 0,
	   sig[s] ? cum4/(sig[s]*sig[s]*sig[s]*sig[s]*3)-1 : 0); 
  }
  printf("\n");

  if (filtlen)
    filter(filtlen,n,nset,val,dt);
  
  if (msdfile) {
    out=xvgropen(msdfile,"Mean square displacement",
		 "time","MSD (nm\\S2\\N)");
    nlast = (int)(n*frac);
    for(s=0; s<nset; s++) {
      for(j=0; j<=nlast; j++) {
	if (j % 100 == 0)
	  fprintf(stderr,"\r%d",j);
	tot=0;
	for(i=0; i<n-j; i++)
	  tot += sqr(val[s][i]-val[s][i+j]); 
	tot /= (real)(n-j);
	fprintf(out," %g %8g\n",dt*j,tot);
      }
      if (s<nset-1)
	fprintf(out,"&\n");
    }
    fclose(out);
    fprintf(stderr,"\r%d, time=%g\n",j-1,(j-1)*dt);
  }
  if (ccfile)
    plot_coscont(ccfile,n,nset,val);
  
  if (distfile)
    histogram(distfile,binwidth,n,nset,val);
  if (avfile)
    average(avfile,nenum(avbar_opt),n,nset,val,t);
  if (eefile)
    estimate_error(eefile,nb_min,resol,n,nset,av,sig,val,dt,
		   bEeFitAc,bEESEF,bEENLC);
  if (bPower)
    power_fit(n,nset,val,t);
  if (acfile) {
    if (bSubAv) 
      for(s=0; s<nset; s++)
	for(i=0; i<n; i++)
	  val[s][i] -= av[s];
    do_autocorr(acfile,"Autocorrelation",n,nset,val,dt,
		eacNormal,bAverCorr);
  }
  if (bRegression)
    regression_analysis(n,bXYdy,t,val);

  if (bLuzar) 
    luzar_correl(n,t,nset,val,temp,bXYdy,fit_start,smooth_tail_start);
    
  view_all(NFILE, fnm);
  
  thanx(stderr);

  return 0;
}
Exemple #5
0
int gmx_analyze(int argc, char *argv[])
{
    static const char *desc[] = {
        "[TT]g_analyze[tt] reads an ASCII file and analyzes data sets.",
        "A line in the input file may start with a time",
        "(see option [TT]-time[tt]) and any number of [IT]y[it]-values may follow.",
        "Multiple sets can also be",
        "read when they are separated by & (option [TT]-n[tt]);",
        "in this case only one [IT]y[it]-value is read from each line.",
        "All lines starting with # and @ are skipped.",
        "All analyses can also be done for the derivative of a set",
        "(option [TT]-d[tt]).[PAR]",

        "All options, except for [TT]-av[tt] and [TT]-power[tt], assume that the",
        "points are equidistant in time.[PAR]",

        "[TT]g_analyze[tt] always shows the average and standard deviation of each",
        "set, as well as the relative deviation of the third",
        "and fourth cumulant from those of a Gaussian distribution with the same",
        "standard deviation.[PAR]",

        "Option [TT]-ac[tt] produces the autocorrelation function(s).",
        "Be sure that the time interval between data points is",
        "much shorter than the time scale of the autocorrelation.[PAR]",

        "Option [TT]-cc[tt] plots the resemblance of set i with a cosine of",
        "i/2 periods. The formula is:[BR]"
        "[MATH]2 ([INT][FROM]0[from][TO]T[to][int] y(t) [COS]i [GRK]pi[grk] t[cos] dt)^2 / [INT][FROM]0[from][TO]T[to][int] y^2(t) dt[math][BR]",
        "This is useful for principal components obtained from covariance",
        "analysis, since the principal components of random diffusion are",
        "pure cosines.[PAR]",

        "Option [TT]-msd[tt] produces the mean square displacement(s).[PAR]",

        "Option [TT]-dist[tt] produces distribution plot(s).[PAR]",

        "Option [TT]-av[tt] produces the average over the sets.",
        "Error bars can be added with the option [TT]-errbar[tt].",
        "The errorbars can represent the standard deviation, the error",
        "(assuming the points are independent) or the interval containing",
        "90% of the points, by discarding 5% of the points at the top and",
        "the bottom.[PAR]",

        "Option [TT]-ee[tt] produces error estimates using block averaging.",
        "A set is divided in a number of blocks and averages are calculated for",
        "each block. The error for the total average is calculated from",
        "the variance between averages of the m blocks B[SUB]i[sub] as follows:",
        "error^2 = [SUM][sum] (B[SUB]i[sub] - [CHEVRON]B[chevron])^2 / (m*(m-1)).",
        "These errors are plotted as a function of the block size.",
        "Also an analytical block average curve is plotted, assuming",
        "that the autocorrelation is a sum of two exponentials.",
        "The analytical curve for the block average is:[BR]",
        "[MATH]f(t) = [GRK]sigma[grk][TT]*[tt][SQRT]2/T (  [GRK]alpha[grk]   ([GRK]tau[grk][SUB]1[sub] (([EXP]-t/[GRK]tau[grk][SUB]1[sub][exp] - 1) [GRK]tau[grk][SUB]1[sub]/t + 1)) +[BR]",
        "                       (1-[GRK]alpha[grk]) ([GRK]tau[grk][SUB]2[sub] (([EXP]-t/[GRK]tau[grk][SUB]2[sub][exp] - 1) [GRK]tau[grk][SUB]2[sub]/t + 1)))[sqrt][math],[BR]"
        "where T is the total time.",
        "[GRK]alpha[grk], [GRK]tau[grk][SUB]1[sub] and [GRK]tau[grk][SUB]2[sub] are obtained by fitting f^2(t) to error^2.",
        "When the actual block average is very close to the analytical curve,",
        "the error is [MATH][GRK]sigma[grk][TT]*[tt][SQRT]2/T (a [GRK]tau[grk][SUB]1[sub] + (1-a) [GRK]tau[grk][SUB]2[sub])[sqrt][math].",
        "The complete derivation is given in",
        "B. Hess, J. Chem. Phys. 116:209-217, 2002.[PAR]",

        "Option [TT]-bal[tt] finds and subtracts the ultrafast \"ballistic\"",
        "component from a hydrogen bond autocorrelation function by the fitting",
        "of a sum of exponentials, as described in e.g.",
        "O. Markovitch, J. Chem. Phys. 129:084505, 2008. The fastest term",
        "is the one with the most negative coefficient in the exponential,",
        "or with [TT]-d[tt], the one with most negative time derivative at time 0.",
        "[TT]-nbalexp[tt] sets the number of exponentials to fit.[PAR]",

        "Option [TT]-gem[tt] fits bimolecular rate constants ka and kb",
        "(and optionally kD) to the hydrogen bond autocorrelation function",
        "according to the reversible geminate recombination model. Removal of",
        "the ballistic component first is strongly advised. The model is presented in",
        "O. Markovitch, J. Chem. Phys. 129:084505, 2008.[PAR]",

        "Option [TT]-filter[tt] prints the RMS high-frequency fluctuation",
        "of each set and over all sets with respect to a filtered average.",
        "The filter is proportional to cos([GRK]pi[grk] t/len) where t goes from -len/2",
        "to len/2. len is supplied with the option [TT]-filter[tt].",
        "This filter reduces oscillations with period len/2 and len by a factor",
        "of 0.79 and 0.33 respectively.[PAR]",

        "Option [TT]-g[tt] fits the data to the function given with option",
        "[TT]-fitfn[tt].[PAR]",

        "Option [TT]-power[tt] fits the data to [MATH]b t^a[math], which is accomplished",
        "by fitting to [MATH]a t + b[math] on log-log scale. All points after the first",
        "zero or with a negative value are ignored.[PAR]"

        "Option [TT]-luzar[tt] performs a Luzar & Chandler kinetics analysis",
        "on output from [TT]g_hbond[tt]. The input file can be taken directly",
        "from [TT]g_hbond -ac[tt], and then the same result should be produced."
    };
    static real        tb         = -1, te = -1, frac = 0.5, filtlen = 0, binwidth = 0.1, aver_start = 0;
    static gmx_bool    bHaveT     = TRUE, bDer = FALSE, bSubAv = TRUE, bAverCorr = FALSE, bXYdy = FALSE;
    static gmx_bool    bEESEF     = FALSE, bEENLC = FALSE, bEeFitAc = FALSE, bPower = FALSE;
    static gmx_bool    bIntegrate = FALSE, bRegression = FALSE, bLuzar = FALSE, bLuzarError = FALSE;
    static int         nsets_in   = 1, d = 1, nb_min = 4, resol = 10, nBalExp = 4, nFitPoints = 100;
    static real        temp       = 298.15, fit_start = 1, fit_end = 60, smooth_tail_start = -1, balTime = 0.2, diffusion = 5e-5, rcut = 0.35;

    /* must correspond to enum avbar* declared at beginning of file */
    static const char *avbar_opt[avbarNR+1] = {
        NULL, "none", "stddev", "error", "90", NULL
    };

    t_pargs            pa[] = {
        { "-time",    FALSE, etBOOL, {&bHaveT},
          "Expect a time in the input" },
        { "-b",       FALSE, etREAL, {&tb},
          "First time to read from set" },
        { "-e",       FALSE, etREAL, {&te},
          "Last time to read from set" },
        { "-n",       FALSE, etINT, {&nsets_in},
          "Read this number of sets separated by &" },
        { "-d",       FALSE, etBOOL, {&bDer},
          "Use the derivative" },
        { "-dp",      FALSE, etINT, {&d},
          "HIDDENThe derivative is the difference over this number of points" },
        { "-bw",      FALSE, etREAL, {&binwidth},
          "Binwidth for the distribution" },
        { "-errbar",  FALSE, etENUM, {avbar_opt},
          "Error bars for [TT]-av[tt]" },
        { "-integrate", FALSE, etBOOL, {&bIntegrate},
          "Integrate data function(s) numerically using trapezium rule" },
        { "-aver_start", FALSE, etREAL, {&aver_start},
          "Start averaging the integral from here" },
        { "-xydy",    FALSE, etBOOL, {&bXYdy},
          "Interpret second data set as error in the y values for integrating" },
        { "-regression", FALSE, etBOOL, {&bRegression},
          "Perform a linear regression analysis on the data. If [TT]-xydy[tt] is set a second set will be interpreted as the error bar in the Y value. Otherwise, if multiple data sets are present a multilinear regression will be performed yielding the constant A that minimize [MATH][GRK]chi[grk]^2 = (y - A[SUB]0[sub] x[SUB]0[sub] - A[SUB]1[sub] x[SUB]1[sub] - ... - A[SUB]N[sub] x[SUB]N[sub])^2[math] where now Y is the first data set in the input file and x[SUB]i[sub] the others. Do read the information at the option [TT]-time[tt]." },
        { "-luzar",   FALSE, etBOOL, {&bLuzar},
          "Do a Luzar and Chandler analysis on a correlation function and related as produced by [TT]g_hbond[tt]. When in addition the [TT]-xydy[tt] flag is given the second and fourth column will be interpreted as errors in c(t) and n(t)." },
        { "-temp",    FALSE, etREAL, {&temp},
          "Temperature for the Luzar hydrogen bonding kinetics analysis (K)" },
        { "-fitstart", FALSE, etREAL, {&fit_start},
          "Time (ps) from which to start fitting the correlation functions in order to obtain the forward and backward rate constants for HB breaking and formation" },
        { "-fitend", FALSE, etREAL, {&fit_end},
          "Time (ps) where to stop fitting the correlation functions in order to obtain the forward and backward rate constants for HB breaking and formation. Only with [TT]-gem[tt]" },
        { "-smooth", FALSE, etREAL, {&smooth_tail_start},
          "If this value is >= 0, the tail of the ACF will be smoothed by fitting it to an exponential function: [MATH]y = A [EXP]-x/[GRK]tau[grk][exp][math]" },
        { "-nbmin",   FALSE, etINT, {&nb_min},
          "HIDDENMinimum number of blocks for block averaging" },
        { "-resol", FALSE, etINT, {&resol},
          "HIDDENResolution for the block averaging, block size increases with"
          " a factor 2^(1/resol)" },
        { "-eeexpfit", FALSE, etBOOL, {&bEESEF},
          "HIDDENAlways use a single exponential fit for the error estimate" },
        { "-eenlc", FALSE, etBOOL, {&bEENLC},
          "HIDDENAllow a negative long-time correlation" },
        { "-eefitac", FALSE, etBOOL, {&bEeFitAc},
          "HIDDENAlso plot analytical block average using a autocorrelation fit" },
        { "-filter",  FALSE, etREAL, {&filtlen},
          "Print the high-frequency fluctuation after filtering with a cosine filter of this length" },
        { "-power", FALSE, etBOOL, {&bPower},
          "Fit data to: b t^a" },
        { "-subav", FALSE, etBOOL, {&bSubAv},
          "Subtract the average before autocorrelating" },
        { "-oneacf", FALSE, etBOOL, {&bAverCorr},
          "Calculate one ACF over all sets" },
        { "-nbalexp", FALSE, etINT, {&nBalExp},
          "HIDDENNumber of exponentials to fit to the ultrafast component" },
        { "-baltime", FALSE, etREAL, {&balTime},
          "HIDDENTime up to which the ballistic component will be fitted" },
/*     { "-gemnp", FALSE, etINT, {&nFitPoints}, */
/*       "HIDDENNumber of data points taken from the ACF to use for fitting to rev. gem. recomb. model."}, */
/*     { "-rcut", FALSE, etREAL, {&rcut}, */
/*       "Cut-off for hydrogen bonds in geminate algorithms" }, */
/*     { "-gemtype", FALSE, etENUM, {gemType}, */
/*       "What type of gminate recombination to use"}, */
/*     { "-D", FALSE, etREAL, {&diffusion}, */
/*       "The self diffusion coefficient which is used for the reversible geminate recombination model."} */
    };
#define NPA asize(pa)

    FILE           *out, *out_fit;
    int             n, nlast, s, nset, i, j = 0;
    real          **val, *t, dt, tot, error;
    double         *av, *sig, cum1, cum2, cum3, cum4, db;
    const char     *acfile, *msdfile, *ccfile, *distfile, *avfile, *eefile, *balfile, *gemfile, *fitfile;
    output_env_t    oenv;

    t_filenm        fnm[] = {
        { efXVG, "-f",    "graph",    ffREAD   },
        { efXVG, "-ac",   "autocorr", ffOPTWR  },
        { efXVG, "-msd",  "msd",      ffOPTWR  },
        { efXVG, "-cc",   "coscont",  ffOPTWR  },
        { efXVG, "-dist", "distr",    ffOPTWR  },
        { efXVG, "-av",   "average",  ffOPTWR  },
        { efXVG, "-ee",   "errest",   ffOPTWR  },
        { efXVG, "-bal",  "ballisitc", ffOPTWR  },
/*     { efXVG, "-gem",  "geminate", ffOPTWR  }, */
        { efLOG, "-g",    "fitlog",   ffOPTWR  }
    };
#define NFILE asize(fnm)

    int      npargs;
    t_pargs *ppa;

    npargs = asize(pa);
    ppa    = add_acf_pargs(&npargs, pa);

    parse_common_args(&argc, argv, PCA_CAN_VIEW,
                      NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv);

    acfile   = opt2fn_null("-ac", NFILE, fnm);
    msdfile  = opt2fn_null("-msd", NFILE, fnm);
    ccfile   = opt2fn_null("-cc", NFILE, fnm);
    distfile = opt2fn_null("-dist", NFILE, fnm);
    avfile   = opt2fn_null("-av", NFILE, fnm);
    eefile   = opt2fn_null("-ee", NFILE, fnm);
    balfile  = opt2fn_null("-bal", NFILE, fnm);
/*   gemfile  = opt2fn_null("-gem",NFILE,fnm); */
    /* When doing autocorrelation we don't want a fitlog for fitting
     * the function itself (not the acf) when the user did not ask for it.
     */
    if (opt2parg_bSet("-fitfn", npargs, ppa) && acfile == NULL)
    {
        fitfile  = opt2fn("-g", NFILE, fnm);
    }
    else
    {
        fitfile  = opt2fn_null("-g", NFILE, fnm);
    }

    val = read_xvg_time(opt2fn("-f", NFILE, fnm), bHaveT,
                        opt2parg_bSet("-b", npargs, ppa), tb,
                        opt2parg_bSet("-e", npargs, ppa), te,
                        nsets_in, &nset, &n, &dt, &t);
    printf("Read %d sets of %d points, dt = %g\n\n", nset, n, dt);

    if (bDer)
    {
        printf("Calculating the derivative as (f[i+%d]-f[i])/(%d*dt)\n\n",
               d, d);
        n -= d;
        for (s = 0; s < nset; s++)
        {
            for (i = 0; (i < n); i++)
            {
                val[s][i] = (val[s][i+d]-val[s][i])/(d*dt);
            }
        }
    }

    if (bIntegrate)
    {
        real sum, stddev;

        printf("Calculating the integral using the trapezium rule\n");

        if (bXYdy)
        {
            sum = evaluate_integral(n, t, val[0], val[1], aver_start, &stddev);
            printf("Integral %10.3f +/- %10.5f\n", sum, stddev);
        }
        else
        {
            for (s = 0; s < nset; s++)
            {
                sum = evaluate_integral(n, t, val[s], NULL, aver_start, &stddev);
                printf("Integral %d  %10.5f  +/- %10.5f\n", s+1, sum, stddev);
            }
        }
    }

    if (fitfile != NULL)
    {
        out_fit = ffopen(fitfile, "w");
        if (bXYdy && nset >= 2)
        {
            do_fit(out_fit, 0, TRUE, n, t, val, npargs, ppa, oenv);
        }
        else
        {
            for (s = 0; s < nset; s++)
            {
                do_fit(out_fit, s, FALSE, n, t, val, npargs, ppa, oenv);
            }
        }
        ffclose(out_fit);
    }

    printf("                                      std. dev.    relative deviation of\n");
    printf("                       standard       ---------   cumulants from those of\n");
    printf("set      average       deviation      sqrt(n-1)   a Gaussian distribition\n");
    printf("                                                      cum. 3   cum. 4\n");
    snew(av, nset);
    snew(sig, nset);
    for (s = 0; (s < nset); s++)
    {
        cum1 = 0;
        cum2 = 0;
        cum3 = 0;
        cum4 = 0;
        for (i = 0; (i < n); i++)
        {
            cum1 += val[s][i];
        }
        cum1 /= n;
        for (i = 0; (i < n); i++)
        {
            db    = val[s][i]-cum1;
            cum2 += db*db;
            cum3 += db*db*db;
            cum4 += db*db*db*db;
        }
        cum2  /= n;
        cum3  /= n;
        cum4  /= n;
        av[s]  = cum1;
        sig[s] = sqrt(cum2);
        if (n > 1)
        {
            error = sqrt(cum2/(n-1));
        }
        else
        {
            error = 0;
        }
        printf("SS%d  %13.6e   %12.6e   %12.6e      %6.3f   %6.3f\n",
               s+1, av[s], sig[s], error,
               sig[s] ? cum3/(sig[s]*sig[s]*sig[s]*sqrt(8/M_PI)) : 0,
               sig[s] ? cum4/(sig[s]*sig[s]*sig[s]*sig[s]*3)-1 : 0);
    }
    printf("\n");

    if (filtlen)
    {
        filter(filtlen, n, nset, val, dt);
    }

    if (msdfile)
    {
        out = xvgropen(msdfile, "Mean square displacement",
                       "time", "MSD (nm\\S2\\N)", oenv);
        nlast = (int)(n*frac);
        for (s = 0; s < nset; s++)
        {
            for (j = 0; j <= nlast; j++)
            {
                if (j % 100 == 0)
                {
                    fprintf(stderr, "\r%d", j);
                }
                tot = 0;
                for (i = 0; i < n-j; i++)
                {
                    tot += sqr(val[s][i]-val[s][i+j]);
                }
                tot /= (real)(n-j);
                fprintf(out, " %g %8g\n", dt*j, tot);
            }
            if (s < nset-1)
            {
                fprintf(out, "&\n");
            }
        }
        ffclose(out);
        fprintf(stderr, "\r%d, time=%g\n", j-1, (j-1)*dt);
    }
    if (ccfile)
    {
        plot_coscont(ccfile, n, nset, val, oenv);
    }

    if (distfile)
    {
        histogram(distfile, binwidth, n, nset, val, oenv);
    }
    if (avfile)
    {
        average(avfile, nenum(avbar_opt), n, nset, val, t);
    }
    if (eefile)
    {
        estimate_error(eefile, nb_min, resol, n, nset, av, sig, val, dt,
                       bEeFitAc, bEESEF, bEENLC, oenv);
    }
    if (balfile)
    {
        do_ballistic(balfile, n, t, val, nset, balTime, nBalExp, oenv);
    }
/*   if (gemfile) */
/*       do_geminate(gemfile,n,t,val,nset,diffusion,rcut,balTime, */
/*                   nFitPoints, fit_start, fit_end, oenv); */
    if (bPower)
    {
        power_fit(n, nset, val, t);
    }

    if (acfile != NULL)
    {
        if (bSubAv)
        {
            for (s = 0; s < nset; s++)
            {
                for (i = 0; i < n; i++)
                {
                    val[s][i] -= av[s];
                }
            }
        }
        do_autocorr(acfile, oenv, "Autocorrelation", n, nset, val, dt,
                    eacNormal, bAverCorr);
    }

    if (bRegression)
    {
        regression_analysis(n, bXYdy, t, nset, val);
    }

    if (bLuzar)
    {
        luzar_correl(n, t, nset, val, temp, bXYdy, fit_start, smooth_tail_start, oenv);
    }

    view_all(oenv, NFILE, fnm);

    return 0;
}
Exemple #6
0
int gmx_g_angle(int argc, char *argv[])
{
    static const char *desc[] = {
        "[TT]g_angle[tt] computes the angle distribution for a number of angles",
        "or dihedrals.[PAR]",
        "With option [TT]-ov[tt], you can plot the average angle of",
        "a group of angles as a function of time. With the [TT]-all[tt] option,",
        "the first graph is the average and the rest are the individual angles.[PAR]",
        "With the [TT]-of[tt] option, [TT]g_angle[tt] also calculates the fraction of trans",
        "dihedrals (only for dihedrals) as function of time, but this is",
        "probably only fun for a select few.[PAR]",
        "With option [TT]-oc[tt], a dihedral correlation function is calculated.[PAR]",
        "It should be noted that the index file must contain",
        "atom triplets for angles or atom quadruplets for dihedrals.",
        "If this is not the case, the program will crash.[PAR]",
        "With option [TT]-or[tt], a trajectory file is dumped containing cos and",
        "sin of selected dihedral angles, which subsequently can be used as",
        "input for a principal components analysis using [TT]g_covar[tt].[PAR]",
        "Option [TT]-ot[tt] plots when transitions occur between",
        "dihedral rotamers of multiplicity 3 and [TT]-oh[tt]",
        "records a histogram of the times between such transitions,",
        "assuming the input trajectory frames are equally spaced in time."
    };
    static const char *opt[]    = { NULL, "angle", "dihedral", "improper", "ryckaert-bellemans", NULL };
    static gmx_bool    bALL     = FALSE, bChandler = FALSE, bAverCorr = FALSE, bPBC = TRUE;
    static real        binwidth = 1;
    t_pargs            pa[]     = {
        {   "-type", FALSE, etENUM, {opt},
            "Type of angle to analyse"
        },
        {   "-all",    FALSE,  etBOOL, {&bALL},
            "Plot all angles separately in the averages file, in the order of appearance in the index file."
        },
        {   "-binwidth", FALSE, etREAL, {&binwidth},
            "binwidth (degrees) for calculating the distribution"
        },
        {   "-periodic", FALSE, etBOOL, {&bPBC},
            "Print dihedral angles modulo 360 degrees"
        },
        {   "-chandler", FALSE,  etBOOL, {&bChandler},
            "Use Chandler correlation function (N[trans] = 1, N[gauche] = 0) rather than cosine correlation function. Trans is defined as phi < -60 or phi > 60."
        },
        {   "-avercorr", FALSE,  etBOOL, {&bAverCorr},
            "Average the correlation functions for the individual angles/dihedrals"
        }
    };
    static const char *bugs[] = {
        "Counting transitions only works for dihedrals with multiplicity 3"
    };

    FILE              *out;
    real               tmp, dt;
    int                status, isize;
    atom_id           *index;
    char              *grpname;
    real               maxang, Jc, S2, norm_fac, maxstat;
    unsigned long      mode;
    int                nframes, maxangstat, mult, *angstat;
    int                i, j, total, nangles, natoms, nat2, first, last, angind;
    gmx_bool           bAver, bRb, bPeriodic,
                       bFrac,                           /* calculate fraction too?  */
                       bTrans,                          /* worry about transtions too? */
                       bCorr;                           /* correlation function ? */
    real         t, aa, aver, aver2, aversig, fraction; /* fraction trans dihedrals */
    double       tfrac = 0;
    char         title[256];
    real       **dih = NULL;      /* mega array with all dih. angles at all times*/
    char         buf[80];
    real        *time, *trans_frac, *aver_angle;
    t_filenm     fnm[] = {
        { efTRX, "-f", NULL,  ffREAD  },
        { efNDX, NULL, "angle",  ffREAD  },
        { efXVG, "-od", "angdist",  ffWRITE },
        { efXVG, "-ov", "angaver",  ffOPTWR },
        { efXVG, "-of", "dihfrac",  ffOPTWR },
        { efXVG, "-ot", "dihtrans", ffOPTWR },
        { efXVG, "-oh", "trhisto",  ffOPTWR },
        { efXVG, "-oc", "dihcorr",  ffOPTWR },
        { efTRR, "-or", NULL,       ffOPTWR }
    };
#define NFILE asize(fnm)
    int          npargs;
    t_pargs     *ppa;
    output_env_t oenv;

    npargs = asize(pa);
    ppa    = add_acf_pargs(&npargs, pa);
    parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME | PCA_BE_NICE,
                      NFILE, fnm, npargs, ppa, asize(desc), desc, asize(bugs), bugs,
                      &oenv);

    mult   = 4;
    maxang = 360.0;
    bRb    = FALSE;
    switch (opt[0][0])
    {
    case 'a':
        mult   = 3;
        maxang = 180.0;
        break;
    case 'd':
        break;
    case 'i':
        break;
    case 'r':
        bRb = TRUE;
        break;
    }

    if (opt2bSet("-or", NFILE, fnm))
    {
        if (mult != 4)
        {
            gmx_fatal(FARGS, "Can not combine angles with trn dump");
        }
        else
        {
            please_cite(stdout, "Mu2005a");
        }
    }

    /* Calculate bin size */
    maxangstat = (int)(maxang/binwidth+0.5);
    binwidth   = maxang/maxangstat;

    rd_index(ftp2fn(efNDX, NFILE, fnm), 1, &isize, &index, &grpname);
    nangles = isize/mult;
    if ((isize % mult) != 0)
    {
        gmx_fatal(FARGS, "number of index elements not multiple of %d, "
                  "these can not be %s\n",
                  mult, (mult == 3) ? "angle triplets" : "dihedral quadruplets");
    }


    /* Check whether specific analysis has to be performed */
    bCorr  = opt2bSet("-oc", NFILE, fnm);
    bAver  = opt2bSet("-ov", NFILE, fnm);
    bTrans = opt2bSet("-ot", NFILE, fnm);
    bFrac  = opt2bSet("-of", NFILE, fnm);
    if (bTrans && opt[0][0] != 'd')
    {
        fprintf(stderr, "Option -ot should only accompany -type dihedral. Disabling -ot.\n");
        bTrans = FALSE;
    }

    if (bChandler && !bCorr)
    {
        bCorr = TRUE;
    }

    if (bFrac && !bRb)
    {
        fprintf(stderr, "Warning:"
                " calculating fractions as defined in this program\n"
                "makes sense for Ryckaert Bellemans dihs. only. Ignoring -of\n\n");
        bFrac = FALSE;
    }

    if ( (bTrans || bFrac || bCorr) && mult == 3)
    {
        gmx_fatal(FARGS, "Can only do transition, fraction or correlation\n"
                  "on dihedrals. Select -d\n");
    }

    /*
     * We need to know the nr of frames so we can allocate memory for an array
     * with all dihedral angles at all timesteps. Works for me.
     */
    if (bTrans || bCorr  || bALL || opt2bSet("-or", NFILE, fnm))
    {
        snew(dih, nangles);
    }

    snew(angstat, maxangstat);

    read_ang_dih(ftp2fn(efTRX, NFILE, fnm), (mult == 3),
                 bALL || bCorr || bTrans || opt2bSet("-or", NFILE, fnm),
                 bRb, bPBC, maxangstat, angstat,
                 &nframes, &time, isize, index, &trans_frac, &aver_angle, dih,
                 oenv);

    dt = (time[nframes-1]-time[0])/(nframes-1);

    if (bAver)
    {
        sprintf(title, "Average Angle: %s", grpname);
        out = xvgropen(opt2fn("-ov", NFILE, fnm),
                       title, "Time (ps)", "Angle (degrees)", oenv);
        for (i = 0; (i < nframes); i++)
        {
            fprintf(out, "%10.5f  %8.3f", time[i], aver_angle[i]*RAD2DEG);
            if (bALL)
            {
                for (j = 0; (j < nangles); j++)
                {
                    if (bPBC)
                    {
                        real dd = dih[j][i];
                        fprintf(out, "  %8.3f", atan2(sin(dd), cos(dd))*RAD2DEG);
                    }
                    else
                    {
                        fprintf(out, "  %8.3f", dih[j][i]*RAD2DEG);
                    }
                }
            }
            fprintf(out, "\n");
        }
        ffclose(out);
    }
    if (opt2bSet("-or", NFILE, fnm))
    {
        dump_dih_trn(nframes, nangles, dih, opt2fn("-or", NFILE, fnm), time);
    }

    if (bFrac)
    {
        sprintf(title, "Trans fraction: %s", grpname);
        out = xvgropen(opt2fn("-of", NFILE, fnm),
                       title, "Time (ps)", "Fraction", oenv);
        tfrac = 0.0;
        for (i = 0; (i < nframes); i++)
        {
            fprintf(out, "%10.5f  %10.3f\n", time[i], trans_frac[i]);
            tfrac += trans_frac[i];
        }
        ffclose(out);

        tfrac /= nframes;
        fprintf(stderr, "Average trans fraction: %g\n", tfrac);
    }
    sfree(trans_frac);

    if (bTrans)
    {
        ana_dih_trans(opt2fn("-ot", NFILE, fnm), opt2fn("-oh", NFILE, fnm),
                      dih, nframes, nangles, grpname, time, bRb, oenv);
    }

    if (bCorr)
    {
        /* Autocorrelation function */
        if (nframes < 2)
        {
            fprintf(stderr, "Not enough frames for correlation function\n");
        }
        else
        {

            if (bChandler)
            {
                real     dval, sixty = DEG2RAD*60;
                gmx_bool bTest;

                for (i = 0; (i < nangles); i++)
                {
                    for (j = 0; (j < nframes); j++)
                    {
                        dval = dih[i][j];
                        if (bRb)
                        {
                            bTest = (dval > -sixty) && (dval < sixty);
                        }
                        else
                        {
                            bTest = (dval < -sixty) || (dval > sixty);
                        }
                        if (bTest)
                        {
                            dih[i][j] = dval-tfrac;
                        }
                        else
                        {
                            dih[i][j] = -tfrac;
                        }
                    }
                }
            }
            if (bChandler)
            {
                mode = eacNormal;
            }
            else
            {
                mode = eacCos;
            }
            do_autocorr(opt2fn("-oc", NFILE, fnm), oenv,
                        "Dihedral Autocorrelation Function",
                        nframes, nangles, dih, dt, mode, bAverCorr);
        }
    }


    /* Determine the non-zero part of the distribution */
    for (first = 0; (first < maxangstat-1) && (angstat[first+1] == 0); first++)
    {
        ;
    }
    for (last = maxangstat-1; (last > 0) && (angstat[last-1] == 0); last--)
    {
        ;
    }

    aver = aver2 = 0;
    for (i = 0; (i < nframes); i++)
    {
        aver  += RAD2DEG*aver_angle[i];
        aver2 += sqr(RAD2DEG*aver_angle[i]);
    }
    aver   /= (real) nframes;
    aver2  /= (real) nframes;
    aversig = sqrt(aver2-sqr(aver));
    printf("Found points in the range from %d to %d (max %d)\n",
           first, last, maxangstat);
    printf(" < angle >  = %g\n", aver);
    printf("< angle^2 > = %g\n", aver2);
    printf("Std. Dev.   = %g\n", aversig);

    if (mult == 3)
    {
        sprintf(title, "Angle Distribution: %s", grpname);
    }
    else
    {
        sprintf(title, "Dihedral Distribution: %s", grpname);

        calc_distribution_props(maxangstat, angstat, -180.0, 0, NULL, &S2);
        fprintf(stderr, "Order parameter S^2 = %g\n", S2);
    }

    bPeriodic = (mult == 4) && (first == 0) && (last == maxangstat-1);

    out = xvgropen(opt2fn("-od", NFILE, fnm), title, "Degrees", "", oenv);
    if (output_env_get_print_xvgr_codes(oenv))
    {
        fprintf(out, "@    subtitle \"average angle: %g\\So\\N\"\n", aver);
    }
    norm_fac = 1.0/(nangles*nframes*binwidth);
    if (bPeriodic)
    {
        maxstat = 0;
        for (i = first; (i <= last); i++)
        {
            maxstat = max(maxstat, angstat[i]*norm_fac);
        }
        fprintf(out, "@with g0\n");
        fprintf(out, "@    world xmin -180\n");
        fprintf(out, "@    world xmax  180\n");
        fprintf(out, "@    world ymin 0\n");
        fprintf(out, "@    world ymax %g\n", maxstat*1.05);
        fprintf(out, "@    xaxis  tick major 60\n");
        fprintf(out, "@    xaxis  tick minor 30\n");
        fprintf(out, "@    yaxis  tick major 0.005\n");
        fprintf(out, "@    yaxis  tick minor 0.0025\n");
    }
    for (i = first; (i <= last); i++)
    {
        fprintf(out, "%10g  %10f\n", i*binwidth+180.0-maxang, angstat[i]*norm_fac);
    }
    if (bPeriodic)
    {
        /* print first bin again as last one */
        fprintf(out, "%10g  %10f\n", 180.0, angstat[0]*norm_fac);
    }

    ffclose(out);

    do_view(oenv, opt2fn("-od", NFILE, fnm), "-nxy");
    if (bAver)
    {
        do_view(oenv, opt2fn("-ov", NFILE, fnm), "-nxy");
    }

    thanx(stderr);

    return 0;
}
Exemple #7
0
int gmx_gyrate(int argc, char *argv[])
{
    const char       *desc[] = {
        "[THISMODULE] computes the radius of gyration of a molecule",
        "and the radii of gyration about the [IT]x[it]-, [IT]y[it]- and [IT]z[it]-axes,",
        "as a function of time. The atoms are explicitly mass weighted.[PAR]",
        "The axis components corresponds to the mass-weighted root-mean-square",
        "of the radii components orthogonal to each axis, for example:[PAR]",
        "Rg(x) = sqrt((sum_i m_i (R_i(y)^2 + R_i(z)^2))/(sum_i m_i)).[PAR]",
        "With the [TT]-nmol[tt] option the radius of gyration will be calculated",
        "for multiple molecules by splitting the analysis group in equally",
        "sized parts.[PAR]",
        "With the option [TT]-nz[tt] 2D radii of gyration in the [IT]x-y[it] plane",
        "of slices along the [IT]z[it]-axis are calculated."
    };
    static int        nmol = 1, nz = 0;
    static gmx_bool   bQ   = FALSE, bRot = FALSE, bMOI = FALSE;
    t_pargs           pa[] = {
        { "-nmol", FALSE, etINT, {&nmol},
          "The number of molecules to analyze" },
        { "-q", FALSE, etBOOL, {&bQ},
          "Use absolute value of the charge of an atom as weighting factor instead of mass" },
        { "-p", FALSE, etBOOL, {&bRot},
          "Calculate the radii of gyration about the principal axes." },
        { "-moi", FALSE, etBOOL, {&bMOI},
          "Calculate the moments of inertia (defined by the principal axes)." },
        { "-nz", FALSE, etINT, {&nz},
          "Calculate the 2D radii of gyration of this number of slices along the z-axis" },
    };
    FILE             *out;
    t_trxstatus      *status;
    t_topology        top;
    int               ePBC;
    rvec             *x, *x_s;
    rvec              xcm, gvec, gvec1;
    matrix            box, trans;
    gmx_bool          bACF;
    real            **moi_trans = NULL;
    int               max_moi   = 0, delta_moi = 100;
    rvec              d, d1; /* eigenvalues of inertia tensor */
    real              t, t0, tm, gyro;
    int               natoms;
    char             *grpname;
    int               j, m, gnx, nam, mol;
    atom_id          *index;
    gmx_output_env_t *oenv;
    gmx_rmpbc_t       gpbc   = NULL;
    const char       *leg[]  = { "Rg", "Rg\\sX\\N", "Rg\\sY\\N", "Rg\\sZ\\N" };
    const char       *legI[] = { "Itot", "I1", "I2", "I3" };
#define NLEG asize(leg)
    t_filenm          fnm[] = {
        { efTRX, "-f",   NULL,       ffREAD },
        { efTPS, NULL,   NULL,       ffREAD },
        { efNDX, NULL,   NULL,       ffOPTRD },
        { efXVG, NULL,   "gyrate",   ffWRITE },
        { efXVG, "-acf", "moi-acf",  ffOPTWR },
    };
#define NFILE asize(fnm)
    int               npargs;
    t_pargs          *ppa;

    npargs = asize(pa);
    ppa    = add_acf_pargs(&npargs, pa);

    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW,
                           NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv))
    {
        return 0;
    }
    bACF = opt2bSet("-acf", NFILE, fnm);
    if (bACF && nmol != 1)
    {
        gmx_fatal(FARGS, "Can only do acf with nmol=1");
    }
    bRot = bRot || bMOI || bACF;
    /*
       if (nz > 0)
       bMOI = TRUE;
     */
    if (bRot)
    {
        printf("Will rotate system along principal axes\n");
        snew(moi_trans, DIM);
    }
    if (bMOI)
    {
        printf("Will print moments of inertia\n");
        bQ = FALSE;
    }
    if (bQ)
    {
        printf("Will print radius normalised by charge\n");
    }

    read_tps_conf(ftp2fn(efTPS, NFILE, fnm), &top, &ePBC, &x, NULL, box, TRUE);
    get_index(&top.atoms, ftp2fn_null(efNDX, NFILE, fnm), 1, &gnx, &index, &grpname);

    if (nmol > gnx || gnx % nmol != 0)
    {
        gmx_fatal(FARGS, "The number of atoms in the group (%d) is not a multiple of nmol (%d)", gnx, nmol);
    }
    nam = gnx/nmol;

    natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box);
    snew(x_s, natoms);

    j  = 0;
    t0 = t;
    if (bQ)
    {
        out = xvgropen(ftp2fn(efXVG, NFILE, fnm),
                       "Radius of Charge (total and around axes)", "Time (ps)", "Rg (nm)", oenv);
    }
    else if (bMOI)
    {
        out = xvgropen(ftp2fn(efXVG, NFILE, fnm),
                       "Moments of inertia (total and around axes)", "Time (ps)", "I (a.m.u. nm\\S2\\N)", oenv);
    }
    else
    {
        out = xvgropen(ftp2fn(efXVG, NFILE, fnm),
                       "Radius of gyration (total and around axes)", "Time (ps)", "Rg (nm)", oenv);
    }
    if (bMOI)
    {
        xvgr_legend(out, NLEG, legI, oenv);
    }
    else
    {
        if (bRot)
        {
            if (output_env_get_print_xvgr_codes(oenv))
            {
                fprintf(out, "@ subtitle \"Axes are principal component axes\"\n");
            }
        }
        xvgr_legend(out, NLEG, leg, oenv);
    }
    if (nz == 0)
    {
        gpbc = gmx_rmpbc_init(&top.idef, ePBC, natoms);
    }
    do
    {
        if (nz == 0)
        {
            gmx_rmpbc_copy(gpbc, natoms, box, x, x_s);
        }
        gyro = 0;
        clear_rvec(gvec);
        clear_rvec(gvec1);
        clear_rvec(d);
        clear_rvec(d1);
        for (mol = 0; mol < nmol; mol++)
        {
            tm    = sub_xcm(nz == 0 ? x_s : x, nam, index+mol*nam, top.atoms.atom, xcm, bQ);
            if (nz == 0)
            {
                gyro += calc_gyro(x_s, nam, index+mol*nam, top.atoms.atom,
                                  tm, gvec1, d1, bQ, bRot, bMOI, trans);
            }
            else
            {
                calc_gyro_z(x, box, nam, index+mol*nam, top.atoms.atom, nz, t, out);
            }
            rvec_inc(gvec, gvec1);
            rvec_inc(d, d1);
        }
        if (nmol > 0)
        {
            gyro /= nmol;
            svmul(1.0/nmol, gvec, gvec);
            svmul(1.0/nmol, d, d);
        }

        if (nz == 0)
        {
            if (bRot)
            {
                if (j >= max_moi)
                {
                    max_moi += delta_moi;
                    for (m = 0; (m < DIM); m++)
                    {
                        srenew(moi_trans[m], max_moi*DIM);
                    }
                }
                for (m = 0; (m < DIM); m++)
                {
                    copy_rvec(trans[m], moi_trans[m]+DIM*j);
                }
                fprintf(out, "%10g  %10g  %10g  %10g  %10g\n",
                        t, gyro, d[XX], d[YY], d[ZZ]);
            }
            else
            {
                fprintf(out, "%10g  %10g  %10g  %10g  %10g\n",
                        t, gyro, gvec[XX], gvec[YY], gvec[ZZ]);
            }
        }
        j++;
    }
    while (read_next_x(oenv, status, &t, x, box));
    close_trj(status);
    if (nz == 0)
    {
        gmx_rmpbc_done(gpbc);
    }

    xvgrclose(out);

    if (bACF)
    {
        int mode = eacVector;

        do_autocorr(opt2fn("-acf", NFILE, fnm), oenv,
                    "Moment of inertia vector ACF",
                    j, 3, moi_trans, (t-t0)/j, mode, FALSE);
        do_view(oenv, opt2fn("-acf", NFILE, fnm), "-nxy");
    }

    do_view(oenv, ftp2fn(efXVG, NFILE, fnm), "-nxy");

    return 0;
}
Exemple #8
0
int main(int argc,char *argv[])
{
  FILE *fp;
  const char *desc[] = {
    "testac tests the functioning of the GROMACS acf routines"
  };
  static int nframes = 1024;
  static int datatp  = 0;
  static real a=0.02*M_PI;
  output_env_t oenv;
  t_pargs pa[] = {
    { "-np", FALSE, etINT, &nframes,
      "Number of data points" },
    { "-dtp",FALSE, etINT, &datatp,
      "Which data: 0=all 0.0, 1=all 1.0, 2=cos(a t), 3=random, 4=cos(a t)+random, 5=sin(a t)/(a t)" }
  };
  static char *str[] = {
    "all 0.0", 
    "all 1.0",
    "cos(a t)",
    "random", 
    "cos(a t)+random",
    "sin(a t)/(a t)"
  };
  t_filenm fnm[] = {
    { efXVG, "-d", "acf-data", ffWRITE },
    { efXVG, "-c", "acf-corr", ffWRITE },
    { efXVG, "-comb", "acf-comb.xvg", ffWRITE }
  };
#define NFILE asize(fnm)
  int     npargs,i,nlag;
  int     seed=1993;
  real    *data,*data2,x;
  t_pargs *ppa;
  
  CopyRight(stderr,argv[0]);
  npargs = asize(pa);
  ppa    = add_acf_pargs(&npargs,pa);
  parse_common_args_r(&argc,argv,PCA_CAN_TIME | PCA_CAN_VIEW | PCA_BE_NICE,
		      NFILE,fnm,npargs,ppa,asize(desc),desc,0,NULL,&oenv);
  snew(data,nframes);
  snew(data2,nframes);
  
  fp = xvgropen(opt2fn("-d",NFILE,fnm),"testac","x","y",oenv);
  for(i=0; (i<nframes); i++) {
    x = a*i;
    switch (datatp) {
    case 1:
      data[i] = 1;
      break;
    case 2:
      data[i] = cos(x);
      break;
    case 3:
      data[i] = 2*rando(&seed)-1.0;
      break;
    case 4:
      data[i] = cos(x)+2*rando(&seed)-1.0;
      break;
    case 5:
      if (i==0)
	data[i] = 1;
      else
	data[i] = sin(x)/(x);
    default:
      /* Data remains 0.0 */
      break;
    }
    fprintf(fp,"%10g  %10g\n",x,data[i]);
    data2[i] = data[i];
  }
  ffclose(fp);
  
  do_autocorr(opt2fn("-c",NFILE,fnm),oenv,str[datatp],
	      nframes,1,&data,a,eacNormal,FALSE);
	      
  nlag = get_acfnout();
  fp = xvgropen(opt2fn("-comb",NFILE,fnm),"testac","x","y",oenv);
  for(i=0; (i<nlag); i++) {
    fprintf(fp,"%10g  %10g  %10g\n",a*i,data2[i],data[i]);
  }
  ffclose(fp);

  do_view(opt2fn("-c",NFILE,fnm),"-nxy");
    
  thanx(stderr);

  return 0;
}
static void do_dip(t_topology *top,int ePBC,real volume,
                   const char *fn,
                   const char *out_mtot,const char *out_eps,
                   const char *out_aver, const char *dipdist,
                   const char *cosaver, const char *fndip3d,
                   const char *fnadip,  gmx_bool bPairs,
                   const char *corrtype,const char *corf,
                   gmx_bool bGkr,     const char *gkrfn,
                   gmx_bool bPhi,     int  *nlevels,  int ndegrees,
                   int  ncos,
                   const char *cmap,    real rcmax,
                   gmx_bool bQuad,    const char *quadfn,
                   gmx_bool bMU,      const char *mufn,
                   int  *gnx,     int  *molindex[],
                   real mu_max,   real mu_aver,
                   real epsilonRF,real temp,
                   int  *gkatom,  int skip,
                   gmx_bool bSlab,    int nslices,
                   const char *axtitle, const char *slabfn,
                   const output_env_t oenv)
{
    const char *leg_mtot[] = { 
        "M\\sx \\N", 
        "M\\sy \\N",
        "M\\sz \\N",
        "|M\\stot \\N|"
    };
#define NLEGMTOT asize(leg_mtot)
    const char *leg_eps[] = { 
        "epsilon",
        "G\\sk",
        "g\\sk"
    };
#define NLEGEPS asize(leg_eps)
    const char *leg_aver[] = { 
        "< |M|\\S2\\N >", 
        "< |M| >\\S2\\N",
        "< |M|\\S2\\N > - < |M| >\\S2\\N",
        "< |M| >\\S2\\N / < |M|\\S2\\N >"
    };
#define NLEGAVER asize(leg_aver)
    const char *leg_cosaver[] = {
        "\\f{4}<|cos\\f{12}q\\f{4}\\sij\\N|>",
        "RMSD cos",
        "\\f{4}<|cos\\f{12}q\\f{4}\\siX\\N|>",
        "\\f{4}<|cos\\f{12}q\\f{4}\\siY\\N|>",
        "\\f{4}<|cos\\f{12}q\\f{4}\\siZ\\N|>"
    };
#define NLEGCOSAVER asize(leg_cosaver)
    const char *leg_adip[] = {
        "<mu>",
        "Std. Dev.",
        "Error"
    };
#define NLEGADIP asize(leg_adip)

    FILE       *outdd,*outmtot,*outaver,*outeps,*caver=NULL;
    FILE       *dip3d=NULL,*adip=NULL;
    rvec       *x,*dipole=NULL,mu_t,quad,*dipsp=NULL;
    t_gkrbin   *gkrbin = NULL;
    gmx_enxnm_t *enm=NULL;
    t_enxframe *fr;
    int        nframes=1000,nre,timecheck=0,ncolour=0;
    ener_file_t fmu=NULL;
    int        i,j,k,n,m,natom=0,nmol,gnx_tot,teller,tel3;
    t_trxstatus *status;
    int        *dipole_bin,ndipbin,ibin,iVol,step,idim=-1;
    unsigned long mode;
    char       buf[STRLEN];
    real       rcut=0,t,t0,t1,dt,lambda,dd,rms_cos;
    rvec       dipaxis;
    matrix     box;
    gmx_bool   bCorr,bTotal,bCont;
    double     M_diff=0,epsilon,invtel,vol_aver;
    double     mu_ave,mu_mol,M2_ave=0,M_ave2=0,M_av[DIM],M_av2[DIM];
    double     M[3],M2[3],M4[3],Gk=0,g_k=0;
    gmx_stats_t Mx,My,Mz,Msq,Vol,*Qlsq,mulsq,muframelsq=NULL;
    ivec       iMu;
    real       **muall=NULL;
    rvec       *slab_dipoles=NULL;
    t_atom     *atom=NULL;
    t_block    *mols=NULL;
    gmx_rmpbc_t gpbc=NULL;

    gnx_tot = gnx[0];
    if (ncos > 1) {
        gnx_tot += gnx[1];
    }

    vol_aver = 0.0;
      
    iVol=-1;
    if (bMU) 
    {
        fmu = open_enx(mufn,"r");
        do_enxnms(fmu,&nre,&enm);

        /* Determine the indexes of the energy grps we need */
        for (i=0; (i<nre); i++) {
            if (strstr(enm[i].name,"Volume"))
                iVol=i;
            else if (strstr(enm[i].name,"Mu-X"))
                iMu[XX]=i;
            else if (strstr(enm[i].name,"Mu-Y"))
                iMu[YY]=i;
            else if (strstr(enm[i].name,"Mu-Z"))
                iMu[ZZ]=i;
        }
    }
    else 
    {
        atom = top->atoms.atom;
        mols = &(top->mols);
    }
  
    if ((iVol == -1) && bMU)
        printf("Using Volume from topology: %g nm^3\n",volume);

    /* Correlation stuff */ 
    bCorr  = (corrtype[0] != 'n');
    bTotal = (corrtype[0] == 't');
    if (bCorr) 
    {
        if (bTotal) 
        {
            snew(muall,1);
            snew(muall[0],nframes*DIM);
        }
        else 
        {
            snew(muall,gnx[0]);
            for(i=0; (i<gnx[0]); i++)
                snew(muall[i],nframes*DIM);
        }
    }

    /* Allocate array which contains for every molecule in a frame the
     * dipole moment.
     */
    if (!bMU)
        snew(dipole,gnx_tot);

    /* Statistics */
    snew(Qlsq,DIM);
    for(i=0; (i<DIM); i++) 
        Qlsq[i] = gmx_stats_init();
    mulsq = gmx_stats_init();
  
    /* Open all the files */
    outmtot = xvgropen(out_mtot,
                       "Total dipole moment of the simulation box vs. time",
                       "Time (ps)","Total Dipole Moment (Debye)",oenv);
    outeps  = xvgropen(out_eps,"Epsilon and Kirkwood factors",
                       "Time (ps)","",oenv);
    outaver = xvgropen(out_aver,"Total dipole moment",
                       "Time (ps)","D",oenv);
    if (bSlab) 
    {
        idim = axtitle[0] - 'X';
        if ((idim < 0) || (idim >= DIM))
            idim = axtitle[0] - 'x';
        if ((idim < 0) || (idim >= DIM))
            bSlab = FALSE;
        if (nslices < 2)
            bSlab = FALSE;
        fprintf(stderr,"axtitle = %s, nslices = %d, idim = %d\n",
                axtitle,nslices,idim);
        if (bSlab) 
        {
            snew(slab_dipoles,nslices);
            fprintf(stderr,"Doing slab analysis\n");
        }
    }
  
    if (fnadip) 
    {
        adip = xvgropen(fnadip, "Average molecular dipole","Dipole (D)","",oenv);
        xvgr_legend(adip,NLEGADIP,leg_adip, oenv);
  
    }
    if (cosaver) 
    {
        caver = xvgropen(cosaver,bPairs ? "Average pair orientation" :
                         "Average absolute dipole orientation","Time (ps)","",oenv);
        xvgr_legend(caver,NLEGCOSAVER,bPairs ? leg_cosaver : &(leg_cosaver[1]),
                    oenv);
    }
    
    if (fndip3d) 
    {
        snew(dipsp,gnx_tot);
  
        /* we need a dummy file for gnuplot */
        dip3d = (FILE *)ffopen("dummy.dat","w");
        fprintf(dip3d,"%f %f %f", 0.0,0.0,0.0);
        ffclose(dip3d);

        dip3d = (FILE *)ffopen(fndip3d,"w");
        fprintf(dip3d,"# This file was created by %s\n",Program());
        fprintf(dip3d,"# which is part of G R O M A C S:\n");
        fprintf(dip3d,"#\n");
    }
  
    /* Write legends to all the files */
    xvgr_legend(outmtot,NLEGMTOT,leg_mtot,oenv);
    xvgr_legend(outaver,NLEGAVER,leg_aver,oenv);
  
    if (bMU && (mu_aver == -1))
        xvgr_legend(outeps,NLEGEPS-2,leg_eps,oenv);
    else
        xvgr_legend(outeps,NLEGEPS,leg_eps,oenv);
    
    snew(fr,1);
    clear_rvec(mu_t);
    teller = 0;
    /* Read the first frame from energy or traj file */
    if (bMU)
        do 
        {
            bCont = read_mu_from_enx(fmu,iVol,iMu,mu_t,&volume,&t,nre,fr);
            if (bCont) 
            {  
                timecheck=check_times(t);
                if (timecheck < 0)
                    teller++;
                if ((teller % 10) == 0)
                    fprintf(stderr,"\r Skipping Frame %6d, time: %8.3f", teller, t);
            }
            else 
            {
                printf("End of %s reached\n",mufn);
                break;
            }
        } while (bCont && (timecheck < 0));
    else
        natom  = read_first_x(oenv,&status,fn,&t,&x,box);
  
    /* Calculate spacing for dipole bin (simple histogram) */
    ndipbin = 1+(mu_max/0.01);
    snew(dipole_bin, ndipbin);
    epsilon    = 0.0;
    mu_ave     = 0.0;
    for(m=0; (m<DIM); m++) 
    {
        M[m] = M2[m] = M4[m] = 0.0;
    }
  
    if (bGkr) 
    {
        /* Use 0.7 iso 0.5 to account for pressure scaling */
        /*  rcut   = 0.7*sqrt(max_cutoff2(box)); */
        rcut   = 0.7*sqrt(sqr(box[XX][XX])+sqr(box[YY][YY])+sqr(box[ZZ][ZZ]));

        gkrbin = mk_gkrbin(rcut,rcmax,bPhi,ndegrees); 
    }
    gpbc = gmx_rmpbc_init(&top->idef,ePBC,natom,box);

    /* Start while loop over frames */
    t1 = t0 = t;
    teller = 0;
    do 
    {
        if (bCorr && (teller >= nframes)) 
        {
            nframes += 1000;
            if (bTotal) 
            {
                srenew(muall[0],nframes*DIM);
            }
            else 
            {
                for(i=0; (i<gnx_tot); i++)
                    srenew(muall[i],nframes*DIM);
            }
        }
        t1 = t;

        muframelsq = gmx_stats_init();
    
        /* Initialise */
        for(m=0; (m<DIM); m++) 
            M_av2[m] = 0;
            
        if (bMU) 
        {
            /* Copy rvec into double precision local variable */
            for(m=0; (m<DIM); m++)
                M_av[m]  = mu_t[m];
        }
        else 
        {
            /* Initialise */
            for(m=0; (m<DIM); m++) 
                M_av[m] = 0;
                
            gmx_rmpbc(gpbc,natom,box,x);
      
            /* Begin loop of all molecules in frame */
            for(n=0; (n<ncos); n++) 
            {
                for(i=0; (i<gnx[n]); i++) 
                {
                    int gi,ind0,ind1;
	  
                    ind0  = mols->index[molindex[n][i]];
                    ind1  = mols->index[molindex[n][i]+1];
	  
                    mol_dip(ind0,ind1,x,atom,dipole[i]);
                    gmx_stats_add_point(mulsq,0,norm(dipole[i]),0,0);
                    gmx_stats_add_point(muframelsq,0,norm(dipole[i]),0,0);
                    if (bSlab) 
                        update_slab_dipoles(ind0,ind1,x,
                                            dipole[i],idim,nslices,slab_dipoles,box);
                    if (bQuad) 
                    {
                        mol_quad(ind0,ind1,x,atom,quad);
                        for(m=0; (m<DIM); m++)
                            gmx_stats_add_point(Qlsq[m],0,quad[m],0,0);
                    }
                    if (bCorr && !bTotal) 
                    {
                        tel3=DIM*teller;
                        muall[i][tel3+XX] = dipole[i][XX];
                        muall[i][tel3+YY] = dipole[i][YY];
                        muall[i][tel3+ZZ] = dipole[i][ZZ];
                    }
                    mu_mol = 0.0;
                    for(m=0; (m<DIM); m++) 
                    {
                        M_av[m]  += dipole[i][m];               /* M per frame */
                        mu_mol   += dipole[i][m]*dipole[i][m];  /* calc. mu for distribution */
                    }
                    mu_mol = sqrt(mu_mol);
	  
                    mu_ave += mu_mol;                         /* calc. the average mu */
	  
                    /* Update the dipole distribution */
                    ibin = (int)(ndipbin*mu_mol/mu_max + 0.5);
                    if (ibin < ndipbin)
                        dipole_bin[ibin]++;
	  
                    if (fndip3d) 
                    {
                        rvec2sprvec(dipole[i],dipsp[i]);
	    
                        if (dipsp[i][YY] > -M_PI && dipsp[i][YY] < -0.5*M_PI) {
                            if (dipsp[i][ZZ] < 0.5 * M_PI) 
                            {
                                ncolour = 1;
                            } 
                            else 
                            {
                                ncolour = 2;
                            }
                        }
                        else if (dipsp[i][YY] > -0.5*M_PI && dipsp[i][YY] < 0.0*M_PI) 
                        {
                            if (dipsp[i][ZZ] < 0.5 * M_PI) 
                            {
                                ncolour = 3;
                            } 
                            else 
                            {
                                ncolour = 4;
                            }       
                        }else if (dipsp[i][YY] > 0.0 && dipsp[i][YY] < 0.5*M_PI) {
                            if (dipsp[i][ZZ] < 0.5 * M_PI) {
                                ncolour = 5;
                            } else {
                                ncolour = 6;
                            }      
                        }
                        else if (dipsp[i][YY] > 0.5*M_PI && dipsp[i][YY] < M_PI) 
                        {
                            if (dipsp[i][ZZ] < 0.5 * M_PI) 
                            {
                                ncolour = 7;
                            } 
                            else 
                            {
                                ncolour = 8;
                            }
                        }
                        if (dip3d)
                            fprintf(dip3d,"set arrow %d from %f, %f, %f to %f, %f, %f lt %d  # %d %d\n", 
                                    i+1,
                                    x[ind0][XX],
                                    x[ind0][YY],
                                    x[ind0][ZZ],
                                    x[ind0][XX]+dipole[i][XX]/25, 
                                    x[ind0][YY]+dipole[i][YY]/25, 
                                    x[ind0][ZZ]+dipole[i][ZZ]/25, 
                                    ncolour, ind0, i);
                    }
                } /* End loop of all molecules in frame */
	
                if (dip3d) 
                {
                    fprintf(dip3d,"set title \"t = %4.3f\"\n",t);
                    fprintf(dip3d,"set xrange [0.0:%4.2f]\n",box[XX][XX]);
                    fprintf(dip3d,"set yrange [0.0:%4.2f]\n",box[YY][YY]);
                    fprintf(dip3d,"set zrange [0.0:%4.2f]\n\n",box[ZZ][ZZ]);
                    fprintf(dip3d,"splot 'dummy.dat' using 1:2:3 w vec\n");
                    fprintf(dip3d,"pause -1 'Hit return to continue'\n");
                }
            }
        }
        /* Compute square of total dipole */
        for(m=0; (m<DIM); m++)
            M_av2[m] = M_av[m]*M_av[m];
    
        if (cosaver) 
        {
            compute_avercos(gnx_tot,dipole,&dd,dipaxis,bPairs);
            rms_cos = sqrt(sqr(dipaxis[XX]-0.5)+
                           sqr(dipaxis[YY]-0.5)+
                           sqr(dipaxis[ZZ]-0.5));
            if (bPairs) 
                fprintf(caver,"%10.3e  %10.3e  %10.3e  %10.3e  %10.3e  %10.3e\n",
                        t,dd,rms_cos,dipaxis[XX],dipaxis[YY],dipaxis[ZZ]);
            else
                fprintf(caver,"%10.3e  %10.3e  %10.3e  %10.3e  %10.3e\n",
                        t,rms_cos,dipaxis[XX],dipaxis[YY],dipaxis[ZZ]);
        }
    
        if (bGkr) 
        {
            do_gkr(gkrbin,ncos,gnx,molindex,mols->index,x,dipole,ePBC,box,
                   atom,gkatom);
        }
    
        if (bTotal) 
        {
            tel3 = DIM*teller;
            muall[0][tel3+XX] = M_av[XX];
            muall[0][tel3+YY] = M_av[YY];
            muall[0][tel3+ZZ] = M_av[ZZ];
        }

        /* Write to file the total dipole moment of the box, and its components 
         * for this frame.
         */
        if ((skip == 0) || ((teller % skip) == 0))
            fprintf(outmtot,"%10g  %12.8e %12.8e %12.8e %12.8e\n",
                    t,M_av[XX],M_av[YY],M_av[ZZ],
                    sqrt(M_av2[XX]+M_av2[YY]+M_av2[ZZ]));

        for(m=0; (m<DIM); m++) 
        {
            M[m]  += M_av[m];
            M2[m] += M_av2[m];
            M4[m] += sqr(M_av2[m]);
        }
        /* Increment loop counter */
        teller++;
    
        /* Calculate for output the running averages */
        invtel  = 1.0/teller;
        M2_ave  = (M2[XX]+M2[YY]+M2[ZZ])*invtel;
        M_ave2  = invtel*(invtel*(M[XX]*M[XX] + M[YY]*M[YY] + M[ZZ]*M[ZZ]));
        M_diff  = M2_ave - M_ave2;

        /* Compute volume from box in traj, else we use the one from above */
        if (!bMU)
            volume  = det(box);
        vol_aver += volume;
    
        epsilon = calc_eps(M_diff,(vol_aver/teller),epsilonRF,temp);

        /* Calculate running average for dipole */
        if (mu_ave != 0) 
            mu_aver = (mu_ave/gnx_tot)*invtel;
    
        if ((skip == 0) || ((teller % skip) == 0)) 
        {
            /* Write to file < |M|^2 >, |< M >|^2. And the difference between 
             * the two. Here M is sum mu_i. Further write the finite system
             * Kirkwood G factor and epsilon.
             */
            fprintf(outaver,"%10g  %10.3e %10.3e %10.3e %10.3e\n",
                    t,M2_ave,M_ave2,M_diff,M_ave2/M2_ave);
      
            if (fnadip) 
            {
                real aver;
                gmx_stats_get_average(muframelsq,&aver);
                fprintf(adip, "%10g %f \n", t,aver);
            }
            /*if (dipole)
              printf("%f %f\n", norm(dipole[0]), norm(dipole[1]));
            */      
            if (!bMU || (mu_aver != -1)) 
            {
                /* Finite system Kirkwood G-factor */
                Gk = M_diff/(gnx_tot*mu_aver*mu_aver);
                /* Infinite system Kirkwood G-factor */
                if (epsilonRF == 0.0) 
                    g_k = ((2*epsilon+1)*Gk/(3*epsilon));
                else 
                    g_k = ((2*epsilonRF+epsilon)*(2*epsilon+1)*
                           Gk/(3*epsilon*(2*epsilonRF+1)));
	
                fprintf(outeps,"%10g  %10.3e %10.3e %10.3e\n",t,epsilon,Gk,g_k);

            }
            else 
                fprintf(outeps,"%10g  %12.8e\n",t,epsilon);
        }
        gmx_stats_done(muframelsq);
    
        if (bMU)
            bCont = read_mu_from_enx(fmu,iVol,iMu,mu_t,&volume,&t,nre,fr); 
        else
            bCont = read_next_x(oenv,status,&t,natom,x,box);
        timecheck=check_times(t);
    } while (bCont && (timecheck == 0) );
  
    gmx_rmpbc_done(gpbc);

    if (!bMU)
        close_trj(status);
    
    ffclose(outmtot);
    ffclose(outaver);
    ffclose(outeps);

    if (fnadip)
        ffclose(adip);

    if (cosaver)
        ffclose(caver);

    if (dip3d) {
        fprintf(dip3d,"set xrange [0.0:%4.2f]\n",box[XX][XX]);
        fprintf(dip3d,"set yrange [0.0:%4.2f]\n",box[YY][YY]);
        fprintf(dip3d,"set zrange [0.0:%4.2f]\n\n",box[ZZ][ZZ]);
        fprintf(dip3d,"splot 'dummy.dat' using 1:2:3 w vec\n");
        fprintf(dip3d,"pause -1 'Hit return to continue'\n");
        ffclose(dip3d);
    }

    if (bSlab) {
        dump_slab_dipoles(slabfn,idim,nslices,slab_dipoles,box,teller,oenv);
        sfree(slab_dipoles);
    }
  
    vol_aver /= teller;
    printf("Average volume over run is %g\n",vol_aver);
    if (bGkr) {
        print_gkrbin(gkrfn,gkrbin,gnx[0],teller,vol_aver,oenv);
        print_cmap(cmap,gkrbin,nlevels);
    }
    /* Autocorrelation function */  
    if (bCorr) {
        if (teller < 2) {
            printf("Not enough frames for autocorrelation\n");
        }
        else {
            dt=(t1 - t0)/(teller-1);
            printf("t0 %g, t %g, teller %d\n", t0,t,teller);
      
            mode = eacVector;

            if (bTotal)
                do_autocorr(corf,oenv,"Autocorrelation Function of Total Dipole",
                            teller,1,muall,dt,mode,TRUE);
            else
                do_autocorr(corf,oenv,"Dipole Autocorrelation Function",
                            teller,gnx_tot,muall,dt,
                            mode,strcmp(corrtype,"molsep"));
        }
    }
    if (!bMU) {
        real aver,sigma,error,lsq;

        gmx_stats_get_ase(mulsq,&aver,&sigma,&error);
        printf("\nDipole moment (Debye)\n");
        printf("---------------------\n");
        printf("Average  = %8.4f  Std. Dev. = %8.4f  Error = %8.4f\n",
               aver,sigma,error);
        if (bQuad) {
            rvec a,s,e;
            int mm;
            for(m=0; (m<DIM); m++)
                gmx_stats_get_ase(mulsq,&(a[m]),&(s[m]),&(e[m]));
    
            printf("\nQuadrupole moment (Debye-Ang)\n");
            printf("-----------------------------\n");
            printf("Averages  = %8.4f  %8.4f  %8.4f\n",a[XX],a[YY],a[ZZ]);
            printf("Std. Dev. = %8.4f  %8.4f  %8.4f\n",s[XX],s[YY],s[ZZ]);
            printf("Error     = %8.4f  %8.4f  %8.4f\n",e[XX],e[YY],e[ZZ]);
        }
        printf("\n");
    }
    printf("The following averages for the complete trajectory have been calculated:\n\n");
    printf(" Total < M_x > = %g Debye\n", M[XX]/teller);
    printf(" Total < M_y > = %g Debye\n", M[YY]/teller);
    printf(" Total < M_z > = %g Debye\n\n", M[ZZ]/teller);

    printf(" Total < M_x^2 > = %g Debye^2\n", M2[XX]/teller);
    printf(" Total < M_y^2 > = %g Debye^2\n", M2[YY]/teller);
    printf(" Total < M_z^2 > = %g Debye^2\n\n", M2[ZZ]/teller);

    printf(" Total < |M|^2 > = %g Debye^2\n", M2_ave);
    printf(" Total |< M >|^2 = %g Debye^2\n\n", M_ave2);

    printf(" < |M|^2 > - |< M >|^2 = %g Debye^2\n\n", M_diff);
  
    if (!bMU || (mu_aver != -1)) {
        printf("Finite system Kirkwood g factor G_k = %g\n", Gk);
        printf("Infinite system Kirkwood g factor g_k = %g\n\n", g_k);
    }
    printf("Epsilon = %g\n", epsilon);

    if (!bMU) {
        /* Write to file the dipole moment distibution during the simulation.
         */
        outdd=xvgropen(dipdist,"Dipole Moment Distribution","mu (Debye)","",oenv);
        for(i=0; (i<ndipbin); i++)
            fprintf(outdd,"%10g  %10f\n",
                    (i*mu_max)/ndipbin,dipole_bin[i]/(double)teller);
        ffclose(outdd);
        sfree(dipole_bin);
    }
    if (bGkr) 
        done_gkrbin(&gkrbin);
}
Exemple #10
0
void spectrum(bool bVerbose,
	      char *trj,char *shifts,bool bAbInitio,
	      char *corrfn,char *noefn,
	      int maxframes,bool bFour,bool bFit,int nrestart,
	      int npair,t_pair pair[],int nat,real chem_shifts[],
	      real taum,real maxdist,
	      real w_rls[],rvec xp[],t_idef *idef)
{
  FILE   *fp;
  int    i,j,m,ii,jj,natoms,status,nframes;
  rvec   *x,dx;
  matrix box;
  real   t0,t1,t,dt;
  real   r2,r6,r_3,r_6,tauc;
  rvec   **corr;
  real   **Corr;
  t_sij  *spec;

  snew(spec,npair);
  
  fprintf(stderr,"There is no kill like overkill! Going to malloc %d bytes\n",
	  npair*maxframes*sizeof(corr[0][0]));
  snew(corr,npair);
  for(i=0; (i<npair); i++)
    snew(corr[i],maxframes);
  nframes = 0;
  natoms  = read_first_x(&status,trj,&t0,&x,box);
  if (natoms > nat)
    gmx_fatal(FARGS,"Not enough atoms in trajectory");
  do {
    if (nframes >= maxframes) {
      fprintf(stderr,"\nThere are more than the %d frames you told me!",
	      maxframes);
      break;
    }
    t1 = t;
    if (bVerbose)
      fprintf(stderr,"\rframe: %d",nframes);
    rm_pbc(idef,natoms,box,x,x);
    if (bFit)
      do_fit(natoms,w_rls,xp,x);  
    
    for(i=0; (i<npair); i++) {
      ii = pair[i].ai;
      jj = pair[i].aj;
      rvec_sub(x[ii],x[jj],dx);
      copy_rvec(dx,corr[i][nframes]);
      
      r2  = iprod(dx,dx);
      r6  = r2*r2*r2;
      r_3 = invsqrt(r6);
      r_6 = r_3*r_3;
      spec[i].rij_3 += r_3;
      spec[i].rij_6 += r_6;
      for(m=0; (m<5); m++) {
	spec[i].Ylm[m] = c_add(spec[i].Ylm[m],
			       calc_ylm(m-2,dx,r2,r_3,r_6));
      }
    }
    nframes++;
  } while (read_next_x(status,&t,natoms,x,box));
  close_trj(status);
  if (bVerbose)
    fprintf(stderr,"\n");
 
  fp=ffopen("ylm.out","w");
  calc_aver(fp,nframes,npair,pair,spec,maxdist);
  fclose(fp);
 
  /* Select out the pairs that have to be correlated */
  snew(Corr,npair);
  for(i=j=0; (i<npair); i++) {
    if (spec[i].bNOE) {
      Corr[j] = &(corr[i][0][0]);
      j++;
    }
  }
  fprintf(stderr,"There are %d NOEs in your simulation\n",j);
  if (nframes > 1)
    dt = (t1-t0)/(nframes-1);
  else
    dt = 1;
  do_autocorr(corrfn,"Correlation Function for Interproton Vectors",
	      nframes,j,Corr,dt,eacP2,nrestart,FALSE,FALSE,bFour,TRUE);
  
  calc_tauc(bVerbose,npair,pair,dt,nframes/2,spec,(real **)corr);
  
  plot_spectrum(noefn,npair,pair,spec,taum);
}
Exemple #11
0
int gmx_gyrate(int argc,char *argv[])
{
  const char *desc[] = {
    "g_gyrate computes the radius of gyration of a group of atoms",
    "and the radii of gyration about the x, y and z axes,",
    "as a function of time. The atoms are explicitly mass weighted.[PAR]",
    "With the [TT]-nmol[tt] option the radius of gyration will be calculated",
    "for multiple molecules by splitting the analysis group in equally",
    "sized parts.[PAR]",
    "With the option [TT]-nz[tt] 2D radii of gyration in the x-y plane",
    "of slices along the z-axis are calculated."
  };
  static int  nmol=1,nz=0;
  static bool bQ=FALSE,bRot=FALSE,bMOI=FALSE;
  t_pargs pa[] = {
    { "-nmol", FALSE, etINT, {&nmol},
      "The number of molecules to analyze" },
    { "-q", FALSE, etBOOL, {&bQ},
      "Use absolute value of the charge of an atom as weighting factor instead of mass" },
    { "-p", FALSE, etBOOL, {&bRot},
      "Calculate the radii of gyration about the principal axes." },
    { "-moi", FALSE, etBOOL, {&bMOI},
      "Calculate the moments of inertia (defined by the principal axes)." },
    { "-nz", FALSE, etINT, {&nz},
      "Calculate the 2D radii of gyration of # slices along the z-axis" },
  };
  FILE       *out;
  int        status;
  t_topology top;
  int        ePBC;
  rvec       *x,*x_s;
  rvec       xcm,gvec,gvec1;
  matrix     box,trans;
  bool       bACF;
  real       **moi_trans=NULL;
  int        max_moi=0,delta_moi=100;
  rvec       d,d1;         /* eigenvalues of inertia tensor */
  real       t,t0,tm,gyro;
  int        natoms;
  char       *grpname,title[256];
  int        i,j,m,gnx,nam,mol;
  atom_id    *index;
  char *leg[]  = { "Rg", "RgX", "RgY", "RgZ" }; 
  char *legI[] = { "Itot", "I1", "I2", "I3" }; 
#define NLEG asize(leg) 
  t_filenm fnm[] = {
    { efTRX, "-f",   NULL,       ffREAD }, 
    { efTPS, NULL,   NULL,       ffREAD },
    { efNDX, NULL,   NULL,       ffOPTRD },
    { efXVG, NULL,   "gyrate",   ffWRITE }, 
    { efXVG, "-acf", "moi-acf",  ffOPTWR },
  }; 
#define NFILE asize(fnm) 
  int     npargs;
  t_pargs *ppa;
  
  CopyRight(stderr,argv[0]);
  npargs = asize(pa);
  ppa    = add_acf_pargs(&npargs,pa);

  parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_CAN_VIEW | PCA_BE_NICE,
		    NFILE,fnm,npargs,ppa,asize(desc),desc,0,NULL); 
  bACF = opt2bSet("-acf",NFILE,fnm);
  if (bACF && nmol!=1)
    gmx_fatal(FARGS,"Can only do acf with nmol=1");
  bRot = bRot || bMOI || bACF;
  /*
    if (nz > 0)
    bMOI = TRUE;
  */
  if (bRot) {
    printf("Will rotate system along principal axes\n"); 
    snew(moi_trans,DIM);
  }
  if (bMOI) {
    printf("Will print moments of inertia\n");
    bQ = FALSE;
  }
  if (bQ) 
    printf("Will print radius normalised by charge\n"); 
    
  read_tps_conf(ftp2fn(efTPS,NFILE,fnm),title,&top,&ePBC,&x,NULL,box,TRUE);
  get_index(&top.atoms,ftp2fn_null(efNDX,NFILE,fnm),1,&gnx,&index,&grpname);

  if (nmol > gnx || gnx % nmol != 0) {
    gmx_fatal(FARGS,"The number of atoms in the group (%d) is not a multiple of nmol (%d)",gnx,nmol);
  }
  nam = gnx/nmol;

  natoms=read_first_x(&status,ftp2fn(efTRX,NFILE,fnm),&t,&x,box); 
  snew(x_s,natoms); 

  j  = 0; 
  t0 = t;
  if (bQ) 
    out=xvgropen(ftp2fn(efXVG,NFILE,fnm), 
		 "Radius of Charge","Time (ps)","Rg (nm)"); 
  else if (bMOI)
    out=xvgropen(ftp2fn(efXVG,NFILE,fnm), 
		 "Moments of inertia","Time (ps)","I (a.m.u. nm\\S2\\N)"); 
  else 
    out=xvgropen(ftp2fn(efXVG,NFILE,fnm), 
		 "Radius of gyration","Time (ps)","Rg (nm)"); 
  if (bMOI) 
    xvgr_legend(out,NLEG,legI);
  else {
    if (bRot)
      if (bPrintXvgrCodes())
	fprintf(out,"@ subtitle \"Axes are principal component axes\"\n");
    xvgr_legend(out,NLEG,leg);
  }
  do {
    if (nz == 0)
      rm_pbc(&top.idef,ePBC,natoms,box,x,x_s);
    gyro = 0;
    clear_rvec(gvec);
    clear_rvec(d);
    for(mol=0; mol<nmol; mol++) {
      tm    = sub_xcm(nz==0?x_s:x,nam,index+mol*nam,top.atoms.atom,xcm,bQ);
      if (nz == 0)
	gyro += calc_gyro(x_s,nam,index+mol*nam,top.atoms.atom,
			  tm,gvec1,d1,bQ,bRot,bMOI,trans);
      else
	calc_gyro_z(x,box,nam,index+mol*nam,top.atoms.atom,nz,t,out);
      rvec_inc(gvec,gvec1);
      rvec_inc(d,d1);
    }
    if (nmol > 0) {
      gyro /= nmol;
      svmul(1.0/nmol,gvec,gvec);
      svmul(1.0/nmol,d,d);
    }

    if (nz == 0) {
      if (bRot) {
	if (j >= max_moi) {
	  max_moi += delta_moi;
	  for(m=0; (m<DIM); m++)
	    srenew(moi_trans[m],max_moi*DIM);
	}
	for(m=0; (m<DIM); m++)
	  copy_rvec(trans[m],moi_trans[m]+DIM*j);
	fprintf(out,"%10g  %10g  %10g  %10g  %10g\n",
		t,gyro,d[XX],d[YY],d[ZZ]); }
      else {
	fprintf(out,"%10g  %10g  %10g  %10g  %10g\n",
		t,gyro,gvec[XX],gvec[YY],gvec[ZZ]); }
    }
    j++;
  } while(read_next_x(status,&t,natoms,x,box));
  close_trj(status);
  
  fclose(out);

  if (bACF) {
    int mode = eacVector;
  
    do_autocorr(opt2fn("-acf",NFILE,fnm),
		"Moment of inertia vector ACF",
		j,3,moi_trans,(t-t0)/j,mode,FALSE);
    do_view(opt2fn("-acf",NFILE,fnm),"-nxy");
  }
  
  do_view(ftp2fn(efXVG,NFILE,fnm),"-nxy");
  
  thanx(stderr);
  
  return 0;
}