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 * check out http://www.gromacs.org for more information.
7 * Copyright (c) 2012, by the GROMACS development team, led by
8 * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9 * others, as listed in the AUTHORS file in the top-level source
10 * directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
54 #include "gmx_fatal.h"
62 static void gyro_eigen(double **gyr,double *eig,double **eigv,int *ord)
66 jacobi(gyr,DIM,eig,eigv,&nrot);
67 /* Order the eigenvalues */
70 for(d=0; d<DIM; d++) {
71 if (eig[d] > eig[ord[0]])
73 if (eig[d] < eig[ord[2]])
76 for(d=0; d<DIM; d++) {
77 if (ord[0] != d && ord[2] != d)
82 /* Calculate mean square internal distances (Auhl et al., JCP 119, 12718) */
83 static void calc_int_dist(double *intd, rvec *x, int i0, int i1)
86 const int ml = i1 - i0 + 1; /* Number of beads in molecule. */
87 int bd; /* Distance between beads */
90 for (bd = 1; bd < ml; bd++) {
92 for (ii = i0; ii <= i1 - bd; ii++)
93 d += distance2(x[ii], x[ii+bd]);
99 int gmx_polystat(int argc,char *argv[])
101 const char *desc[] = {
102 "[TT]g_polystat[tt] plots static properties of polymers as a function of time",
103 "and prints the average.[PAR]",
104 "By default it determines the average end-to-end distance and radii",
105 "of gyration of polymers. It asks for an index group and split this",
106 "into molecules. The end-to-end distance is then determined using",
107 "the first and the last atom in the index group for each molecules.",
108 "For the radius of gyration the total and the three principal components",
109 "for the average gyration tensor are written.",
110 "With option [TT]-v[tt] the eigenvectors are written.",
111 "With option [TT]-pc[tt] also the average eigenvalues of the individual",
112 "gyration tensors are written.",
113 "With option [TT]-i[tt] the mean square internal distances are",
115 "With option [TT]-p[tt] the persistence length is determined.",
116 "The chosen index group should consist of atoms that are",
117 "consecutively bonded in the polymer mainchains.",
118 "The persistence length is then determined from the cosine of",
119 "the angles between bonds with an index difference that is even,",
120 "the odd pairs are not used, because straight polymer backbones",
121 "are usually all trans and therefore only every second bond aligns.",
122 "The persistence length is defined as number of bonds where",
123 "the average cos reaches a value of 1/e. This point is determined",
124 "by a linear interpolation of log(<cos>)."
126 static gmx_bool bMW = TRUE, bPC = FALSE;
128 { "-mw", FALSE, etBOOL, {&bMW},
129 "Use the mass weighting for radii of gyration" },
130 { "-pc", FALSE, etBOOL, {&bPC},
131 "Plot average eigenvalues" }
135 { efTPX, NULL, NULL, ffREAD },
136 { efTRX, "-f", NULL, ffREAD },
137 { efNDX, NULL, NULL, ffOPTRD },
138 { efXVG, "-o", "polystat", ffWRITE },
139 { efXVG, "-v", "polyvec", ffOPTWR },
140 { efXVG, "-p", "persist", ffOPTWR },
141 { efXVG, "-i", "intdist", ffOPTWR }
143 #define NFILE asize(fnm)
148 int isize,*index,nmol,*molind,mol,nat_min=0,nat_max=0;
154 int natoms,i,j,frame,ind0,ind1,a,d,d2,ord[DIM]={0};
155 dvec cm,sum_eig={0,0,0};
156 double **gyr,**gyr_all,eig[DIM],**eigv;
157 double sum_eed2,sum_eed2_tot,sum_gyro,sum_gyro_tot,sum_pers_tot;
159 double *sum_inp=NULL,pers;
160 double *intd, ymax, ymin;
163 FILE *out,*outv,*outp, *outi;
164 const char *leg[8] = { "end to end", "<R\\sg\\N>",
165 "<R\\sg\\N> eig1", "<R\\sg\\N> eig2", "<R\\sg\\N> eig3",
166 "<R\\sg\\N eig1>", "<R\\sg\\N eig2>", "<R\\sg\\N eig3>" };
167 char **legp,buf[STRLEN];
168 gmx_rmpbc_t gpbc=NULL;
170 CopyRight(stderr,argv[0]);
171 parse_common_args(&argc,argv,
172 PCA_CAN_VIEW | PCA_CAN_TIME | PCA_TIME_UNIT | PCA_BE_NICE,
173 NFILE,fnm,asize(pa),pa,asize(desc),desc,0,NULL,&oenv);
176 ePBC = read_tpx_top(ftp2fn(efTPX,NFILE,fnm),
177 NULL,box,&natoms,NULL,NULL,NULL,top);
179 fprintf(stderr,"Select a group of polymer mainchain atoms:\n");
180 get_index(&top->atoms,ftp2fn_null(efNDX,NFILE,fnm),
181 1,&isize,&index,&grpname);
183 snew(molind,top->mols.nr+1);
186 for(i=0; i<isize; i++) {
187 if (i == 0 || index[i] >= top->mols.index[mol+1]) {
191 } while (index[i] >= top->mols.index[mol+1]);
195 nat_min = top->atoms.nr;
197 for(mol=0; mol<nmol; mol++) {
198 nat_min = min(nat_min,molind[mol+1]-molind[mol]);
199 nat_max = max(nat_max,molind[mol+1]-molind[mol]);
201 fprintf(stderr,"Group %s consists of %d molecules\n",grpname,nmol);
202 fprintf(stderr,"Group size per molecule, min: %d atoms, max %d atoms\n",
205 sprintf(title,"Size of %d polymers",nmol);
206 out = xvgropen(opt2fn("-o",NFILE,fnm),title,output_env_get_xvgr_tlabel(oenv),"(nm)",
208 xvgr_legend(out,bPC ? 8 : 5,leg,oenv);
210 if (opt2bSet("-v",NFILE,fnm)) {
211 outv = xvgropen(opt2fn("-v",NFILE,fnm),"Principal components",
212 output_env_get_xvgr_tlabel(oenv),"(nm)",oenv);
214 for(d=0; d<DIM; d++) {
215 for(d2=0; d2<DIM; d2++) {
216 sprintf(buf,"eig%d %c",d+1,'x'+d2);
217 legp[d*DIM+d2] = strdup(buf);
220 xvgr_legend(outv,DIM*DIM,(const char**)legp,oenv);
225 if (opt2bSet("-p",NFILE,fnm)) {
226 outp = xvgropen(opt2fn("-p",NFILE,fnm),"Persistence length",
227 output_env_get_xvgr_tlabel(oenv),"bonds",oenv);
228 snew(bond,nat_max-1);
229 snew(sum_inp,nat_min/2);
230 snew(ninp,nat_min/2);
235 if (opt2bSet("-i", NFILE, fnm)) {
236 outi = xvgropen(opt2fn("-i", NFILE, fnm), "Internal distances",
237 "n", "<R\\S2\\N(n)>/n (nm\\S2\\N)",oenv);
238 i = index[molind[1]-1] - index[molind[0]]; /* Length of polymer -1 */
245 natoms = read_first_x(oenv,&status,ftp2fn(efTRX,NFILE,fnm),&t,&x,box);
250 for(d=0; d<DIM; d++) {
252 snew(gyr_all[d],DIM);
261 gpbc = gmx_rmpbc_init(&top->idef,ePBC,natoms,box);
264 gmx_rmpbc(gpbc,natoms,box,x);
268 clear_dvec(gyr_all[d]);
274 for(i=0; i<nat_min/2; i++) {
280 for(mol=0; mol<nmol; mol++) {
282 ind1 = molind[mol+1];
284 /* Determine end to end distance */
285 sum_eed2 += distance2(x[index[ind0]],x[index[ind1-1]]);
287 /* Determine internal distances */
289 calc_int_dist(intd, x, index[ind0], index[ind1-1]);
292 /* Determine the radius of gyration */
298 for(i=ind0; i<ind1; i++) {
301 m = top->atoms.atom[a].m;
305 for(d=0; d<DIM; d++) {
307 for(d2=0; d2<DIM; d2++)
308 gyr[d][d2] += m*x[a][d]*x[a][d2];
311 dsvmul(1/mmol,cm,cm);
312 for(d=0; d<DIM; d++) {
313 for(d2=0; d2<DIM; d2++) {
314 gyr[d][d2] = gyr[d][d2]/mmol - cm[d]*cm[d2];
315 gyr_all[d][d2] += gyr[d][d2];
319 gyro_eigen(gyr,eig,eigv,ord);
321 sum_eig[d] += eig[ord[d]];
324 for(i=ind0; i<ind1-1; i++) {
325 rvec_sub(x[index[i+1]],x[index[i]],bond[i-ind0]);
326 unitv(bond[i-ind0],bond[i-ind0]);
328 for(i=ind0; i<ind1-1; i++) {
329 for(j=0; (i+j<ind1-1 && j<nat_min/2); j+=2) {
330 sum_inp[j] += iprod(bond[i-ind0],bond[i-ind0+j]);
339 for(d=0; d<DIM; d++) {
340 for(d2=0; d2<DIM; d2++)
341 gyr_all[d][d2] /= nmol;
342 sum_gyro += gyr_all[d][d];
345 gyro_eigen(gyr_all,eig,eigv,ord);
347 fprintf(out,"%10.3f %8.4f %8.4f %8.4f %8.4f %8.4f",
348 t*output_env_get_time_factor(oenv),
349 sqrt(sum_eed2),sqrt(sum_gyro),
350 sqrt(eig[ord[0]]),sqrt(eig[ord[1]]),sqrt(eig[ord[2]]));
353 fprintf(out," %8.4f",sqrt(sum_eig[d]/nmol));
358 fprintf(outv,"%10.3f",t*output_env_get_time_factor(oenv));
359 for(d=0; d<DIM; d++) {
360 for(d2=0; d2<DIM; d2++)
361 fprintf(outv," %6.3f",eigv[ord[d]][d2]);
366 sum_eed2_tot += sum_eed2;
367 sum_gyro_tot += sum_gyro;
371 for(j=0; j<nat_min/2; j+=2) {
372 sum_inp[j] /= ninp[j];
373 if (i == -1 && sum_inp[j] <= exp(-1.0))
379 /* Do linear interpolation on a log scale */
381 + 2*(log(sum_inp[i-2]) + 1)/(log(sum_inp[i-2]) - log(sum_inp[i]));
383 fprintf(outp,"%10.3f %8.4f\n",t*output_env_get_time_factor(oenv),pers);
384 sum_pers_tot += pers;
388 } while (read_next_x(oenv,status,&t,natoms,x,box));
390 gmx_rmpbc_done(gpbc);
400 sum_eed2_tot /= frame;
401 sum_gyro_tot /= frame;
402 sum_pers_tot /= frame;
403 fprintf(stdout,"\nAverage end to end distance: %.3f (nm)\n",
405 fprintf(stdout,"\nAverage radius of gyration: %.3f (nm)\n",
407 if (opt2bSet("-p",NFILE,fnm))
408 fprintf(stdout,"\nAverage persistence length: %.2f bonds\n",
411 /* Handle printing of internal distances. */
413 fprintf(outi, "@ xaxes scale Logarithmic\n");
416 j = index[molind[1]-1] - index[molind[0]]; /* Polymer length -1. */
417 for (i = 0; i < j; i++) {
418 intd[i] /= (i + 1) * frame * nmol;
424 xvgr_world(outi, 1, ymin, j, ymax,oenv);
425 for (i = 0; i < j; i++) {
426 fprintf(outi, "%d %8.4f\n", i+1, intd[i]);
431 do_view(oenv,opt2fn("-o",NFILE,fnm),"-nxy");
432 if (opt2bSet("-v",NFILE,fnm))
433 do_view(oenv,opt2fn("-v",NFILE,fnm),"-nxy");
434 if (opt2bSet("-p",NFILE,fnm))
435 do_view(oenv,opt2fn("-p",NFILE,fnm),"-nxy");