Move physics.* to math/units.*
[gromacs.git] / src / gromacs / gmxana / gmx_polystat.c
blobf219ff9c43e5624c517b5bd9456fc2ae630c45ae
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2013,2014, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
41 #include <math.h>
42 #include <string.h>
44 #include "typedefs.h"
45 #include "gromacs/utility/smalloc.h"
46 #include "gromacs/utility/futil.h"
47 #include "gromacs/commandline/pargs.h"
48 #include "gromacs/math/vec.h"
49 #include "index.h"
50 #include "macros.h"
51 #include "gromacs/fileio/xvgr.h"
52 #include "viewit.h"
53 #include "rmpbc.h"
54 #include "gromacs/fileio/tpxio.h"
55 #include "gromacs/fileio/trxio.h"
56 #include "gmx_ana.h"
58 #include "gromacs/linearalgebra/nrjac.h"
60 static void gyro_eigen(double **gyr, double *eig, double **eigv, int *ord)
62 int nrot, d;
64 jacobi(gyr, DIM, eig, eigv, &nrot);
65 /* Order the eigenvalues */
66 ord[0] = 0;
67 ord[2] = 2;
68 for (d = 0; d < DIM; d++)
70 if (eig[d] > eig[ord[0]])
72 ord[0] = d;
74 if (eig[d] < eig[ord[2]])
76 ord[2] = d;
79 for (d = 0; d < DIM; d++)
81 if (ord[0] != d && ord[2] != d)
83 ord[1] = d;
88 /* Calculate mean square internal distances (Auhl et al., JCP 119, 12718) */
89 static void calc_int_dist(double *intd, rvec *x, int i0, int i1)
91 int ii, jj;
92 const int ml = i1 - i0 + 1; /* Number of beads in molecule. */
93 int bd; /* Distance between beads */
94 double d;
96 for (bd = 1; bd < ml; bd++)
98 d = 0.;
99 for (ii = i0; ii <= i1 - bd; ii++)
101 d += distance2(x[ii], x[ii+bd]);
103 d /= ml - bd;
104 intd[bd - 1] += d;
108 int gmx_polystat(int argc, char *argv[])
110 const char *desc[] = {
111 "[THISMODULE] plots static properties of polymers as a function of time",
112 "and prints the average.[PAR]",
113 "By default it determines the average end-to-end distance and radii",
114 "of gyration of polymers. It asks for an index group and split this",
115 "into molecules. The end-to-end distance is then determined using",
116 "the first and the last atom in the index group for each molecules.",
117 "For the radius of gyration the total and the three principal components",
118 "for the average gyration tensor are written.",
119 "With option [TT]-v[tt] the eigenvectors are written.",
120 "With option [TT]-pc[tt] also the average eigenvalues of the individual",
121 "gyration tensors are written.",
122 "With option [TT]-i[tt] the mean square internal distances are",
123 "written.[PAR]",
124 "With option [TT]-p[tt] the persistence length is determined.",
125 "The chosen index group should consist of atoms that are",
126 "consecutively bonded in the polymer mainchains.",
127 "The persistence length is then determined from the cosine of",
128 "the angles between bonds with an index difference that is even,",
129 "the odd pairs are not used, because straight polymer backbones",
130 "are usually all trans and therefore only every second bond aligns.",
131 "The persistence length is defined as number of bonds where",
132 "the average cos reaches a value of 1/e. This point is determined",
133 "by a linear interpolation of log(<cos>)."
135 static gmx_bool bMW = TRUE, bPC = FALSE;
136 t_pargs pa[] = {
137 { "-mw", FALSE, etBOOL, {&bMW},
138 "Use the mass weighting for radii of gyration" },
139 { "-pc", FALSE, etBOOL, {&bPC},
140 "Plot average eigenvalues" }
143 t_filenm fnm[] = {
144 { efTPX, NULL, NULL, ffREAD },
145 { efTRX, "-f", NULL, ffREAD },
146 { efNDX, NULL, NULL, ffOPTRD },
147 { efXVG, "-o", "polystat", ffWRITE },
148 { efXVG, "-v", "polyvec", ffOPTWR },
149 { efXVG, "-p", "persist", ffOPTWR },
150 { efXVG, "-i", "intdist", ffOPTWR }
152 #define NFILE asize(fnm)
154 t_topology *top;
155 output_env_t oenv;
156 int ePBC;
157 int isize, *index, nmol, *molind, mol, nat_min = 0, nat_max = 0;
158 char *grpname;
159 t_trxstatus *status;
160 real t;
161 rvec *x, *bond = NULL;
162 matrix box;
163 int natoms, i, j, frame, ind0, ind1, a, d, d2, ord[DIM] = {0};
164 dvec cm, sum_eig = {0, 0, 0};
165 double **gyr, **gyr_all, eig[DIM], **eigv;
166 double sum_eed2, sum_eed2_tot, sum_gyro, sum_gyro_tot, sum_pers_tot;
167 int *ninp = NULL;
168 double *sum_inp = NULL, pers;
169 double *intd, ymax, ymin;
170 double mmol, m;
171 char title[STRLEN];
172 FILE *out, *outv, *outp, *outi;
173 const char *leg[8] = {
174 "end to end", "<R\\sg\\N>",
175 "<R\\sg\\N> eig1", "<R\\sg\\N> eig2", "<R\\sg\\N> eig3",
176 "<R\\sg\\N eig1>", "<R\\sg\\N eig2>", "<R\\sg\\N eig3>"
178 char **legp, buf[STRLEN];
179 gmx_rmpbc_t gpbc = NULL;
181 if (!parse_common_args(&argc, argv,
182 PCA_CAN_VIEW | PCA_CAN_TIME | PCA_TIME_UNIT | PCA_BE_NICE,
183 NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv))
185 return 0;
188 snew(top, 1);
189 ePBC = read_tpx_top(ftp2fn(efTPX, NFILE, fnm),
190 NULL, box, &natoms, NULL, NULL, NULL, top);
192 fprintf(stderr, "Select a group of polymer mainchain atoms:\n");
193 get_index(&top->atoms, ftp2fn_null(efNDX, NFILE, fnm),
194 1, &isize, &index, &grpname);
196 snew(molind, top->mols.nr+1);
197 nmol = 0;
198 mol = -1;
199 for (i = 0; i < isize; i++)
201 if (i == 0 || index[i] >= top->mols.index[mol+1])
203 molind[nmol++] = i;
206 mol++;
208 while (index[i] >= top->mols.index[mol+1]);
211 molind[nmol] = i;
212 nat_min = top->atoms.nr;
213 nat_max = 0;
214 for (mol = 0; mol < nmol; mol++)
216 nat_min = min(nat_min, molind[mol+1]-molind[mol]);
217 nat_max = max(nat_max, molind[mol+1]-molind[mol]);
219 fprintf(stderr, "Group %s consists of %d molecules\n", grpname, nmol);
220 fprintf(stderr, "Group size per molecule, min: %d atoms, max %d atoms\n",
221 nat_min, nat_max);
223 sprintf(title, "Size of %d polymers", nmol);
224 out = xvgropen(opt2fn("-o", NFILE, fnm), title, output_env_get_xvgr_tlabel(oenv), "(nm)",
225 oenv);
226 xvgr_legend(out, bPC ? 8 : 5, leg, oenv);
228 if (opt2bSet("-v", NFILE, fnm))
230 outv = xvgropen(opt2fn("-v", NFILE, fnm), "Principal components",
231 output_env_get_xvgr_tlabel(oenv), "(nm)", oenv);
232 snew(legp, DIM*DIM);
233 for (d = 0; d < DIM; d++)
235 for (d2 = 0; d2 < DIM; d2++)
237 sprintf(buf, "eig%d %c", d+1, 'x'+d2);
238 legp[d*DIM+d2] = strdup(buf);
241 xvgr_legend(outv, DIM*DIM, (const char**)legp, oenv);
243 else
245 outv = NULL;
248 if (opt2bSet("-p", NFILE, fnm))
250 outp = xvgropen(opt2fn("-p", NFILE, fnm), "Persistence length",
251 output_env_get_xvgr_tlabel(oenv), "bonds", oenv);
252 snew(bond, nat_max-1);
253 snew(sum_inp, nat_min/2);
254 snew(ninp, nat_min/2);
256 else
258 outp = NULL;
261 if (opt2bSet("-i", NFILE, fnm))
263 outi = xvgropen(opt2fn("-i", NFILE, fnm), "Internal distances",
264 "n", "<R\\S2\\N(n)>/n (nm\\S2\\N)", oenv);
265 i = index[molind[1]-1] - index[molind[0]]; /* Length of polymer -1 */
266 snew(intd, i);
268 else
270 intd = NULL;
271 outi = NULL;
274 natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box);
276 snew(gyr, DIM);
277 snew(gyr_all, DIM);
278 snew(eigv, DIM);
279 for (d = 0; d < DIM; d++)
281 snew(gyr[d], DIM);
282 snew(gyr_all[d], DIM);
283 snew(eigv[d], DIM);
286 frame = 0;
287 sum_eed2_tot = 0;
288 sum_gyro_tot = 0;
289 sum_pers_tot = 0;
291 gpbc = gmx_rmpbc_init(&top->idef, ePBC, natoms);
295 gmx_rmpbc(gpbc, natoms, box, x);
297 sum_eed2 = 0;
298 for (d = 0; d < DIM; d++)
300 clear_dvec(gyr_all[d]);
303 if (bPC)
305 clear_dvec(sum_eig);
308 if (outp)
310 for (i = 0; i < nat_min/2; i++)
312 sum_inp[i] = 0;
313 ninp[i] = 0;
317 for (mol = 0; mol < nmol; mol++)
319 ind0 = molind[mol];
320 ind1 = molind[mol+1];
322 /* Determine end to end distance */
323 sum_eed2 += distance2(x[index[ind0]], x[index[ind1-1]]);
325 /* Determine internal distances */
326 if (outi)
328 calc_int_dist(intd, x, index[ind0], index[ind1-1]);
331 /* Determine the radius of gyration */
332 clear_dvec(cm);
333 for (d = 0; d < DIM; d++)
335 clear_dvec(gyr[d]);
337 mmol = 0;
339 for (i = ind0; i < ind1; i++)
341 a = index[i];
342 if (bMW)
344 m = top->atoms.atom[a].m;
346 else
348 m = 1;
350 mmol += m;
351 for (d = 0; d < DIM; d++)
353 cm[d] += m*x[a][d];
354 for (d2 = 0; d2 < DIM; d2++)
356 gyr[d][d2] += m*x[a][d]*x[a][d2];
360 dsvmul(1/mmol, cm, cm);
361 for (d = 0; d < DIM; d++)
363 for (d2 = 0; d2 < DIM; d2++)
365 gyr[d][d2] = gyr[d][d2]/mmol - cm[d]*cm[d2];
366 gyr_all[d][d2] += gyr[d][d2];
369 if (bPC)
371 gyro_eigen(gyr, eig, eigv, ord);
372 for (d = 0; d < DIM; d++)
374 sum_eig[d] += eig[ord[d]];
377 if (outp)
379 for (i = ind0; i < ind1-1; i++)
381 rvec_sub(x[index[i+1]], x[index[i]], bond[i-ind0]);
382 unitv(bond[i-ind0], bond[i-ind0]);
384 for (i = ind0; i < ind1-1; i++)
386 for (j = 0; (i+j < ind1-1 && j < nat_min/2); j += 2)
388 sum_inp[j] += iprod(bond[i-ind0], bond[i-ind0+j]);
389 ninp[j]++;
394 sum_eed2 /= nmol;
396 sum_gyro = 0;
397 for (d = 0; d < DIM; d++)
399 for (d2 = 0; d2 < DIM; d2++)
401 gyr_all[d][d2] /= nmol;
403 sum_gyro += gyr_all[d][d];
406 gyro_eigen(gyr_all, eig, eigv, ord);
408 fprintf(out, "%10.3f %8.4f %8.4f %8.4f %8.4f %8.4f",
409 t*output_env_get_time_factor(oenv),
410 sqrt(sum_eed2), sqrt(sum_gyro),
411 sqrt(eig[ord[0]]), sqrt(eig[ord[1]]), sqrt(eig[ord[2]]));
412 if (bPC)
414 for (d = 0; d < DIM; d++)
416 fprintf(out, " %8.4f", sqrt(sum_eig[d]/nmol));
419 fprintf(out, "\n");
421 if (outv)
423 fprintf(outv, "%10.3f", t*output_env_get_time_factor(oenv));
424 for (d = 0; d < DIM; d++)
426 for (d2 = 0; d2 < DIM; d2++)
428 fprintf(outv, " %6.3f", eigv[ord[d]][d2]);
431 fprintf(outv, "\n");
434 sum_eed2_tot += sum_eed2;
435 sum_gyro_tot += sum_gyro;
437 if (outp)
439 i = -1;
440 for (j = 0; j < nat_min/2; j += 2)
442 sum_inp[j] /= ninp[j];
443 if (i == -1 && sum_inp[j] <= exp(-1.0))
445 i = j;
448 if (i == -1)
450 pers = j;
452 else
454 /* Do linear interpolation on a log scale */
455 pers = i - 2
456 + 2*(log(sum_inp[i-2]) + 1)/(log(sum_inp[i-2]) - log(sum_inp[i]));
458 fprintf(outp, "%10.3f %8.4f\n", t*output_env_get_time_factor(oenv), pers);
459 sum_pers_tot += pers;
462 frame++;
464 while (read_next_x(oenv, status, &t, x, box));
466 gmx_rmpbc_done(gpbc);
468 close_trx(status);
470 gmx_ffclose(out);
471 if (outv)
473 gmx_ffclose(outv);
475 if (outp)
477 gmx_ffclose(outp);
480 sum_eed2_tot /= frame;
481 sum_gyro_tot /= frame;
482 sum_pers_tot /= frame;
483 fprintf(stdout, "\nAverage end to end distance: %.3f (nm)\n",
484 sqrt(sum_eed2_tot));
485 fprintf(stdout, "\nAverage radius of gyration: %.3f (nm)\n",
486 sqrt(sum_gyro_tot));
487 if (opt2bSet("-p", NFILE, fnm))
489 fprintf(stdout, "\nAverage persistence length: %.2f bonds\n",
490 sum_pers_tot);
493 /* Handle printing of internal distances. */
494 if (outi)
496 fprintf(outi, "@ xaxes scale Logarithmic\n");
497 ymax = -1;
498 ymin = 1e300;
499 j = index[molind[1]-1] - index[molind[0]]; /* Polymer length -1. */
500 for (i = 0; i < j; i++)
502 intd[i] /= (i + 1) * frame * nmol;
503 if (intd[i] > ymax)
505 ymax = intd[i];
507 if (intd[i] < ymin)
509 ymin = intd[i];
512 xvgr_world(outi, 1, ymin, j, ymax, oenv);
513 for (i = 0; i < j; i++)
515 fprintf(outi, "%d %8.4f\n", i+1, intd[i]);
517 gmx_ffclose(outi);
520 do_view(oenv, opt2fn("-o", NFILE, fnm), "-nxy");
521 if (opt2bSet("-v", NFILE, fnm))
523 do_view(oenv, opt2fn("-v", NFILE, fnm), "-nxy");
525 if (opt2bSet("-p", NFILE, fnm))
527 do_view(oenv, opt2fn("-p", NFILE, fnm), "-nxy");
530 return 0;