Update copyright statements and change license to LGPL
[alexxy/gromacs.git] / src / tools / gmx_vanhove.c
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team,
6  * check out http://www.gromacs.org for more information.
7  * Copyright (c) 2012, by the GROMACS development team, led by
8  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9  * others, as listed in the AUTHORS file in the top-level source
10  * directory and at http://www.gromacs.org.
11  *
12  * GROMACS is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public License
14  * as published by the Free Software Foundation; either version 2.1
15  * of the License, or (at your option) any later version.
16  *
17  * GROMACS is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with GROMACS; if not, see
24  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
26  *
27  * If you want to redistribute modifications to GROMACS, please
28  * consider that scientific software is very special. Version
29  * control is crucial - bugs must be traceable. We will be happy to
30  * consider code for inclusion in the official distribution, but
31  * derived work must not be called official GROMACS. Details are found
32  * in the README & COPYING files - if they are missing, get the
33  * official version at http://www.gromacs.org.
34  *
35  * To help us fund GROMACS development, we humbly ask that you cite
36  * the research papers on the package. Check out http://www.gromacs.org.
37  */
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #include <string.h>
43 #include <ctype.h>
44 #include <math.h>
45
46 #include "sysstuff.h"
47 #include "smalloc.h"
48 #include "macros.h"
49 #include "statutil.h"
50 #include "maths.h"
51 #include "futil.h"
52 #include "index.h"
53 #include "copyrite.h"
54 #include "typedefs.h"
55 #include "xvgr.h"
56 #include "gstat.h"
57 #include "tpxio.h"
58 #include "vec.h"
59 #include "matio.h"
60 #include "gmx_ana.h"
61
62
63 int gmx_vanhove(int argc,char *argv[])
64 {
65   const char *desc[] = {
66     "[TT]g_vanhove[tt] computes the Van Hove correlation function.",
67     "The Van Hove G(r,t) is the probability that a particle that is at r[SUB]0[sub]",
68     "at time zero can be found at position r[SUB]0[sub]+r at time t.",
69     "[TT]g_vanhove[tt] determines G not for a vector r, but for the length of r.",
70     "Thus it gives the probability that a particle moves a distance of r",
71     "in time t.",
72     "Jumps across the periodic boundaries are removed.",
73     "Corrections are made for scaling due to isotropic",
74     "or anisotropic pressure coupling.",
75     "[PAR]",
76     "With option [TT]-om[tt] the whole matrix can be written as a function",
77     "of t and r or as a function of [SQRT]t[sqrt] and r (option [TT]-sqrt[tt]).",
78     "[PAR]",
79     "With option [TT]-or[tt] the Van Hove function is plotted for one",
80     "or more values of t. Option [TT]-nr[tt] sets the number of times,",
81     "option [TT]-fr[tt] the number spacing between the times.",
82     "The binwidth is set with option [TT]-rbin[tt]. The number of bins",
83     "is determined automatically.",
84     "[PAR]",
85     "With option [TT]-ot[tt] the integral up to a certain distance",
86     "(option [TT]-rt[tt]) is plotted as a function of time.",
87     "[PAR]",
88     "For all frames that are read the coordinates of the selected particles",
89     "are stored in memory. Therefore the program may use a lot of memory.",
90     "For options [TT]-om[tt] and [TT]-ot[tt] the program may be slow.",
91     "This is because the calculation scales as the number of frames times",
92     "[TT]-fm[tt] or [TT]-ft[tt].",
93     "Note that with the [TT]-dt[tt] option the memory usage and calculation",
94     "time can be reduced."
95   };
96   static int fmmax=0,ftmax=0,nlev=81,nr=1,fshift=0;
97   static real sbin=0,rmax=2,rbin=0.01,mmax=0,rint=0;
98   t_pargs pa[] = {
99     { "-sqrt",    FALSE, etREAL,{&sbin},
100       "Use [SQRT]t[sqrt] on the matrix axis which binspacing # in [SQRT]ps[sqrt]" },
101     { "-fm",      FALSE, etINT, {&fmmax},
102       "Number of frames in the matrix, 0 is plot all" },
103     { "-rmax",    FALSE, etREAL, {&rmax},
104       "Maximum r in the matrix (nm)" },
105     { "-rbin",    FALSE, etREAL, {&rbin},
106       "Binwidth in the matrix and for [TT]-or[tt] (nm)" },
107     { "-mmax",    FALSE, etREAL, {&mmax},
108       "Maximum density in the matrix, 0 is calculate (1/nm)" },
109     { "-nlevels" ,FALSE, etINT,  {&nlev}, 
110       "Number of levels in the matrix" },
111     { "-nr",      FALSE, etINT, {&nr},
112       "Number of curves for the [TT]-or[tt] output" },
113     { "-fr",      FALSE, etINT, {&fshift},
114       "Frame spacing for the [TT]-or[tt] output" },
115     { "-rt",      FALSE, etREAL, {&rint},
116       "Integration limit for the [TT]-ot[tt] output (nm)" },
117     { "-ft",      FALSE, etINT, {&ftmax},
118       "Number of frames in the [TT]-ot[tt] output, 0 is plot all" }
119   };
120 #define NPA asize(pa)
121
122   t_filenm fnm[] = { 
123     { efTRX, NULL, NULL,  ffREAD },
124     { efTPS, NULL, NULL,  ffREAD }, 
125     { efNDX, NULL, NULL,  ffOPTRD },
126     { efXPM, "-om", "vanhove", ffOPTWR },
127     { efXVG, "-or", "vanhove_r", ffOPTWR },
128     { efXVG, "-ot", "vanhove_t", ffOPTWR }
129   };
130 #define NFILE asize(fnm)
131
132   output_env_t oenv;
133   const char *matfile,*otfile,*orfile;
134   char     title[256];
135   t_topology top;
136   int      ePBC;
137   matrix   boxtop,box,*sbox,avbox,corr;
138   rvec     *xtop,*x,**sx;
139   int      isize,nalloc,nallocn,natom;
140   t_trxstatus *status;
141   atom_id  *index;
142   char     *grpname;
143   int      nfr,f,ff,i,m,mat_nx=0,nbin=0,bin,mbin,fbin;
144   real     *time,t,invbin=0,rmax2=0,rint2=0,d2;
145   real     invsbin=0,matmax,normfac,dt,*tickx,*ticky;
146   char     buf[STRLEN],**legend;
147   real     **mat=NULL;
148   int      *pt=NULL,**pr=NULL,*mcount=NULL,*tcount=NULL,*rcount=NULL;
149   FILE     *fp;
150   t_rgb    rlo={1,1,1}, rhi={0,0,0};
151
152   CopyRight(stderr,argv[0]);
153
154   parse_common_args(&argc,argv,PCA_CAN_VIEW | PCA_CAN_TIME | PCA_BE_NICE,
155                     NFILE,fnm,asize(pa),pa,asize(desc),desc,0,NULL,&oenv);
156   
157   matfile = opt2fn_null("-om",NFILE,fnm);
158   if (opt2parg_bSet("-fr",NPA,pa))
159     orfile  = opt2fn("-or",NFILE,fnm);
160   else
161     orfile  = opt2fn_null("-or",NFILE,fnm);
162   if (opt2parg_bSet("-rt",NPA,pa))
163     otfile  = opt2fn("-ot",NFILE,fnm);
164   else
165     otfile  = opt2fn_null("-ot",NFILE,fnm);
166   
167   if (!matfile && !otfile && !orfile) {
168     fprintf(stderr,
169             "For output set one (or more) of the output file options\n");
170     exit(0);
171   }
172   
173   read_tps_conf(ftp2fn(efTPS,NFILE,fnm),title,&top,&ePBC,&xtop,NULL,boxtop,
174                 FALSE); 
175   get_index(&top.atoms,ftp2fn_null(efNDX,NFILE,fnm),1,&isize,&index,&grpname);
176   
177   nalloc = 0;
178   time = NULL;
179   sbox = NULL;
180   sx   = NULL;
181   clear_mat(avbox);
182
183   natom=read_first_x(oenv,&status,ftp2fn(efTRX,NFILE,fnm),&t,&x,box);
184   nfr = 0;
185   do {
186     if (nfr >= nalloc) {
187       nalloc += 100;
188       srenew(time,nalloc);
189       srenew(sbox,nalloc);
190       srenew(sx,nalloc);
191     }
192     
193     time[nfr] = t;
194     copy_mat(box,sbox[nfr]);
195     /* This assumes that the off-diagonal box elements
196      * are not affected by jumps across the periodic boundaries.
197      */
198     m_add(avbox,box,avbox);
199     snew(sx[nfr],isize);
200     for(i=0; i<isize; i++)
201      copy_rvec(x[index[i]],sx[nfr][i]);
202     
203     nfr++;
204   } while (read_next_x(oenv,status,&t,natom,x,box));
205
206   /* clean up */
207   sfree(x);
208   close_trj(status);
209   
210   fprintf(stderr,"Read %d frames\n",nfr);
211
212   dt = (time[nfr-1] - time[0])/(nfr - 1);
213   /* Some ugly rounding to get nice nice times in the output */
214   dt = (int)(10000.0*dt + 0.5)/10000.0;
215
216   invbin = 1.0/rbin;
217
218   if (matfile) {
219     if (fmmax <= 0 || fmmax >= nfr)
220       fmmax = nfr - 1;
221     snew(mcount,fmmax);
222     nbin = (int)(rmax*invbin + 0.5);
223     if (sbin == 0) {
224       mat_nx = fmmax + 1;
225     } else {
226       invsbin = 1.0/sbin;
227       mat_nx = sqrt(fmmax*dt)*invsbin + 1;
228     }
229     snew(mat,mat_nx);
230     for(f=0; f<mat_nx; f++)
231       snew(mat[f],nbin);
232     rmax2 = sqr(nbin*rbin);
233     /* Initialize time zero */
234     mat[0][0] = nfr*isize;
235     mcount[0] += nfr;
236   } else {
237     fmmax = 0;
238   }
239   
240   if (orfile) {
241     snew(pr,nr);
242     nalloc = 0;
243     snew(rcount,nr);
244   }
245   
246   if (otfile) {
247     if (ftmax <= 0)
248       ftmax = nfr - 1;
249     snew(tcount,ftmax);
250     snew(pt,nfr);
251     rint2 = rint*rint;
252     /* Initialize time zero */
253     pt[0] = nfr*isize;
254     tcount[0] += nfr;
255   } else {
256     ftmax = 0;
257   }
258
259   msmul(avbox,1.0/nfr,avbox);
260   for(f=0; f<nfr; f++) {
261     if (f % 100 == 0)
262       fprintf(stderr,"\rProcessing frame %d",f);
263     /* Scale all the configuration to the average box */
264     m_inv_ur0(sbox[f],corr);
265     mmul_ur0(avbox,corr,corr);
266     for(i=0; i<isize; i++) {
267       mvmul_ur0(corr,sx[f][i],sx[f][i]);
268       if (f > 0) {
269         /* Correct for periodic jumps */
270         for(m=DIM-1; m>=0; m--) {
271           while(sx[f][i][m] - sx[f-1][i][m] > 0.5*avbox[m][m])
272             rvec_dec(sx[f][i],avbox[m]);
273           while(sx[f][i][m] - sx[f-1][i][m] <= -0.5*avbox[m][m])
274             rvec_inc(sx[f][i],avbox[m]);
275         }
276       }
277     }
278     for(ff=0; ff<f; ff++) {
279       fbin = f - ff;
280       if (fbin <= fmmax || fbin <= ftmax) {
281         if (sbin == 0)
282           mbin = fbin;
283         else
284           mbin = (int)(sqrt(fbin*dt)*invsbin + 0.5);
285         for(i=0; i<isize; i++) {
286           d2 = distance2(sx[f][i],sx[ff][i]);
287           if (mbin < mat_nx && d2 < rmax2) {
288             bin = (int)(sqrt(d2)*invbin + 0.5);
289             if (bin < nbin) {
290               mat[mbin][bin] += 1;
291             }
292           }
293           if (fbin <= ftmax && d2 <= rint2)
294             pt[fbin]++;
295         }
296         if (matfile)
297           mcount[mbin]++;
298         if (otfile)
299           tcount[fbin]++;
300       }
301     }
302     if (orfile) {
303       for(fbin=0; fbin<nr; fbin++) {
304         ff = f - (fbin + 1)*fshift;
305         if (ff >= 0) {
306           for(i=0; i<isize; i++) {
307             d2 = distance2(sx[f][i],sx[ff][i]);
308             bin = (int)(sqrt(d2)*invbin);
309             if (bin >= nalloc) {
310               nallocn = 10*(bin/10) + 11;
311               for(m=0; m<nr; m++) {
312                 srenew(pr[m],nallocn);
313                 for(i=nalloc; i<nallocn; i++)
314                   pr[m][i] = 0;
315               }
316               nalloc = nallocn;
317             }
318             pr[fbin][bin]++;
319           }
320           rcount[fbin]++;
321         }
322       }
323     }
324   }
325   fprintf(stderr,"\n");
326   
327   if (matfile) {
328     matmax = 0;
329     for(f=0; f<mat_nx; f++) {
330       normfac = 1.0/(mcount[f]*isize*rbin);
331       for(i=0; i<nbin; i++) {
332         mat[f][i] *= normfac;
333         if (mat[f][i] > matmax && (f!=0 || i!=0))
334           matmax = mat[f][i];
335       }
336     }
337     fprintf(stdout,"Value at (0,0): %.3f, maximum of the rest %.3f\n",
338             mat[0][0],matmax);
339     if (mmax > 0)
340       matmax = mmax;
341     snew(tickx,mat_nx);
342     for(f=0; f<mat_nx; f++) {
343       if (sbin == 0)
344         tickx[f] = f*dt;
345       else
346         tickx[f] = f*sbin;
347     }
348     snew(ticky,nbin+1);
349     for(i=0; i<=nbin; i++)
350       ticky[i] = i*rbin;
351     fp = ffopen(matfile,"w");
352     write_xpm(fp,MAT_SPATIAL_Y,"Van Hove function","G (1/nm)",
353               sbin==0 ? "time (ps)" : "sqrt(time) (ps^1/2)","r (nm)",
354               mat_nx,nbin,tickx,ticky,mat,0,matmax,rlo,rhi,&nlev);     
355     ffclose(fp);
356   }
357   
358   if (orfile) {
359     fp = xvgropen(orfile,"Van Hove function","r (nm)","G (nm\\S-1\\N)",oenv);
360     fprintf(fp,"@ subtitle \"for particles in group %s\"\n",grpname);
361     snew(legend,nr);
362     for(fbin=0; fbin<nr; fbin++) {
363       sprintf(buf,"%g ps",(fbin + 1)*fshift*dt);
364       legend[fbin] = strdup(buf);
365     }
366     xvgr_legend(fp,nr,(const char**)legend,oenv);
367     for(i=0; i<nalloc; i++) {
368       fprintf(fp,"%g",i*rbin);
369       for(fbin=0; fbin<nr; fbin++)
370         fprintf(fp," %g",
371                 (real)pr[fbin][i]/(rcount[fbin]*isize*rbin*(i==0 ? 0.5 : 1)));
372       fprintf(fp,"\n");
373     }
374     ffclose(fp);
375   }
376   
377   if (otfile) {
378     sprintf(buf,"Probability of moving less than %g nm",rint);
379     fp = xvgropen(otfile,buf,"t (ps)","",oenv);
380     fprintf(fp,"@ subtitle \"for particles in group %s\"\n",grpname);
381     for(f=0; f<=ftmax; f++)
382       fprintf(fp,"%g %g\n",f*dt,(real)pt[f]/(tcount[f]*isize));
383     ffclose(fp);
384   }
385
386   do_view(oenv, matfile,NULL);
387   do_view(oenv, orfile,NULL);
388   do_view(oenv, otfile,NULL);
389
390   thanx(stderr);
391   
392   return 0;
393 }