Moved first batch of analysis tool source to C++
[gromacs.git] / src / gromacs / gmxana / gmx_polystat.c
blobd174119ac54301394b32234d7852457921f6a5ad
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,2015, 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 #include "gmxpre.h"
39 #include <math.h>
40 #include <string.h>
42 #include "gromacs/commandline/pargs.h"
43 #include "gromacs/fileio/tpxio.h"
44 #include "gromacs/fileio/trxio.h"
45 #include "gromacs/fileio/xvgr.h"
46 #include "gromacs/gmxana/gmx_ana.h"
47 #include "gromacs/legacyheaders/macros.h"
48 #include "gromacs/legacyheaders/typedefs.h"
49 #include "gromacs/legacyheaders/viewit.h"
50 #include "gromacs/linearalgebra/nrjac.h"
51 #include "gromacs/math/vec.h"
52 #include "gromacs/pbcutil/rmpbc.h"
53 #include "gromacs/topology/index.h"
54 #include "gromacs/utility/cstringutil.h"
55 #include "gromacs/utility/futil.h"
56 #include "gromacs/utility/smalloc.h"
58 static void gyro_eigen(double **gyr, double *eig, double **eigv, int *ord)
60 int nrot, d;
62 jacobi(gyr, DIM, eig, eigv, &nrot);
63 /* Order the eigenvalues */
64 ord[0] = 0;
65 ord[2] = 2;
66 for (d = 0; d < DIM; d++)
68 if (eig[d] > eig[ord[0]])
70 ord[0] = d;
72 if (eig[d] < eig[ord[2]])
74 ord[2] = d;
77 for (d = 0; d < DIM; d++)
79 if (ord[0] != d && ord[2] != d)
81 ord[1] = d;
86 /* Calculate mean square internal distances (Auhl et al., JCP 119, 12718) */
87 static void calc_int_dist(double *intd, rvec *x, int i0, int i1)
89 int ii, jj;
90 const int ml = i1 - i0 + 1; /* Number of beads in molecule. */
91 int bd; /* Distance between beads */
92 double d;
94 for (bd = 1; bd < ml; bd++)
96 d = 0.;
97 for (ii = i0; ii <= i1 - bd; ii++)
99 d += distance2(x[ii], x[ii+bd]);
101 d /= ml - bd;
102 intd[bd - 1] += d;
106 int gmx_polystat(int argc, char *argv[])
108 const char *desc[] = {
109 "[THISMODULE] plots static properties of polymers as a function of time",
110 "and prints the average.[PAR]",
111 "By default it determines the average end-to-end distance and radii",
112 "of gyration of polymers. It asks for an index group and split this",
113 "into molecules. The end-to-end distance is then determined using",
114 "the first and the last atom in the index group for each molecules.",
115 "For the radius of gyration the total and the three principal components",
116 "for the average gyration tensor are written.",
117 "With option [TT]-v[tt] the eigenvectors are written.",
118 "With option [TT]-pc[tt] also the average eigenvalues of the individual",
119 "gyration tensors are written.",
120 "With option [TT]-i[tt] the mean square internal distances are",
121 "written.[PAR]",
122 "With option [TT]-p[tt] the persistence length is determined.",
123 "The chosen index group should consist of atoms that are",
124 "consecutively bonded in the polymer mainchains.",
125 "The persistence length is then determined from the cosine of",
126 "the angles between bonds with an index difference that is even,",
127 "the odd pairs are not used, because straight polymer backbones",
128 "are usually all trans and therefore only every second bond aligns.",
129 "The persistence length is defined as number of bonds where",
130 "the average cos reaches a value of 1/e. This point is determined",
131 "by a linear interpolation of [LOG]<cos>[log]."
133 static gmx_bool bMW = TRUE, bPC = FALSE;
134 t_pargs pa[] = {
135 { "-mw", FALSE, etBOOL, {&bMW},
136 "Use the mass weighting for radii of gyration" },
137 { "-pc", FALSE, etBOOL, {&bPC},
138 "Plot average eigenvalues" }
141 t_filenm fnm[] = {
142 { efTPR, NULL, NULL, ffREAD },
143 { efTRX, "-f", NULL, ffREAD },
144 { efNDX, NULL, NULL, ffOPTRD },
145 { efXVG, "-o", "polystat", ffWRITE },
146 { efXVG, "-v", "polyvec", ffOPTWR },
147 { efXVG, "-p", "persist", ffOPTWR },
148 { efXVG, "-i", "intdist", ffOPTWR }
150 #define NFILE asize(fnm)
152 t_topology *top;
153 output_env_t oenv;
154 int ePBC;
155 int isize, *index, nmol, *molind, mol, nat_min = 0, nat_max = 0;
156 char *grpname;
157 t_trxstatus *status;
158 real t;
159 rvec *x, *bond = NULL;
160 matrix box;
161 int natoms, i, j, frame, ind0, ind1, a, d, d2, ord[DIM] = {0};
162 dvec cm, sum_eig = {0, 0, 0};
163 double **gyr, **gyr_all, eig[DIM], **eigv;
164 double sum_eed2, sum_eed2_tot, sum_gyro, sum_gyro_tot, sum_pers_tot;
165 int *ninp = NULL;
166 double *sum_inp = NULL, pers;
167 double *intd, ymax, ymin;
168 double mmol, m;
169 char title[STRLEN];
170 FILE *out, *outv, *outp, *outi;
171 const char *leg[8] = {
172 "end to end", "<R\\sg\\N>",
173 "<R\\sg\\N> eig1", "<R\\sg\\N> eig2", "<R\\sg\\N> eig3",
174 "<R\\sg\\N eig1>", "<R\\sg\\N eig2>", "<R\\sg\\N eig3>"
176 char **legp, buf[STRLEN];
177 gmx_rmpbc_t gpbc = NULL;
179 if (!parse_common_args(&argc, argv,
180 PCA_CAN_VIEW | PCA_CAN_TIME | PCA_TIME_UNIT,
181 NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv))
183 return 0;
186 snew(top, 1);
187 ePBC = read_tpx_top(ftp2fn(efTPR, NFILE, fnm),
188 NULL, box, &natoms, NULL, NULL, NULL, top);
190 fprintf(stderr, "Select a group of polymer mainchain atoms:\n");
191 get_index(&top->atoms, ftp2fn_null(efNDX, NFILE, fnm),
192 1, &isize, &index, &grpname);
194 snew(molind, top->mols.nr+1);
195 nmol = 0;
196 mol = -1;
197 for (i = 0; i < isize; i++)
199 if (i == 0 || index[i] >= top->mols.index[mol+1])
201 molind[nmol++] = i;
204 mol++;
206 while (index[i] >= top->mols.index[mol+1]);
209 molind[nmol] = i;
210 nat_min = top->atoms.nr;
211 nat_max = 0;
212 for (mol = 0; mol < nmol; mol++)
214 nat_min = min(nat_min, molind[mol+1]-molind[mol]);
215 nat_max = max(nat_max, molind[mol+1]-molind[mol]);
217 fprintf(stderr, "Group %s consists of %d molecules\n", grpname, nmol);
218 fprintf(stderr, "Group size per molecule, min: %d atoms, max %d atoms\n",
219 nat_min, nat_max);
221 sprintf(title, "Size of %d polymers", nmol);
222 out = xvgropen(opt2fn("-o", NFILE, fnm), title, output_env_get_xvgr_tlabel(oenv), "(nm)",
223 oenv);
224 xvgr_legend(out, bPC ? 8 : 5, leg, oenv);
226 if (opt2bSet("-v", NFILE, fnm))
228 outv = xvgropen(opt2fn("-v", NFILE, fnm), "Principal components",
229 output_env_get_xvgr_tlabel(oenv), "(nm)", oenv);
230 snew(legp, DIM*DIM);
231 for (d = 0; d < DIM; d++)
233 for (d2 = 0; d2 < DIM; d2++)
235 sprintf(buf, "eig%d %c", d+1, 'x'+d2);
236 legp[d*DIM+d2] = gmx_strdup(buf);
239 xvgr_legend(outv, DIM*DIM, (const char**)legp, oenv);
241 else
243 outv = NULL;
246 if (opt2bSet("-p", NFILE, fnm))
248 outp = xvgropen(opt2fn("-p", NFILE, fnm), "Persistence length",
249 output_env_get_xvgr_tlabel(oenv), "bonds", oenv);
250 snew(bond, nat_max-1);
251 snew(sum_inp, nat_min/2);
252 snew(ninp, nat_min/2);
254 else
256 outp = NULL;
259 if (opt2bSet("-i", NFILE, fnm))
261 outi = xvgropen(opt2fn("-i", NFILE, fnm), "Internal distances",
262 "n", "<R\\S2\\N(n)>/n (nm\\S2\\N)", oenv);
263 i = index[molind[1]-1] - index[molind[0]]; /* Length of polymer -1 */
264 snew(intd, i);
266 else
268 intd = NULL;
269 outi = NULL;
272 natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box);
274 snew(gyr, DIM);
275 snew(gyr_all, DIM);
276 snew(eigv, DIM);
277 for (d = 0; d < DIM; d++)
279 snew(gyr[d], DIM);
280 snew(gyr_all[d], DIM);
281 snew(eigv[d], DIM);
284 frame = 0;
285 sum_eed2_tot = 0;
286 sum_gyro_tot = 0;
287 sum_pers_tot = 0;
289 gpbc = gmx_rmpbc_init(&top->idef, ePBC, natoms);
293 gmx_rmpbc(gpbc, natoms, box, x);
295 sum_eed2 = 0;
296 for (d = 0; d < DIM; d++)
298 clear_dvec(gyr_all[d]);
301 if (bPC)
303 clear_dvec(sum_eig);
306 if (outp)
308 for (i = 0; i < nat_min/2; i++)
310 sum_inp[i] = 0;
311 ninp[i] = 0;
315 for (mol = 0; mol < nmol; mol++)
317 ind0 = molind[mol];
318 ind1 = molind[mol+1];
320 /* Determine end to end distance */
321 sum_eed2 += distance2(x[index[ind0]], x[index[ind1-1]]);
323 /* Determine internal distances */
324 if (outi)
326 calc_int_dist(intd, x, index[ind0], index[ind1-1]);
329 /* Determine the radius of gyration */
330 clear_dvec(cm);
331 for (d = 0; d < DIM; d++)
333 clear_dvec(gyr[d]);
335 mmol = 0;
337 for (i = ind0; i < ind1; i++)
339 a = index[i];
340 if (bMW)
342 m = top->atoms.atom[a].m;
344 else
346 m = 1;
348 mmol += m;
349 for (d = 0; d < DIM; d++)
351 cm[d] += m*x[a][d];
352 for (d2 = 0; d2 < DIM; d2++)
354 gyr[d][d2] += m*x[a][d]*x[a][d2];
358 dsvmul(1/mmol, cm, cm);
359 for (d = 0; d < DIM; d++)
361 for (d2 = 0; d2 < DIM; d2++)
363 gyr[d][d2] = gyr[d][d2]/mmol - cm[d]*cm[d2];
364 gyr_all[d][d2] += gyr[d][d2];
367 if (bPC)
369 gyro_eigen(gyr, eig, eigv, ord);
370 for (d = 0; d < DIM; d++)
372 sum_eig[d] += eig[ord[d]];
375 if (outp)
377 for (i = ind0; i < ind1-1; i++)
379 rvec_sub(x[index[i+1]], x[index[i]], bond[i-ind0]);
380 unitv(bond[i-ind0], bond[i-ind0]);
382 for (i = ind0; i < ind1-1; i++)
384 for (j = 0; (i+j < ind1-1 && j < nat_min/2); j += 2)
386 sum_inp[j] += iprod(bond[i-ind0], bond[i-ind0+j]);
387 ninp[j]++;
392 sum_eed2 /= nmol;
394 sum_gyro = 0;
395 for (d = 0; d < DIM; d++)
397 for (d2 = 0; d2 < DIM; d2++)
399 gyr_all[d][d2] /= nmol;
401 sum_gyro += gyr_all[d][d];
404 gyro_eigen(gyr_all, eig, eigv, ord);
406 fprintf(out, "%10.3f %8.4f %8.4f %8.4f %8.4f %8.4f",
407 t*output_env_get_time_factor(oenv),
408 sqrt(sum_eed2), sqrt(sum_gyro),
409 sqrt(eig[ord[0]]), sqrt(eig[ord[1]]), sqrt(eig[ord[2]]));
410 if (bPC)
412 for (d = 0; d < DIM; d++)
414 fprintf(out, " %8.4f", sqrt(sum_eig[d]/nmol));
417 fprintf(out, "\n");
419 if (outv)
421 fprintf(outv, "%10.3f", t*output_env_get_time_factor(oenv));
422 for (d = 0; d < DIM; d++)
424 for (d2 = 0; d2 < DIM; d2++)
426 fprintf(outv, " %6.3f", eigv[ord[d]][d2]);
429 fprintf(outv, "\n");
432 sum_eed2_tot += sum_eed2;
433 sum_gyro_tot += sum_gyro;
435 if (outp)
437 i = -1;
438 for (j = 0; j < nat_min/2; j += 2)
440 sum_inp[j] /= ninp[j];
441 if (i == -1 && sum_inp[j] <= exp(-1.0))
443 i = j;
446 if (i == -1)
448 pers = j;
450 else
452 /* Do linear interpolation on a log scale */
453 pers = i - 2
454 + 2*(log(sum_inp[i-2]) + 1)/(log(sum_inp[i-2]) - log(sum_inp[i]));
456 fprintf(outp, "%10.3f %8.4f\n", t*output_env_get_time_factor(oenv), pers);
457 sum_pers_tot += pers;
460 frame++;
462 while (read_next_x(oenv, status, &t, x, box));
464 gmx_rmpbc_done(gpbc);
466 close_trx(status);
468 xvgrclose(out);
469 if (outv)
471 xvgrclose(outv);
473 if (outp)
475 xvgrclose(outp);
478 sum_eed2_tot /= frame;
479 sum_gyro_tot /= frame;
480 sum_pers_tot /= frame;
481 fprintf(stdout, "\nAverage end to end distance: %.3f (nm)\n",
482 sqrt(sum_eed2_tot));
483 fprintf(stdout, "\nAverage radius of gyration: %.3f (nm)\n",
484 sqrt(sum_gyro_tot));
485 if (opt2bSet("-p", NFILE, fnm))
487 fprintf(stdout, "\nAverage persistence length: %.2f bonds\n",
488 sum_pers_tot);
491 /* Handle printing of internal distances. */
492 if (outi)
494 if (output_env_get_print_xvgr_codes(oenv))
496 fprintf(outi, "@ xaxes scale Logarithmic\n");
498 ymax = -1;
499 ymin = 1e300;
500 j = index[molind[1]-1] - index[molind[0]]; /* Polymer length -1. */
501 for (i = 0; i < j; i++)
503 intd[i] /= (i + 1) * frame * nmol;
504 if (intd[i] > ymax)
506 ymax = intd[i];
508 if (intd[i] < ymin)
510 ymin = intd[i];
513 xvgr_world(outi, 1, ymin, j, ymax, oenv);
514 for (i = 0; i < j; i++)
516 fprintf(outi, "%d %8.4f\n", i+1, intd[i]);
518 xvgrclose(outi);
521 do_view(oenv, opt2fn("-o", NFILE, fnm), "-nxy");
522 if (opt2bSet("-v", NFILE, fnm))
524 do_view(oenv, opt2fn("-v", NFILE, fnm), "-nxy");
526 if (opt2bSet("-p", NFILE, fnm))
528 do_view(oenv, opt2fn("-p", NFILE, fnm), "-nxy");
531 return 0;