3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
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.
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.
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.
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.
30 * For more info, check our website at http://www.gromacs.org
33 * Green Red Orange Magenta Azure Cyan Skyblue
51 #include "gromacs/fileio/confio.h"
52 #include "gromacs/fileio/trxio.h"
54 void print_one(const output_env_t oenv, const char *base, const char *name,
55 const char *title, const char *ylabel, int nf, real time[],
59 char buf[256], t2[256];
62 sprintf(buf, "%s%s.xvg", base, name);
63 fprintf(stderr, "\rPrinting %s ", buf);
64 sprintf(t2, "%s %s", title, name);
65 fp = xvgropen(buf, t2, "Time (ps)", ylabel, oenv);
66 for (k = 0; (k < nf); k++)
68 fprintf(fp, "%10g %10g\n", time[k], data[k]);
73 static int calc_RBbin(real phi, int gmx_unused multiplicity, real gmx_unused core_frac)
75 /* multiplicity and core_frac NOT used,
76 * just given to enable use of pt-to-fn in caller low_ana_dih_trans*/
77 static const real r30 = M_PI/6.0;
78 static const real r90 = M_PI/2.0;
79 static const real r150 = M_PI*5.0/6.0;
81 if ((phi < r30) && (phi > -r30))
85 else if ((phi > -r150) && (phi < -r90))
89 else if ((phi < r150) && (phi > r90))
96 static int calc_Nbin(real phi, int multiplicity, real core_frac)
98 static const real r360 = 360*DEG2RAD;
99 real rot_width, core_width, core_offset, low, hi;
101 /* with multiplicity 3 and core_frac 0.5
102 * 0<g(-)<120, 120<t<240, 240<g(+)<360
103 * 0< bin0 < 30, 30<bin1<90, 90<bin0<150, 150<bin2<210, 210<bin0<270, 270<bin3<330, 330<bin0<360
104 * so with multiplicity 3, bin1 is core g(-), bin2 is core t, bin3 is
105 core g(+), bin0 is between rotamers */
111 rot_width = 360/multiplicity;
112 core_width = core_frac * rot_width;
113 core_offset = (rot_width - core_width)/2.0;
114 for (bin = 1; bin <= multiplicity; bin++)
116 low = ((bin - 1) * rot_width ) + core_offset;
117 hi = ((bin - 1) * rot_width ) + core_offset + core_width;
120 if ((phi > low) && (phi < hi))
128 void ana_dih_trans(const char *fn_trans, const char *fn_histo,
129 real **dih, int nframes, int nangles,
130 const char *grpname, real *time, gmx_bool bRb,
131 const output_env_t oenv)
133 /* just a wrapper; declare extra args, then chuck away at end. */
141 snew(multiplicity, nangles);
142 for (k = 0; (k < nangles); k++)
147 low_ana_dih_trans(TRUE, fn_trans, TRUE, fn_histo, maxchi,
148 dih, nlist, dlist, nframes,
149 nangles, grpname, multiplicity, time, bRb, 0.5, oenv);
155 void low_ana_dih_trans(gmx_bool bTrans, const char *fn_trans,
156 gmx_bool bHisto, const char *fn_histo, int maxchi,
157 real **dih, int nlist, t_dlist dlist[], int nframes,
158 int nangles, const char *grpname, int multiplicity[],
159 real *time, gmx_bool bRb, real core_frac,
160 const output_env_t oenv)
165 int i, j, k, Dih, ntrans;
166 int cur_bin, new_bin;
169 int (*calc_bin)(real, int, real);
176 /* Assumes the frames are equally spaced in time */
177 dt = (time[nframes-1]-time[0])/(nframes-1);
179 /* Analysis of dihedral transitions */
180 fprintf(stderr, "Now calculating transitions...\n");
184 calc_bin = calc_RBbin;
188 calc_bin = calc_Nbin;
191 for (k = 0; k < NROT; k++)
193 snew(rot_occ[k], nangles);
194 for (i = 0; (i < nangles); i++)
202 /* dih[i][j] is the dihedral angle i in frame j */
204 for (i = 0; (i < nangles); i++)
209 mind = maxd = prev = dih[i][0];
211 cur_bin = calc_bin(dih[i][0], multiplicity[i], core_frac);
212 rot_occ[cur_bin][i]++;
214 for (j = 1; (j < nframes); j++)
216 new_bin = calc_bin(dih[i][j], multiplicity[i], core_frac);
217 rot_occ[new_bin][i]++;
223 else if ((new_bin != 0) && (cur_bin != new_bin))
231 /* why is all this md rubbish periodic? Remove 360 degree periodicity */
232 if ( (dih[i][j] - prev) > M_PI)
236 else if ( (dih[i][j] - prev) < -M_PI)
243 mind = min(mind, dih[i][j]);
244 maxd = max(maxd, dih[i][j]);
245 if ( (maxd - mind) > 2*M_PI/3) /* or 120 degrees, assuming */
246 { /* multiplicity 3. Not so general.*/
249 maxd = mind = dih[i][j]; /* get ready for next transition */
254 for (k = 0; k < NROT; k++)
256 rot_occ[k][i] /= nframes;
259 fprintf(stderr, "Total number of transitions: %10d\n", ntrans);
262 ttime = (dt*nframes*nangles)/ntrans;
263 fprintf(stderr, "Time between transitions: %10.3f ps\n", ttime);
266 /* new by grs - copy transitions from tr_h[] to dlist->ntr[]
267 * and rotamer populations from rot_occ to dlist->rot_occ[]
268 * based on fn histogramming in g_chi. diff roles for i and j here */
271 for (Dih = 0; (Dih < NONCHI+maxchi); Dih++)
273 for (i = 0; (i < nlist); i++)
275 if (((Dih < edOmega) ) ||
276 ((Dih == edOmega) && (has_dihedral(edOmega, &(dlist[i])))) ||
277 ((Dih > edOmega) && (dlist[i].atm.Cn[Dih-NONCHI+3] != -1)))
279 /* grs debug printf("Not OK? i %d j %d Dih %d \n", i, j, Dih) ; */
280 dlist[i].ntr[Dih] = tr_h[j];
281 for (k = 0; k < NROT; k++)
283 dlist[i].rot_occ[Dih][k] = rot_occ[k][j];
290 /* end addition by grs */
294 sprintf(title, "Number of transitions: %s", grpname);
295 fp = xvgropen(fn_trans, title, "Time (ps)", "# transitions/timeframe", oenv);
296 for (j = 0; (j < nframes); j++)
298 fprintf(fp, "%10.3f %10d\n", time[j], tr_f[j]);
303 /* Compute histogram from # transitions per dihedral */
305 for (j = 0; (j < nframes); j++)
309 for (i = 0; (i < nangles); i++)
313 for (j = nframes; ((tr_f[j-1] == 0) && (j > 0)); j--)
321 sprintf(title, "Transition time: %s", grpname);
322 fp = xvgropen(fn_histo, title, "Time (ps)", "#", oenv);
323 for (i = j-1; (i > 0); i--)
327 fprintf(fp, "%10.3f %10d\n", ttime/i, tr_f[i]);
335 for (k = 0; k < NROT; k++)
342 void mk_multiplicity_lookup (int *multiplicity, int maxchi,
343 int nlist, t_dlist dlist[], int nangles)
345 /* new by grs - for dihedral j (as in dih[j]) get multiplicity from dlist
346 * and store in multiplicity[j]
353 for (Dih = 0; (Dih < NONCHI+maxchi); Dih++)
355 for (i = 0; (i < nlist); i++)
357 strncpy(name, dlist[i].name, 3);
359 if (((Dih < edOmega) ) ||
360 ((Dih == edOmega) && (has_dihedral(edOmega, &(dlist[i])))) ||
361 ((Dih > edOmega) && (dlist[i].atm.Cn[Dih-NONCHI+3] != -1)))
363 /* default - we will correct the rest below */
366 /* make omegas 2fold, though doesn't make much more sense than 3 */
367 if (Dih == edOmega && (has_dihedral(edOmega, &(dlist[i]))))
372 /* dihedrals to aromatic rings, COO, CONH2 or guanidinium are 2fold*/
373 if (Dih > edOmega && (dlist[i].atm.Cn[Dih-NONCHI+3] != -1))
375 if ( ((strstr(name, "PHE") != NULL) && (Dih == edChi2)) ||
376 ((strstr(name, "TYR") != NULL) && (Dih == edChi2)) ||
377 ((strstr(name, "PTR") != NULL) && (Dih == edChi2)) ||
378 ((strstr(name, "TRP") != NULL) && (Dih == edChi2)) ||
379 ((strstr(name, "HIS") != NULL) && (Dih == edChi2)) ||
380 ((strstr(name, "GLU") != NULL) && (Dih == edChi3)) ||
381 ((strstr(name, "ASP") != NULL) && (Dih == edChi2)) ||
382 ((strstr(name, "GLN") != NULL) && (Dih == edChi3)) ||
383 ((strstr(name, "ASN") != NULL) && (Dih == edChi2)) ||
384 ((strstr(name, "ARG") != NULL) && (Dih == edChi4)) )
395 fprintf(stderr, "WARNING: not all dihedrals found in topology (only %d out of %d)!\n",
398 /* Check for remaining dihedrals */
399 for (; (j < nangles); j++)
406 void mk_chi_lookup (int **lookup, int maxchi,
407 int nlist, t_dlist dlist[])
410 /* by grs. should rewrite everything to use this. (but haven't,
411 * and at mmt only used in get_chi_product_traj
412 * returns the dihed number given the residue number (from-0)
413 * and chi (from-0) nr. -1 for chi undefined for that res (eg gly, ala..)*/
418 for (Dih = 0; (Dih < NONCHI+maxchi); Dih++)
420 for (i = 0; (i < nlist); i++)
423 if (((Dih < edOmega) ) ||
424 ((Dih == edOmega) && (has_dihedral(edOmega, &(dlist[i])))) ||
425 ((Dih > edOmega) && (dlist[i].atm.Cn[Dih-NONCHI+3] != -1)))
427 /* grs debug printf("Not OK? i %d j %d Dih %d \n", i, j, Dih) ; */
444 void get_chi_product_traj (real **dih, int nframes, int nlist,
445 int maxchi, t_dlist dlist[], real time[],
446 int **lookup, int *multiplicity, gmx_bool bRb, gmx_bool bNormalize,
447 real core_frac, gmx_bool bAll, const char *fnall,
448 const output_env_t oenv)
451 gmx_bool bRotZero, bHaveChi = FALSE;
452 int accum = 0, index, i, j, k, Xi, n, b;
457 char hisfile[256], histitle[256], *namept;
459 int (*calc_bin)(real, int, real);
461 /* Analysis of dihedral transitions */
462 fprintf(stderr, "Now calculating Chi product trajectories...\n");
466 calc_bin = calc_RBbin;
470 calc_bin = calc_Nbin;
473 snew(chi_prtrj, nframes);
475 /* file for info on all residues */
478 fpall = xvgropen(fnall, "Cumulative Rotamers", "Residue", "Probability", oenv);
482 fpall = xvgropen(fnall, "Cumulative Rotamers", "Residue", "# Counts", oenv);
485 for (i = 0; (i < nlist); i++)
488 /* get nbin, the nr. of cumulative rotamers that need to be considered */
490 for (Xi = 0; Xi < maxchi; Xi++)
492 index = lookup[i][Xi]; /* chi_(Xi+1) of res i (-1 if off end) */
495 n = multiplicity[index];
499 nbin += 1; /* for the "zero rotamer", outside the core region */
501 for (j = 0; (j < nframes); j++)
506 index = lookup[i][0]; /* index into dih of chi1 of res i */
515 b = calc_bin(dih[index][j], multiplicity[index], core_frac);
521 for (Xi = 1; Xi < maxchi; Xi++)
523 index = lookup[i][Xi]; /* chi_(Xi+1) of res i (-1 if off end) */
526 n = multiplicity[index];
527 b = calc_bin(dih[index][j], n, core_frac);
528 accum = n * accum + b - 1;
543 chi_prtrj[j] = accum;
555 /* print cuml rotamer vs time */
556 print_one(oenv, "chiproduct", dlist[i].name, "chi product for",
557 "cumulative rotamer", nframes, time, chi_prtrj);
560 /* make a histogram pf culm. rotamer occupancy too */
561 snew(chi_prhist, nbin);
562 make_histo(NULL, nframes, chi_prtrj, nbin, chi_prhist, 0, nbin);
565 sprintf(hisfile, "histo-chiprod%s.xvg", dlist[i].name);
566 sprintf(histitle, "cumulative rotamer distribution for %s", dlist[i].name);
567 fprintf(stderr, " and %s ", hisfile);
568 fp = xvgropen(hisfile, histitle, "number", "", oenv);
569 fprintf(fp, "@ xaxis tick on\n");
570 fprintf(fp, "@ xaxis tick major 1\n");
571 fprintf(fp, "@ type xy\n");
572 for (k = 0; (k < nbin); k++)
576 fprintf(fp, "%5d %10g\n", k, (1.0*chi_prhist[k])/nframes);
580 fprintf(fp, "%5d %10d\n", k, chi_prhist[k]);
587 /* and finally print out occupancies to a single file */
588 /* get the gmx from-1 res nr by setting a ptr to the number part
589 * of dlist[i].name - potential bug for 4-letter res names... */
590 namept = dlist[i].name + 3;
591 fprintf(fpall, "%5s ", namept);
592 for (k = 0; (k < nbin); k++)
596 fprintf(fpall, " %10g", (1.0*chi_prhist[k])/nframes);
600 fprintf(fpall, " %10d", chi_prhist[k]);
603 fprintf(fpall, "\n");
612 fprintf(stderr, "\n");
616 void calc_distribution_props(int nh, int histo[], real start,
617 int nkkk, t_karplus kkk[],
620 real d, dc, ds, c1, c2, tdc, tds;
621 real fac, ang, invth, Jc;
626 gmx_fatal(FARGS, "No points in histogram (%s, %d)", __FILE__, __LINE__);
630 /* Compute normalisation factor */
632 for (j = 0; (j < nh); j++)
638 for (i = 0; (i < nkkk); i++)
644 for (j = 0; (j < nh); j++)
654 for (i = 0; (i < nkkk); i++)
656 c1 = cos(ang+kkk[i].offset);
658 Jc = (kkk[i].A*c2 + kkk[i].B*c1 + kkk[i].C);
659 kkk[i].Jc += histo[j]*Jc;
660 kkk[i].Jcsig += histo[j]*sqr(Jc);
663 for (i = 0; (i < nkkk); i++)
666 kkk[i].Jcsig = sqrt(kkk[i].Jcsig/th-sqr(kkk[i].Jc));
668 *S2 = tdc*tdc+tds*tds;
671 static void calc_angles(t_pbc *pbc,
672 int n3, atom_id index[], real ang[], rvec x_s[])
678 for (i = ix = 0; (ix < n3); i++, ix += 3)
680 ang[i] = bond_angle(x_s[index[ix]], x_s[index[ix+1]], x_s[index[ix+2]],
681 pbc, r_ij, r_kj, &costh, &t1, &t2);
685 fprintf(debug, "Angle[0]=%g, costh=%g, index0 = %d, %d, %d\n",
686 ang[0], costh, index[0], index[1], index[2]);
687 pr_rvec(debug, 0, "rij", r_ij, DIM, TRUE);
688 pr_rvec(debug, 0, "rkj", r_kj, DIM, TRUE);
692 static real calc_fraction(real angles[], int nangles)
695 real trans = 0, gauche = 0;
698 for (i = 0; i < nangles; i++)
700 angle = angles[i] * RAD2DEG;
702 if (angle > 135 && angle < 225)
706 else if (angle > 270 && angle < 330)
710 else if (angle < 90 && angle > 30)
715 if (trans+gauche > 0)
717 return trans/(trans+gauche);
725 static void calc_dihs(t_pbc *pbc,
726 int n4, atom_id index[], real ang[], rvec x_s[])
728 int i, ix, t1, t2, t3;
729 rvec r_ij, r_kj, r_kl, m, n;
732 for (i = ix = 0; (ix < n4); i++, ix += 4)
734 aaa = dih_angle(x_s[index[ix]], x_s[index[ix+1]], x_s[index[ix+2]],
735 x_s[index[ix+3]], pbc,
736 r_ij, r_kj, r_kl, m, n,
737 &sign, &t1, &t2, &t3);
739 ang[i] = aaa; /* not taking into account ryckaert bellemans yet */
743 void make_histo(FILE *log,
744 int ndata, real data[], int npoints, int histo[],
745 real minx, real maxx)
752 minx = maxx = data[0];
753 for (i = 1; (i < ndata); i++)
755 minx = min(minx, data[i]);
756 maxx = max(maxx, data[i]);
758 fprintf(log, "Min data: %10g Max data: %10g\n", minx, maxx);
760 dx = (double)npoints/(maxx-minx);
764 "Histogramming: ndata=%d, nhisto=%d, minx=%g,maxx=%g,dx=%g\n",
765 ndata, npoints, minx, maxx, dx);
767 for (i = 0; (i < ndata); i++)
769 ind = (data[i]-minx)*dx;
770 if ((ind >= 0) && (ind < npoints))
776 fprintf(log, "index = %d, data[%d] = %g\n", ind, i, data[i]);
781 void normalize_histo(int npoints, int histo[], real dx, real normhisto[])
787 for (i = 0; (i < npoints); i++)
793 fprintf(stderr, "Empty histogram!\n");
797 for (i = 0; (i < npoints); i++)
799 normhisto[i] = fac*histo[i];
803 void read_ang_dih(const char *trj_fn,
804 gmx_bool bAngles, gmx_bool bSaveAll, gmx_bool bRb, gmx_bool bPBC,
805 int maxangstat, int angstat[],
806 int *nframes, real **time,
807 int isize, atom_id index[],
811 const output_env_t oenv)
815 int i, angind, natoms, total, teller;
816 int nangles, n_alloc;
817 real t, fraction, pifac, aa, angle;
825 natoms = read_first_x(oenv, &status, trj_fn, &t, &x, box);
837 snew(angles[cur], nangles);
838 snew(angles[prev], nangles);
840 /* Start the loop over frames */
850 if (teller >= n_alloc)
855 for (i = 0; (i < nangles); i++)
857 srenew(dih[i], n_alloc);
860 srenew(*time, n_alloc);
861 srenew(*trans_frac, n_alloc);
862 srenew(*aver_angle, n_alloc);
869 set_pbc(pbc, -1, box);
874 calc_angles(pbc, isize, index, angles[cur], x);
878 calc_dihs(pbc, isize, index, angles[cur], x);
881 fraction = calc_fraction(angles[cur], nangles);
882 (*trans_frac)[teller] = fraction;
884 /* Change Ryckaert-Bellemans dihedrals to polymer convention
885 * Modified 990913 by Erik:
886 * We actually shouldn't change the convention, since it's
887 * calculated from polymer above, but we change the intervall
888 * from [-180,180] to [0,360].
892 for (i = 0; (i < nangles); i++)
894 if (angles[cur][i] <= 0.0)
896 angles[cur][i] += 2*M_PI;
901 /* Periodicity in dihedral space... */
904 for (i = 0; (i < nangles); i++)
906 real dd = angles[cur][i];
907 angles[cur][i] = atan2(sin(dd), cos(dd));
914 for (i = 0; (i < nangles); i++)
916 while (angles[cur][i] <= angles[prev][i] - M_PI)
918 angles[cur][i] += 2*M_PI;
920 while (angles[cur][i] > angles[prev][i] + M_PI)
922 angles[cur][i] -= 2*M_PI;
931 for (i = 0; (i < nangles); i++)
933 aa = aa+angles[cur][i];
935 /* angle in rad / 2Pi * max determines bin. bins go from 0 to maxangstat,
936 even though scale goes from -pi to pi (dihedral) or -pi/2 to pi/2
937 (angle) Basically: translate the x-axis by Pi. Translate it back by
941 angle = angles[cur][i];
944 while (angle < -M_PI)
948 while (angle >= M_PI)
956 /* Update the distribution histogram */
957 angind = (int) ((angle*maxangstat)/pifac + 0.5);
958 if (angind == maxangstat)
962 if ( (angind < 0) || (angind >= maxangstat) )
964 /* this will never happen */
965 gmx_fatal(FARGS, "angle (%f) index out of range (0..%d) : %d\n",
966 angle, maxangstat, angind);
970 if (angind == maxangstat)
972 fprintf(stderr, "angle %d fr %d = %g\n", i, cur, angle);
978 /* average over all angles */
979 (*aver_angle)[teller] = (aa/nangles);
981 /* this copies all current dih. angles to dih[i], teller is frame */
984 for (i = 0; i < nangles; i++)
986 dih[i][teller] = angles[cur][i];
993 /* Increment loop counter */
996 while (read_next_x(oenv, status, &t, x, box));
1001 sfree(angles[prev]);