[tools] g_sans - add trajectory avereging
[alexxy/gromacs.git] / src / tools / gmx_sans.c
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
9  *                        VERSION 3.2.0
10  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12  * Copyright (c) 2001-2004, The GROMACS development team,
13  * check out http://www.gromacs.org for more information.
14
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * If you want to redistribute modifications, please consider that
21  * scientific software is very special. Version control is crucial -
22  * bugs must be traceable. We will be happy to consider code for
23  * inclusion in the official distribution, but derived work must not
24  * be called official GROMACS. Details are found in the README & COPYING
25  * files - if they are missing, get the official version at www.gromacs.org.
26  *
27  * To help us fund GROMACS development, we humbly ask that you cite
28  * the papers on the package - you can find them in the top README file.
29  *
30  * For more info, check our website at http://www.gromacs.org
31  *
32  * And Hey:
33  * Green Red Orange Magenta Azure Cyan Skyblue
34  */
35
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #include <ctype.h>
41 #include "smalloc.h"
42 #include "sysstuff.h"
43 #include "typedefs.h"
44 #include "macros.h"
45 #include "vec.h"
46 #include "pbc.h"
47 #include "xvgr.h"
48 #include "copyrite.h"
49 #include "futil.h"
50 #include "statutil.h"
51 #include "tpxio.h"
52 #include "index.h"
53 #include "gstat.h"
54 #include "matio.h"
55 #include "gmx_ana.h"
56 #include "nsfactor.h"
57 #include "gmx_omp.h"
58
59 int gmx_sans(int argc,char *argv[])
60 {
61     const char *desc[] = {
62         "This is simple tool to compute SANS spectra using Debye formula",
63         "It currently uses topology file (since it need to assigne element for each atom)",
64         "[PAR]",
65         "Parameters:[PAR]"
66         "[TT]-pr[tt] Computes normalized g(r) function averaged over trajectory[PAR]",
67         "[TT]-prframe[tt] Computes normalized g(r) function for each frame[PAR]",
68         "[TT]-sq[tt] Computes SANS intensity curve averaged over trajectory[PAR]",
69         "[TT]-sqframe[tt] Computes SANS intensity curve for each frame[PAR]",
70         "[TT]-startq[tt] Starting q value in nm[PAR]",
71         "[TT]-endq[tt] Ending q value in nm[PAR]",
72         "[TT]-qstep[tt] Stepping in q space[PAR]",
73         "Note: When using Debye direct method computational cost increases as",
74         "1/2 * N * (N - 1) where N is atom number in group of interest",
75         "[PAR]",
76         "WARNING: If sq or pr specified this tool can produce large number of files! Up to two times larger than number of frames!"
77     };
78     static gmx_bool bPBC=TRUE;
79     static gmx_bool bNORM=FALSE;
80     static real binwidth=0.2,grid=0.05; /* bins shouldnt be smaller then smallest bond (~0.1nm) length */
81     static real start_q=0.0, end_q=2.0, q_step=0.01;
82     static real mcover=-1;
83     static unsigned int  seed=0;
84     static int           nthreads=-1;
85
86     static const char *emode[]= { NULL, "direct", "mc", NULL };
87     static const char *emethod[]={ NULL, "debye", "fft", NULL };
88
89     gmx_neutron_atomic_structurefactors_t    *gnsf;
90     gmx_sans_t              *gsans;
91
92 #define NPA asize(pa)
93
94     t_pargs pa[] = {
95         { "-bin", FALSE, etREAL, {&binwidth},
96           "[HIDDEN]Binwidth (nm)" },
97         { "-mode", FALSE, etENUM, {emode},
98           "Mode for sans spectra calculation" },
99         { "-mcover", FALSE, etREAL, {&mcover},
100           "Monte-Carlo coverage should be -1(default) or (0,1]"},
101         { "-method", FALSE, etENUM, {emethod},
102           "[HIDDEN]Method for sans spectra calculation" },
103         { "-pbc", FALSE, etBOOL, {&bPBC},
104           "Use periodic boundary conditions for computing distances" },
105         { "-grid", FALSE, etREAL, {&grid},
106           "[HIDDEN]Grid spacing (in nm) for FFTs" },
107         {"-startq", FALSE, etREAL, {&start_q},
108           "Starting q (1/nm) "},
109         {"-endq", FALSE, etREAL, {&end_q},
110           "Ending q (1/nm)"},
111         { "-qstep", FALSE, etREAL, {&q_step},
112           "Stepping in q (1/nm)"},
113         { "-seed",     FALSE, etINT,  {&seed},
114           "Random seed for Monte-Carlo"},
115 #ifdef GMX_OPENMP
116         { "-nt",  FALSE, etINT, {&nthreads},
117           "Number of threads to start"},
118 #endif
119     };
120   FILE      *fp;
121   const char *fnTPX,*fnNDX,*fnTRX,*fnDAT=NULL;
122   t_trxstatus *status;
123   t_topology *top=NULL;
124   t_atom    *atom=NULL;
125   gmx_rmpbc_t  gpbc=NULL;
126   gmx_bool  bTPX;
127   gmx_bool  bFFT=FALSE, bDEBYE=FALSE;
128   gmx_bool  bMC=FALSE;
129   int        ePBC=-1;
130   matrix     box;
131   char       title[STRLEN];
132   rvec       *x;
133   int       natoms;
134   real       t;
135   char       **grpname=NULL;
136   atom_id    *index=NULL;
137   int        isize;
138   int         i,j;
139   char       *hdr=NULL;
140   char       *suffix=NULL;
141   t_filenm   *fnmdup=NULL;
142   gmx_radial_distribution_histogram_t  *prframecurrent=NULL, *pr=NULL;
143   gmx_static_structurefactor_t  *sqframecurrent=NULL, *sq=NULL;
144   output_env_t oenv;
145
146 #define NFILE asize(fnm)
147
148   t_filenm   fnm[] = {
149       { efTPX,  "-s",       NULL,       ffREAD },
150       { efTRX,  "-f",       NULL,       ffREAD },
151       { efNDX,  NULL,       NULL,       ffOPTRD },
152       { efDAT,  "-d",       "nsfactor", ffOPTRD },
153       { efXVG,  "-pr",      "pr",       ffWRITE },
154       { efXVG,  "-sq",       "sq",      ffWRITE },
155       { efXVG,  "-prframe", "prframe",  ffOPTWR },
156       { efXVG,  "-sqframe", "sqframe",  ffOPTWR }
157   };
158
159   nthreads = gmx_omp_get_max_threads();
160
161   CopyRight(stderr,argv[0]);
162   parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_TIME_UNIT | PCA_BE_NICE,
163                     NFILE,fnm,asize(pa),pa,asize(desc),desc,0,NULL,&oenv);
164
165   /* check that binwidth not smaller than smallers distance */
166   check_binwidth(binwidth);
167   check_mcover(mcover);
168
169   /* setting number of omp threads globaly */
170   gmx_omp_set_num_threads(nthreads);
171
172   /* Now try to parse opts for modes */
173   switch(emethod[0][0]) {
174   case 'd':
175       bDEBYE=TRUE;
176       switch(emode[0][0]) {
177       case 'd':
178           bMC=FALSE;
179           break;
180       case 'm':
181           bMC=TRUE;
182           break;
183       default:
184           break;
185       }
186       break;
187   case 'f':
188       bFFT=TRUE;
189       break;
190   default:
191       break;
192   }
193
194   if (bDEBYE) {
195       if (bMC) {
196           fprintf(stderr,"Using Monte Carlo Debye method to calculate spectrum\n");
197       } else {
198           fprintf(stderr,"Using direct Debye method to calculate spectrum\n");
199       }
200   } else if (bFFT) {
201       gmx_fatal(FARGS,"FFT method not implemented!");
202   } else {
203       gmx_fatal(FARGS,"Unknown combination for mode and method!");
204   }
205
206   /* Try to read files */
207   fnDAT = ftp2fn(efDAT,NFILE,fnm);
208   fnTPX = ftp2fn(efTPX,NFILE,fnm);
209   fnTRX = ftp2fn(efTRX,NFILE,fnm);
210
211   gnsf = gmx_neutronstructurefactors_init(fnDAT);
212   fprintf(stderr,"Read %d atom names from %s with neutron scattering parameters\n\n",gnsf->nratoms,fnDAT);
213
214   snew(top,1);
215   snew(grpname,1);
216   snew(index,1);
217
218   bTPX=read_tps_conf(fnTPX,title,top,&ePBC,&x,NULL,box,TRUE);
219
220   printf("\nPlease select group for SANS spectra calculation:\n");
221   get_index(&(top->atoms),ftp2fn_null(efNDX,NFILE,fnm),1,&isize,&index,grpname);
222
223   gsans = gmx_sans_init(top,gnsf);
224
225   /* Prepare reference frame */
226   if (bPBC) {
227       gpbc = gmx_rmpbc_init(&top->idef,ePBC,top->atoms.nr,box);
228       gmx_rmpbc(gpbc,top->atoms.nr,box,x);
229   }
230
231   natoms=read_first_x(oenv,&status,fnTRX,&t,&x,box);
232   if (natoms != top->atoms.nr) {
233       fprintf(stderr,"\nWARNING: number of atoms in tpx (%d) and trajectory (%d) do not match\n",natoms,top->atoms.nr);
234   }
235
236   do {
237       if (bPBC) {
238           gmx_rmpbc(gpbc,top->atoms.nr,box,x);
239       }
240       /* allocate memory for pr */
241       if (pr == NULL) {
242           /* in case its first frame to read */
243           snew(pr,1);
244       }
245       /*  realy calc p(r) */
246       prframecurrent = calc_radial_distribution_histogram(gsans,x,box,index,isize,binwidth,bMC,bNORM,mcover,seed);
247       /* copy prframecurrent -> pr and summ up pr->gr[i] */
248       /* allocate and/or resize memory for pr->gr[i] and pr->r[i] */
249       if (pr->gr == NULL) {
250           /* check if we use pr->gr first time */
251           snew(pr->gr,prframecurrent->grn);
252           snew(pr->r,prframecurrent->grn);
253       } else {
254           /* resize pr->gr and pr->r if needed to preven overruns */
255           if(prframecurrent->grn > pr->grn) {
256               srenew(pr->gr,prframecurrent->grn);
257               srenew(pr->r,prframecurrent->grn);
258           }
259       }
260       pr->grn = prframecurrent->grn;
261       pr->binwidth = prframecurrent->binwidth;
262       /* summ up gr and fill r */
263       for(i=0;i<prframecurrent->grn;i++) {
264           pr->gr[i] += prframecurrent->gr[i];
265           pr->r[i] = prframecurrent->r[i];
266       }
267       /* normalize histo */
268       normalize_probability(prframecurrent->grn,prframecurrent->gr);
269       /* convert p(r) to sq */
270       sqframecurrent = convert_histogram_to_intensity_curve(prframecurrent,start_q,end_q,q_step);
271       /* print frame data if needed */
272       if(opt2fn_null("-prframe",NFILE,fnm)) {
273           snew(hdr,25);
274           snew(suffix,GMX_PATH_MAX);
275           /* prepare header */
276           sprintf(hdr,"g(r), t = %f",t);
277           /* prepare output filename */
278           fnmdup = dup_tfn(NFILE,fnm);
279           sprintf(suffix,"-t%.2f",t);
280           add_suffix_to_output_names(fnmdup,NFILE,suffix);
281           fp = xvgropen(opt2fn_null("-prframe",NFILE,fnmdup),hdr,"Distance (nm)","Probability",oenv);
282           for(i=0;i<prframecurrent->grn;i++) {
283               fprintf(fp,"%10.6f%10.6f\n",prframecurrent->r[i],prframecurrent->gr[i]);
284           }
285           done_filenms(NFILE,fnmdup);
286           fclose(fp);
287           sfree(hdr);
288           sfree(suffix);
289           sfree(fnmdup);
290       }
291       if(opt2fn_null("-sqframe",NFILE,fnm)) {
292           snew(hdr,25);
293           snew(suffix,GMX_PATH_MAX);
294           /* prepare header */
295           sprintf(hdr,"I(q), t = %f",t);
296           /* prepare output filename */
297           fnmdup = dup_tfn(NFILE,fnm);
298           sprintf(suffix,"-t%.2f",t);
299           add_suffix_to_output_names(fnmdup,NFILE,suffix);
300           fp = xvgropen(opt2fn_null("-sqframe",NFILE,fnmdup),hdr,"q (nm^-1)","s(q)/s(0)",oenv);
301           for(i=0;i<sqframecurrent->qn;i++) {
302               fprintf(fp,"%10.6f%10.6f\n",sqframecurrent->q[i],sqframecurrent->s[i]);
303           }
304           done_filenms(NFILE,fnmdup);
305           fclose(fp);
306           sfree(hdr);
307           sfree(suffix);
308           sfree(fnmdup);
309       }
310       /* free pr structure */
311       sfree(prframecurrent->gr);
312       sfree(prframecurrent->r);
313       sfree(prframecurrent);
314       /* free sq structure */
315       sfree(sqframecurrent->q);
316       sfree(sqframecurrent->s);
317       sfree(sqframecurrent);
318   } while (read_next_x(oenv,status,&t,natoms,x,box));
319   close_trj(status);
320
321   /* normalize histo */
322   normalize_probability(pr->grn,pr->gr);
323   sq = convert_histogram_to_intensity_curve(pr,start_q,end_q,q_step);
324   /* prepare pr.xvg */
325   fp = xvgropen(opt2fn_null("-pr",NFILE,fnm),"G(r)","Distance (nm)","Probability",oenv);
326   for(i=0;i<pr->grn;i++)
327       fprintf(fp,"%10.6f%10.6f\n",pr->r[i],pr->gr[i]);
328   xvgrclose(fp);
329
330   /* prepare sq.xvg */
331   fp = xvgropen(opt2fn_null("-sq",NFILE,fnm),"I(q)","q (nm^-1)","s(q)/s(0)",oenv);
332   for(i=0;i<sq->qn;i++) {
333       fprintf(fp,"%10.6f%10.6f\n",sq->q[i],sq->s[i]);
334   }
335   xvgrclose(fp);
336   /*
337    * Clean up memory
338    */
339   sfree(pr->gr);
340   sfree(pr->r);
341   sfree(pr);
342   sfree(sq->q);
343   sfree(sq->s);
344   sfree(sq);
345
346   please_cite(stdout,"Garmay2012");
347   thanx(stderr);
348
349   return 0;
350 }