Merge "Improve master-specific CMake behavior."
[alexxy/gromacs.git] / src / gromacs / gmxana / 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     parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT | PCA_BE_NICE,
162                       NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv);
163
164     /* check that binwidth not smaller than smallers distance */
165     check_binwidth(binwidth);
166     check_mcover(mcover);
167
168     /* setting number of omp threads globaly */
169     gmx_omp_set_num_threads(nthreads);
170
171     /* Now try to parse opts for modes */
172     switch (emethod[0][0])
173     {
174         case 'd':
175             bDEBYE = TRUE;
176             switch (emode[0][0])
177             {
178                 case 'd':
179                     bMC = FALSE;
180                     break;
181                 case 'm':
182                     bMC = TRUE;
183                     break;
184                 default:
185                     break;
186             }
187             break;
188         case 'f':
189             bFFT = TRUE;
190             break;
191         default:
192             break;
193     }
194
195     if (bDEBYE)
196     {
197         if (bMC)
198         {
199             fprintf(stderr, "Using Monte Carlo Debye method to calculate spectrum\n");
200         }
201         else
202         {
203             fprintf(stderr, "Using direct Debye method to calculate spectrum\n");
204         }
205     }
206     else if (bFFT)
207     {
208         gmx_fatal(FARGS, "FFT method not implemented!");
209     }
210     else
211     {
212         gmx_fatal(FARGS, "Unknown combination for mode and method!");
213     }
214
215     /* Try to read files */
216     fnDAT = ftp2fn(efDAT, NFILE, fnm);
217     fnTPX = ftp2fn(efTPX, NFILE, fnm);
218     fnTRX = ftp2fn(efTRX, NFILE, fnm);
219
220     gnsf = gmx_neutronstructurefactors_init(fnDAT);
221     fprintf(stderr, "Read %d atom names from %s with neutron scattering parameters\n\n", gnsf->nratoms, fnDAT);
222
223     snew(top, 1);
224     snew(grpname, 1);
225     snew(index, 1);
226
227     bTPX = read_tps_conf(fnTPX, title, top, &ePBC, &x, NULL, box, TRUE);
228
229     printf("\nPlease select group for SANS spectra calculation:\n");
230     get_index(&(top->atoms), ftp2fn_null(efNDX, NFILE, fnm), 1, &isize, &index, grpname);
231
232     gsans = gmx_sans_init(top, gnsf);
233
234     /* Prepare reference frame */
235     if (bPBC)
236     {
237         gpbc = gmx_rmpbc_init(&top->idef, ePBC, top->atoms.nr, box);
238         gmx_rmpbc(gpbc, top->atoms.nr, box, x);
239     }
240
241     natoms = read_first_x(oenv, &status, fnTRX, &t, &x, box);
242     if (natoms != top->atoms.nr)
243     {
244         fprintf(stderr, "\nWARNING: number of atoms in tpx (%d) and trajectory (%d) do not match\n", natoms, top->atoms.nr);
245     }
246
247     do
248     {
249         if (bPBC)
250         {
251             gmx_rmpbc(gpbc, top->atoms.nr, box, x);
252         }
253         /* allocate memory for pr */
254         if (pr == NULL)
255         {
256             /* in case its first frame to read */
257             snew(pr, 1);
258         }
259         /*  realy calc p(r) */
260         prframecurrent = calc_radial_distribution_histogram(gsans, x, box, index, isize, binwidth, bMC, bNORM, mcover, seed);
261         /* copy prframecurrent -> pr and summ up pr->gr[i] */
262         /* allocate and/or resize memory for pr->gr[i] and pr->r[i] */
263         if (pr->gr == NULL)
264         {
265             /* check if we use pr->gr first time */
266             snew(pr->gr, prframecurrent->grn);
267             snew(pr->r, prframecurrent->grn);
268         }
269         else
270         {
271             /* resize pr->gr and pr->r if needed to preven overruns */
272             if (prframecurrent->grn > pr->grn)
273             {
274                 srenew(pr->gr, prframecurrent->grn);
275                 srenew(pr->r, prframecurrent->grn);
276             }
277         }
278         pr->grn      = prframecurrent->grn;
279         pr->binwidth = prframecurrent->binwidth;
280         /* summ up gr and fill r */
281         for (i = 0; i < prframecurrent->grn; i++)
282         {
283             pr->gr[i] += prframecurrent->gr[i];
284             pr->r[i]   = prframecurrent->r[i];
285         }
286         /* normalize histo */
287         normalize_probability(prframecurrent->grn, prframecurrent->gr);
288         /* convert p(r) to sq */
289         sqframecurrent = convert_histogram_to_intensity_curve(prframecurrent, start_q, end_q, q_step);
290         /* print frame data if needed */
291         if (opt2fn_null("-prframe", NFILE, fnm))
292         {
293             snew(hdr, 25);
294             snew(suffix, GMX_PATH_MAX);
295             /* prepare header */
296             sprintf(hdr, "g(r), t = %f", t);
297             /* prepare output filename */
298             fnmdup = dup_tfn(NFILE, fnm);
299             sprintf(suffix, "-t%.2f", t);
300             add_suffix_to_output_names(fnmdup, NFILE, suffix);
301             fp = xvgropen(opt2fn_null("-prframe", NFILE, fnmdup), hdr, "Distance (nm)", "Probability", oenv);
302             for (i = 0; i < prframecurrent->grn; i++)
303             {
304                 fprintf(fp, "%10.6f%10.6f\n", prframecurrent->r[i], prframecurrent->gr[i]);
305             }
306             done_filenms(NFILE, fnmdup);
307             fclose(fp);
308             sfree(hdr);
309             sfree(suffix);
310             sfree(fnmdup);
311         }
312         if (opt2fn_null("-sqframe", NFILE, fnm))
313         {
314             snew(hdr, 25);
315             snew(suffix, GMX_PATH_MAX);
316             /* prepare header */
317             sprintf(hdr, "I(q), t = %f", t);
318             /* prepare output filename */
319             fnmdup = dup_tfn(NFILE, fnm);
320             sprintf(suffix, "-t%.2f", t);
321             add_suffix_to_output_names(fnmdup, NFILE, suffix);
322             fp = xvgropen(opt2fn_null("-sqframe", NFILE, fnmdup), hdr, "q (nm^-1)", "s(q)/s(0)", oenv);
323             for (i = 0; i < sqframecurrent->qn; i++)
324             {
325                 fprintf(fp, "%10.6f%10.6f\n", sqframecurrent->q[i], sqframecurrent->s[i]);
326             }
327             done_filenms(NFILE, fnmdup);
328             fclose(fp);
329             sfree(hdr);
330             sfree(suffix);
331             sfree(fnmdup);
332         }
333         /* free pr structure */
334         sfree(prframecurrent->gr);
335         sfree(prframecurrent->r);
336         sfree(prframecurrent);
337         /* free sq structure */
338         sfree(sqframecurrent->q);
339         sfree(sqframecurrent->s);
340         sfree(sqframecurrent);
341     }
342     while (read_next_x(oenv, status, &t, natoms, x, box));
343     close_trj(status);
344
345     /* normalize histo */
346     normalize_probability(pr->grn, pr->gr);
347     sq = convert_histogram_to_intensity_curve(pr, start_q, end_q, q_step);
348     /* prepare pr.xvg */
349     fp = xvgropen(opt2fn_null("-pr", NFILE, fnm), "G(r)", "Distance (nm)", "Probability", oenv);
350     for (i = 0; i < pr->grn; i++)
351     {
352         fprintf(fp, "%10.6f%10.6f\n", pr->r[i], pr->gr[i]);
353     }
354     xvgrclose(fp);
355
356     /* prepare sq.xvg */
357     fp = xvgropen(opt2fn_null("-sq", NFILE, fnm), "I(q)", "q (nm^-1)", "s(q)/s(0)", oenv);
358     for (i = 0; i < sq->qn; i++)
359     {
360         fprintf(fp, "%10.6f%10.6f\n", sq->q[i], sq->s[i]);
361     }
362     xvgrclose(fp);
363     /*
364      * Clean up memory
365      */
366     sfree(pr->gr);
367     sfree(pr->r);
368     sfree(pr);
369     sfree(sq->q);
370     sfree(sq->s);
371     sfree(sq);
372
373     please_cite(stdout, "Garmay2012");
374     thanx(stderr);
375
376     return 0;
377 }