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