Split lines with many copyright years
[gromacs.git] / src / gromacs / gmxana / gmx_chi.cpp
blob03e50be5d9621d8105310346410b9672cc67dd77
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,2016,2017 by the GROMACS development team.
7 * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
8 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
9 * and including many others, as listed in the AUTHORS file in the
10 * top-level source 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.
38 #include "gmxpre.h"
40 #include <cmath>
41 #include <cstdio>
42 #include <cstring>
44 #include <algorithm>
46 #include "gromacs/commandline/pargs.h"
47 #include "gromacs/commandline/viewit.h"
48 #include "gromacs/correlationfunctions/autocorr.h"
49 #include "gromacs/fileio/confio.h"
50 #include "gromacs/fileio/matio.h"
51 #include "gromacs/fileio/pdbio.h"
52 #include "gromacs/fileio/xvgr.h"
53 #include "gromacs/gmxana/gmx_ana.h"
54 #include "gromacs/gmxana/gstat.h"
55 #include "gromacs/math/units.h"
56 #include "gromacs/math/utilities.h"
57 #include "gromacs/math/vec.h"
58 #include "gromacs/topology/residuetypes.h"
59 #include "gromacs/topology/topology.h"
60 #include "gromacs/utility/arraysize.h"
61 #include "gromacs/utility/cstringutil.h"
62 #include "gromacs/utility/fatalerror.h"
63 #include "gromacs/utility/futil.h"
64 #include "gromacs/utility/smalloc.h"
65 #include "gromacs/utility/stringutil.h"
67 static gmx_bool bAllowed(real phi, real psi)
69 static const char* map[] = { "1100000000000000001111111000000000001111111111111111111111111",
70 "1100000000000000001111110000000000011111111111111111111111111",
71 "1100000000000000001111110000000000011111111111111111111111111",
72 "1100000000000000001111100000000000111111111111111111111111111",
73 "1100000000000000001111100000000000111111111111111111111111111",
74 "1100000000000000001111100000000001111111111111111111111111111",
75 "1100000000000000001111100000000001111111111111111111111111111",
76 "1100000000000000001111100000000011111111111111111111111111111",
77 "1110000000000000001111110000000111111111111111111111111111111",
78 "1110000000000000001111110000001111111111111111111111111111111",
79 "1110000000000000001111111000011111111111111111111111111111111",
80 "1110000000000000001111111100111111111111111111111111111111111",
81 "1110000000000000001111111111111111111111111111111111111111111",
82 "1110000000000000001111111111111111111111111111111111111111111",
83 "1110000000000000001111111111111111111111111111111111111111111",
84 "1110000000000000001111111111111111111111111111111111111111111",
85 "1110000000000000001111111111111110011111111111111111111111111",
86 "1110000000000000001111111111111100000111111111111111111111111",
87 "1110000000000000001111111111111000000000001111111111111111111",
88 "1100000000000000001111111111110000000000000011111111111111111",
89 "1100000000000000001111111111100000000000000011111111111111111",
90 "1000000000000000001111111111000000000000000001111111111111110",
91 "0000000000000000001111111110000000000000000000111111111111100",
92 "0000000000000000000000000000000000000000000000000000000000000",
93 "0000000000000000000000000000000000000000000000000000000000000",
94 "0000000000000000000000000000000000000000000000000000000000000",
95 "0000000000000000000000000000000000000000000000000000000000000",
96 "0000000000000000000000000000000000000000000000000000000000000",
97 "0000000000000000000000000000000000000000000000000000000000000",
98 "0000000000000000000000000000000000000000000000000000000000000",
99 "0000000000000000000000000000000000000000000000000000000000000",
100 "0000000000000000000000000000000000000000000000000000000000000",
101 "0000000000000000000000000000000000000000000000000000000000000",
102 "0000000000000000000000000000000000000000000000000000000000000",
103 "0000000000000000000000000000000000000000000000000000000000000",
104 "0000000000000000000000000000000000000000000000000000000000000",
105 "0000000000000000000000000000000000000000000000000000000000000",
106 "0000000000000000000000000000000000000000000000000000000000000",
107 "0000000000000000000000000000000000111111111111000000000000000",
108 "1100000000000000000000000000000001111111111111100000000000111",
109 "1100000000000000000000000000000001111111111111110000000000111",
110 "0000000000000000000000000000000000000000000000000000000000000",
111 "0000000000000000000000000000000000000000000000000000000000000",
112 "0000000000000000000000000000000000000000000000000000000000000",
113 "0000000000000000000000000000000000000000000000000000000000000",
114 "0000000000000000000000000000000000000000000000000000000000000",
115 "0000000000000000000000000000000000000000000000000000000000000",
116 "0000000000000000000000000000000000000000000000000000000000000",
117 "0000000000000000000000000000000000000000000000000000000000000",
118 "0000000000000000000000000000000000000000000000000000000000000",
119 "0000000000000000000000000000000000000000000000000000000000000",
120 "0000000000000000000000000000000000000000000000000000000000000",
121 "0000000000000000000000000000000000000000000000000000000000000",
122 "0000000000000000000000000000000000000000000000000000000000000",
123 "0000000000000000000000000000000000000000000000000000000000000",
124 "0000000000000000000000000000000000000000000000000000000000000",
125 "0000000000000000000000000000000000000000000000000000000000000",
126 "0000000000000000000000000000000000000000000000000000000000000",
127 "0000000000000000000000000000000000000000000000000000000000000",
128 "0000000000000000000000000000000000000000000000000000000000000",
129 "0000000000000000000000000000000000000000000000000000000000000" };
130 #define NPP asize(map)
131 int x, y;
133 #define INDEX(ppp) (((static_cast<int>(360 + (ppp)*RAD2DEG)) % 360) / 6)
134 x = INDEX(phi);
135 y = INDEX(psi);
136 #undef INDEX
138 return map[x][y] == '1';
141 static int* make_chi_ind(int nl, t_dlist dl[], int* ndih)
143 int* id;
144 int i, Xi, n;
146 /* There are nl residues with max edMax dihedrals with 4 atoms each */
147 snew(id, nl * edMax * 4);
149 n = 0;
150 for (i = 0; (i < nl); i++)
152 /* Phi, fake the first one */
153 dl[i].j0[edPhi] = n / 4;
154 if (dl[i].atm.minC >= 0)
156 id[n++] = dl[i].atm.minC;
158 else
160 id[n++] = dl[i].atm.H;
162 id[n++] = dl[i].atm.N;
163 id[n++] = dl[i].atm.Cn[1];
164 id[n++] = dl[i].atm.C;
166 for (i = 0; (i < nl); i++)
168 /* Psi, fake the last one */
169 dl[i].j0[edPsi] = n / 4;
170 id[n++] = dl[i].atm.N;
171 id[n++] = dl[i].atm.Cn[1];
172 id[n++] = dl[i].atm.C;
173 if (i < (nl - 1))
175 id[n++] = dl[i + 1].atm.N;
177 else
179 id[n++] = dl[i].atm.O;
182 for (i = 0; (i < nl); i++)
184 /* Omega */
185 if (has_dihedral(edOmega, &(dl[i])))
187 dl[i].j0[edOmega] = n / 4;
188 id[n++] = dl[i].atm.minCalpha;
189 id[n++] = dl[i].atm.minC;
190 id[n++] = dl[i].atm.N;
191 id[n++] = dl[i].atm.Cn[1];
194 for (Xi = 0; (Xi < MAXCHI); Xi++)
196 /* Chi# */
197 for (i = 0; (i < nl); i++)
199 if (dl[i].atm.Cn[Xi + 3] != -1)
201 dl[i].j0[edChi1 + Xi] = n / 4;
202 id[n++] = dl[i].atm.Cn[Xi];
203 id[n++] = dl[i].atm.Cn[Xi + 1];
204 id[n++] = dl[i].atm.Cn[Xi + 2];
205 id[n++] = dl[i].atm.Cn[Xi + 3];
209 *ndih = n / 4;
211 return id;
214 static void do_dihcorr(const char* fn,
215 int nf,
216 int ndih,
217 real** dih,
218 real dt,
219 int nlist,
220 t_dlist dlist[],
221 real time[],
222 int maxchi,
223 gmx_bool bPhi,
224 gmx_bool bPsi,
225 gmx_bool bChi,
226 gmx_bool bOmega,
227 const gmx_output_env_t* oenv)
229 char name1[256], name2[256];
230 int i, j, Xi;
232 do_autocorr(fn, oenv, "Dihedral Autocorrelation Function", nf, ndih, dih, dt, eacCos, FALSE);
233 /* Dump em all */
234 j = 0;
235 for (i = 0; (i < nlist); i++)
237 if (bPhi)
239 print_one(oenv, "corrphi", dlist[i].name, "Phi ACF for", "C(t)", nf / 2, time, dih[j]);
241 j++;
243 for (i = 0; (i < nlist); i++)
245 if (bPsi)
247 print_one(oenv, "corrpsi", dlist[i].name, "Psi ACF for", "C(t)", nf / 2, time, dih[j]);
249 j++;
251 for (i = 0; (i < nlist); i++)
253 if (has_dihedral(edOmega, &dlist[i]))
255 if (bOmega)
257 print_one(oenv, "corromega", dlist[i].name, "Omega ACF for", "C(t)", nf / 2, time, dih[j]);
259 j++;
262 for (Xi = 0; (Xi < maxchi); Xi++)
264 sprintf(name1, "corrchi%d", Xi + 1);
265 sprintf(name2, "Chi%d ACF for", Xi + 1);
266 for (i = 0; (i < nlist); i++)
268 if (dlist[i].atm.Cn[Xi + 3] != -1)
270 if (bChi)
272 print_one(oenv, name1, dlist[i].name, name2, "C(t)", nf / 2, time, dih[j]);
274 j++;
278 fprintf(stderr, "\n");
281 static void copy_dih_data(const real in[], real out[], int nf, gmx_bool bLEAVE)
283 /* if bLEAVE, do nothing to data in copying to out
284 * otherwise multiply by 180/pi to convert rad to deg */
285 int i;
286 real mult;
287 if (bLEAVE)
289 mult = 1;
291 else
293 mult = (180.0 / M_PI);
295 for (i = 0; (i < nf); i++)
297 out[i] = in[i] * mult;
301 static void dump_em_all(int nlist,
302 t_dlist dlist[],
303 int nf,
304 real time[],
305 real** dih,
306 int maxchi,
307 gmx_bool bPhi,
308 gmx_bool bPsi,
309 gmx_bool bChi,
310 gmx_bool bOmega,
311 gmx_bool bRAD,
312 const gmx_output_env_t* oenv)
314 char name[256], titlestr[256], ystr[256];
315 real* data;
316 int i, j, Xi;
318 snew(data, nf);
319 if (bRAD)
321 std::strcpy(ystr, "Angle (rad)");
323 else
325 std::strcpy(ystr, "Angle (degrees)");
328 /* Dump em all */
329 j = 0;
330 for (i = 0; (i < nlist); i++)
332 /* grs debug printf("OK i %d j %d\n", i, j) ; */
333 if (bPhi)
335 copy_dih_data(dih[j], data, nf, bRAD);
336 print_one(oenv, "phi", dlist[i].name, "\\xf\\f{}", ystr, nf, time, data);
338 j++;
340 for (i = 0; (i < nlist); i++)
342 if (bPsi)
344 copy_dih_data(dih[j], data, nf, bRAD);
345 print_one(oenv, "psi", dlist[i].name, "\\xy\\f{}", ystr, nf, time, data);
347 j++;
349 for (i = 0; (i < nlist); i++)
351 if (has_dihedral(edOmega, &(dlist[i])))
353 if (bOmega)
355 copy_dih_data(dih[j], data, nf, bRAD);
356 print_one(oenv, "omega", dlist[i].name, "\\xw\\f{}", ystr, nf, time, data);
358 j++;
362 for (Xi = 0; (Xi < maxchi); Xi++)
364 for (i = 0; (i < nlist); i++)
366 if (dlist[i].atm.Cn[Xi + 3] != -1)
368 if (bChi)
370 sprintf(name, "chi%d", Xi + 1);
371 sprintf(titlestr, "\\xc\\f{}\\s%d\\N", Xi + 1);
372 copy_dih_data(dih[j], data, nf, bRAD);
373 print_one(oenv, name, dlist[i].name, titlestr, ystr, nf, time, data);
375 j++;
379 fprintf(stderr, "\n");
382 static void reset_one(real dih[], int nf, real phase)
384 int j;
386 for (j = 0; (j < nf); j++)
388 dih[j] += phase;
389 while (dih[j] < -M_PI)
391 dih[j] += 2 * M_PI;
393 while (dih[j] >= M_PI)
395 dih[j] -= 2 * M_PI;
400 static int reset_em_all(int nlist, t_dlist dlist[], int nf, real** dih, int maxchi)
402 int i, j, Xi;
404 /* Reset em all */
405 j = 0;
406 /* Phi */
407 for (i = 0; (i < nlist); i++)
409 if (dlist[i].atm.minC == -1)
411 reset_one(dih[j++], nf, M_PI);
413 else
415 reset_one(dih[j++], nf, 0);
418 /* Psi */
419 for (i = 0; (i < nlist - 1); i++)
421 reset_one(dih[j++], nf, 0);
423 /* last Psi is faked from O */
424 reset_one(dih[j++], nf, M_PI);
426 /* Omega */
427 for (i = 0; (i < nlist); i++)
429 if (has_dihedral(edOmega, &dlist[i]))
431 reset_one(dih[j++], nf, 0);
434 /* Chi 1 thru maxchi */
435 for (Xi = 0; (Xi < maxchi); Xi++)
437 for (i = 0; (i < nlist); i++)
439 if (dlist[i].atm.Cn[Xi + 3] != -1)
441 reset_one(dih[j], nf, 0);
442 j++;
446 fprintf(stderr, "j after resetting (nr. active dihedrals) = %d\n", j);
447 return j;
450 static void histogramming(FILE* log,
451 int nbin,
452 ResidueType* rt,
453 int nf,
454 int maxchi,
455 real** dih,
456 int nlist,
457 t_dlist dlist[],
458 const int index[],
459 gmx_bool bPhi,
460 gmx_bool bPsi,
461 gmx_bool bOmega,
462 gmx_bool bChi,
463 gmx_bool bNormalize,
464 gmx_bool bSSHisto,
465 const char* ssdump,
466 real bfac_max,
467 const t_atoms* atoms,
468 gmx_bool bDo_jc,
469 const char* fn,
470 const gmx_output_env_t* oenv)
472 /* also gets 3J couplings and order parameters S2 */
473 // Avoid warnings about narrowing conversions from double to real
474 #ifdef _MSC_VER
475 # pragma warning(disable : 4838)
476 #endif
477 t_karplus kkkphi[] = { { "J_NHa1", 6.51, -1.76, 1.6, -M_PI / 3, 0.0, 0.0 },
478 { "J_NHa2", 6.51, -1.76, 1.6, M_PI / 3, 0.0, 0.0 },
479 { "J_HaC'", 4.0, 1.1, 0.1, 0.0, 0.0, 0.0 },
480 { "J_NHCb", 4.7, -1.5, -0.2, M_PI / 3, 0.0, 0.0 },
481 { "J_Ci-1Hai", 4.5, -1.3, -1.2, 2 * M_PI / 3, 0.0, 0.0 } };
482 t_karplus kkkpsi[] = { { "J_HaN", -0.88, -0.61, -0.27, M_PI / 3, 0.0, 0.0 } };
483 t_karplus kkkchi1[] = { { "JHaHb2", 9.5, -1.6, 1.8, -M_PI / 3, 0, 0.0 },
484 { "JHaHb3", 9.5, -1.6, 1.8, 0, 0, 0.0 } };
485 #ifdef _MSC_VER
486 # pragma warning(default : 4838)
487 #endif
488 #define NKKKPHI asize(kkkphi)
489 #define NKKKPSI asize(kkkpsi)
490 #define NKKKCHI asize(kkkchi1)
491 #define NJC (NKKKPHI + NKKKPSI + NKKKCHI)
493 FILE * fp, *ssfp[3] = { nullptr, nullptr, nullptr };
494 const char* sss[3] = { "sheet", "helix", "coil" };
495 real S2;
496 real* normhisto;
497 real ** Jc, **Jcsig;
498 int**** his_aa_ss = nullptr;
499 int *** his_aa, *histmp;
500 int i, j, k, m, n, nn, Dih, nres, hindex, angle;
501 gmx_bool bBfac, bOccup;
502 char hisfile[256], hhisfile[256], title[256], *ss_str = nullptr;
503 char** leg;
504 const char* residue_name;
505 int rt_size;
507 rt_size = rt->numberOfEntries();
508 if (bSSHisto)
510 fp = gmx_ffopen(ssdump, "r");
511 if (1 != fscanf(fp, "%d", &nres))
513 gmx_fatal(FARGS, "Error reading from file %s", ssdump);
516 snew(ss_str, nres + 1);
517 if (1 != fscanf(fp, "%s", ss_str))
519 gmx_fatal(FARGS, "Error reading from file %s", ssdump);
522 gmx_ffclose(fp);
523 /* Four dimensional array... Very cool */
524 snew(his_aa_ss, 3);
525 for (i = 0; (i < 3); i++)
527 snew(his_aa_ss[i], rt_size + 1);
528 for (j = 0; (j <= rt_size); j++)
530 snew(his_aa_ss[i][j], edMax);
531 for (Dih = 0; (Dih < edMax); Dih++)
533 snew(his_aa_ss[i][j][Dih], nbin + 1);
538 snew(his_aa, edMax);
539 for (Dih = 0; (Dih < edMax); Dih++)
541 snew(his_aa[Dih], rt_size + 1);
542 for (i = 0; (i <= rt_size); i++)
544 snew(his_aa[Dih][i], nbin + 1);
547 snew(histmp, nbin);
549 snew(Jc, nlist);
550 snew(Jcsig, nlist);
551 for (i = 0; (i < nlist); i++)
553 snew(Jc[i], NJC);
554 snew(Jcsig[i], NJC);
557 j = 0;
558 n = 0;
559 for (Dih = 0; (Dih < NONCHI + maxchi); Dih++)
561 for (i = 0; (i < nlist); i++)
563 if (((Dih < edOmega)) || ((Dih == edOmega) && (has_dihedral(edOmega, &(dlist[i]))))
564 || ((Dih > edOmega) && (dlist[i].atm.Cn[Dih - NONCHI + 3] != -1)))
566 make_histo(log, nf, dih[j], nbin, histmp, -M_PI, M_PI);
568 if (bSSHisto)
570 /* Assume there is only one structure, the first.
571 * Compute index in histogram.
573 /* Check the atoms to see whether their B-factors are low enough
574 * Check atoms to see their occupancy is 1.
576 bBfac = bOccup = TRUE;
577 for (nn = 0; (nn < 4); nn++, n++)
579 bBfac = bBfac && (atoms->pdbinfo[index[n]].bfac <= bfac_max);
580 bOccup = bOccup && (atoms->pdbinfo[index[n]].occup == 1);
582 if (bOccup && ((bfac_max <= 0) || bBfac))
584 hindex = static_cast<int>(((dih[j][0] + M_PI) * nbin) / (2 * M_PI));
585 range_check(hindex, 0, nbin);
587 /* Assign dihedral to either of the structure determined
588 * histograms
590 switch (ss_str[dlist[i].resnr])
592 case 'E': his_aa_ss[0][dlist[i].index][Dih][hindex]++; break;
593 case 'H': his_aa_ss[1][dlist[i].index][Dih][hindex]++; break;
594 default: his_aa_ss[2][dlist[i].index][Dih][hindex]++; break;
597 else if (debug)
599 fprintf(debug, "Res. %d has imcomplete occupancy or bfacs > %g\n",
600 dlist[i].resnr, bfac_max);
603 else
605 n += 4;
608 switch (Dih)
610 case edPhi:
611 calc_distribution_props(nbin, histmp, -M_PI, NKKKPHI, kkkphi, &S2);
613 for (m = 0; (m < NKKKPHI); m++)
615 Jc[i][m] = kkkphi[m].Jc;
616 Jcsig[i][m] = kkkphi[m].Jcsig;
618 break;
619 case edPsi:
620 calc_distribution_props(nbin, histmp, -M_PI, NKKKPSI, kkkpsi, &S2);
622 for (m = 0; (m < NKKKPSI); m++)
624 Jc[i][NKKKPHI + m] = kkkpsi[m].Jc;
625 Jcsig[i][NKKKPHI + m] = kkkpsi[m].Jcsig;
627 break;
628 case edChi1:
629 calc_distribution_props(nbin, histmp, -M_PI, NKKKCHI, kkkchi1, &S2);
630 for (m = 0; (m < NKKKCHI); m++)
632 Jc[i][NKKKPHI + NKKKPSI + m] = kkkchi1[m].Jc;
633 Jcsig[i][NKKKPHI + NKKKPSI + m] = kkkchi1[m].Jcsig;
635 break;
636 default: /* covers edOmega and higher Chis than Chi1 */
637 calc_distribution_props(nbin, histmp, -M_PI, 0, nullptr, &S2);
638 break;
640 dlist[i].S2[Dih] = S2;
642 /* Sum distribution per amino acid type as well */
643 for (k = 0; (k < nbin); k++)
645 his_aa[Dih][dlist[i].index][k] += histmp[k];
646 histmp[k] = 0;
648 j++;
650 else /* dihed not defined */
652 dlist[i].S2[Dih] = 0.0;
656 sfree(histmp);
658 /* Print out Jcouplings */
659 fprintf(log, "\n *** J-Couplings from simulation (plus std. dev.) ***\n\n");
660 fprintf(log, "Residue ");
661 for (i = 0; (i < NKKKPHI); i++)
663 fprintf(log, "%7s SD", kkkphi[i].name);
665 for (i = 0; (i < NKKKPSI); i++)
667 fprintf(log, "%7s SD", kkkpsi[i].name);
669 for (i = 0; (i < NKKKCHI); i++)
671 fprintf(log, "%7s SD", kkkchi1[i].name);
673 fprintf(log, "\n");
674 for (i = 0; (i < NJC + 1); i++)
676 fprintf(log, "------------");
678 fprintf(log, "\n");
679 for (i = 0; (i < nlist); i++)
681 fprintf(log, "%-10s", dlist[i].name);
682 for (j = 0; (j < NJC); j++)
684 fprintf(log, " %5.2f %4.2f", Jc[i][j], Jcsig[i][j]);
686 fprintf(log, "\n");
688 fprintf(log, "\n");
690 /* and to -jc file... */
691 if (bDo_jc)
693 fp = xvgropen(fn, "\\S3\\NJ-Couplings from Karplus Equation", "Residue", "Coupling", oenv);
694 snew(leg, NJC);
695 for (i = 0; (i < NKKKPHI); i++)
697 leg[i] = gmx_strdup(kkkphi[i].name);
699 for (i = 0; (i < NKKKPSI); i++)
701 leg[i + NKKKPHI] = gmx_strdup(kkkpsi[i].name);
703 for (i = 0; (i < NKKKCHI); i++)
705 leg[i + NKKKPHI + NKKKPSI] = gmx_strdup(kkkchi1[i].name);
707 xvgr_legend(fp, NJC, leg, oenv);
708 fprintf(fp, "%5s ", "#Res.");
709 for (i = 0; (i < NJC); i++)
711 fprintf(fp, "%10s ", leg[i]);
713 fprintf(fp, "\n");
714 for (i = 0; (i < nlist); i++)
716 fprintf(fp, "%5d ", dlist[i].resnr);
717 for (j = 0; (j < NJC); j++)
719 fprintf(fp, " %8.3f", Jc[i][j]);
721 fprintf(fp, "\n");
723 xvgrclose(fp);
724 for (i = 0; (i < NJC); i++)
726 sfree(leg[i]);
729 /* finished -jc stuff */
731 snew(normhisto, nbin);
732 for (i = 0; (i < rt_size); i++)
734 for (Dih = 0; (Dih < edMax); Dih++)
736 /* First check whether something is in there */
737 for (j = 0; (j < nbin); j++)
739 if (his_aa[Dih][i][j] != 0)
741 break;
744 if ((j < nbin)
745 && ((bPhi && (Dih == edPhi)) || (bPsi && (Dih == edPsi))
746 || (bOmega && (Dih == edOmega)) || (bChi && (Dih >= edChi1))))
748 if (bNormalize)
750 normalize_histo(nbin, his_aa[Dih][i], (360.0 / nbin), normhisto);
753 residue_name = rt->nameFromResidueIndex(i).c_str();
754 switch (Dih)
756 case edPhi:
757 sprintf(hisfile, "histo-phi%s", residue_name);
758 sprintf(title, "\\xf\\f{} Distribution for %s", residue_name);
759 break;
760 case edPsi:
761 sprintf(hisfile, "histo-psi%s", residue_name);
762 sprintf(title, "\\xy\\f{} Distribution for %s", residue_name);
763 break;
764 case edOmega:
765 sprintf(hisfile, "histo-omega%s", residue_name);
766 sprintf(title, "\\xw\\f{} Distribution for %s", residue_name);
767 break;
768 default:
769 sprintf(hisfile, "histo-chi%d%s", Dih - NONCHI + 1, residue_name);
770 sprintf(title, "\\xc\\f{}\\s%d\\N Distribution for %s", Dih - NONCHI + 1,
771 residue_name);
773 std::strcpy(hhisfile, hisfile);
774 std::strcat(hhisfile, ".xvg");
775 fp = xvgropen(hhisfile, title, "Degrees", "", oenv);
776 if (output_env_get_print_xvgr_codes(oenv))
778 fprintf(fp, "@ with g0\n");
780 xvgr_world(fp, -180, 0, 180, 0.1, oenv);
781 if (output_env_get_print_xvgr_codes(oenv))
783 fprintf(fp,
784 "# this effort to set graph size fails unless you run with -autoscale "
785 "none or -autoscale y flags\n");
786 fprintf(fp, "@ xaxis tick on\n");
787 fprintf(fp, "@ xaxis tick major 90\n");
788 fprintf(fp, "@ xaxis tick minor 30\n");
789 fprintf(fp, "@ xaxis ticklabel prec 0\n");
790 fprintf(fp, "@ yaxis tick off\n");
791 fprintf(fp, "@ yaxis ticklabel off\n");
792 fprintf(fp, "@ type xy\n");
794 if (bSSHisto)
796 for (k = 0; (k < 3); k++)
798 std::string sshisfile = gmx::formatString("%s-%s.xvg", hisfile, sss[k]);
799 ssfp[k] = gmx_ffopen(sshisfile, "w");
802 for (j = 0; (j < nbin); j++)
804 angle = -180 + (360 / nbin) * j;
805 if (bNormalize)
807 fprintf(fp, "%5d %10g\n", angle, normhisto[j]);
809 else
811 fprintf(fp, "%5d %10d\n", angle, his_aa[Dih][i][j]);
813 if (bSSHisto)
815 for (k = 0; (k < 3); k++)
817 fprintf(ssfp[k], "%5d %10d\n", angle, his_aa_ss[k][i][Dih][j]);
821 fprintf(fp, "%s\n", output_env_get_print_xvgr_codes(oenv) ? "&" : "");
822 xvgrclose(fp);
823 if (bSSHisto)
825 for (k = 0; (k < 3); k++)
827 fprintf(ssfp[k], "%s\n", output_env_get_print_xvgr_codes(oenv) ? "&" : "");
828 gmx_ffclose(ssfp[k]);
834 sfree(normhisto);
836 if (bSSHisto)
838 /* Four dimensional array... Very cool */
839 for (i = 0; (i < 3); i++)
841 for (j = 0; (j <= rt_size); j++)
843 for (Dih = 0; (Dih < edMax); Dih++)
845 sfree(his_aa_ss[i][j][Dih]);
847 sfree(his_aa_ss[i][j]);
849 sfree(his_aa_ss[i]);
851 sfree(his_aa_ss);
852 sfree(ss_str);
856 static FILE* rama_file(const char* fn, const char* title, const char* xaxis, const char* yaxis, const gmx_output_env_t* oenv)
858 FILE* fp;
860 fp = xvgropen(fn, title, xaxis, yaxis, oenv);
861 if (output_env_get_print_xvgr_codes(oenv))
863 fprintf(fp, "@ with g0\n");
865 xvgr_world(fp, -180, -180, 180, 180, oenv);
866 if (output_env_get_print_xvgr_codes(oenv))
868 fprintf(fp, "@ xaxis tick on\n");
869 fprintf(fp, "@ xaxis tick major 90\n");
870 fprintf(fp, "@ xaxis tick minor 30\n");
871 fprintf(fp, "@ xaxis ticklabel prec 0\n");
872 fprintf(fp, "@ yaxis tick on\n");
873 fprintf(fp, "@ yaxis tick major 90\n");
874 fprintf(fp, "@ yaxis tick minor 30\n");
875 fprintf(fp, "@ yaxis ticklabel prec 0\n");
876 fprintf(fp, "@ s0 type xy\n");
877 fprintf(fp, "@ s0 symbol 2\n");
878 fprintf(fp, "@ s0 symbol size 0.410000\n");
879 fprintf(fp, "@ s0 symbol fill 1\n");
880 fprintf(fp, "@ s0 symbol color 1\n");
881 fprintf(fp, "@ s0 symbol linewidth 1\n");
882 fprintf(fp, "@ s0 symbol linestyle 1\n");
883 fprintf(fp, "@ s0 symbol center false\n");
884 fprintf(fp, "@ s0 symbol char 0\n");
885 fprintf(fp, "@ s0 skip 0\n");
886 fprintf(fp, "@ s0 linestyle 0\n");
887 fprintf(fp, "@ s0 linewidth 1\n");
888 fprintf(fp, "@ type xy\n");
890 return fp;
893 static void do_rama(int nf,
894 int nlist,
895 t_dlist dlist[],
896 real** dih,
897 gmx_bool bViol,
898 gmx_bool bRamOmega,
899 const gmx_output_env_t* oenv)
901 FILE * fp, *gp = nullptr;
902 gmx_bool bOm;
903 char fn[256];
904 int i, j, k, Xi1, Xi2, Phi, Psi, Om = 0, nlevels;
905 constexpr int NMAT = 120;
906 real ** mat = nullptr, phi, psi, omega, axis[NMAT], lo, hi;
907 t_rgb rlo = { 1.0, 0.0, 0.0 };
908 t_rgb rmid = { 1.0, 1.0, 1.0 };
909 t_rgb rhi = { 0.0, 0.0, 1.0 };
911 for (i = 0; (i < nlist); i++)
913 if ((has_dihedral(edPhi, &(dlist[i]))) && (has_dihedral(edPsi, &(dlist[i]))))
915 sprintf(fn, "ramaPhiPsi%s.xvg", dlist[i].name);
916 fp = rama_file(fn, "Ramachandran Plot", "\\8f\\4 (deg)", "\\8y\\4 (deg)", oenv);
917 bOm = bRamOmega && has_dihedral(edOmega, &(dlist[i]));
918 if (bOm)
920 Om = dlist[i].j0[edOmega];
921 snew(mat, NMAT);
922 for (j = 0; (j < NMAT); j++)
924 snew(mat[j], NMAT);
925 axis[j] = -180 + gmx::exactDiv(360 * j, NMAT);
928 if (bViol)
930 sprintf(fn, "violPhiPsi%s.xvg", dlist[i].name);
931 gp = gmx_ffopen(fn, "w");
933 Phi = dlist[i].j0[edPhi];
934 Psi = dlist[i].j0[edPsi];
935 for (j = 0; (j < nf); j++)
937 phi = RAD2DEG * dih[Phi][j];
938 psi = RAD2DEG * dih[Psi][j];
939 fprintf(fp, "%10g %10g\n", phi, psi);
940 if (bViol)
942 fprintf(gp, "%d\n", static_cast<int>(!bAllowed(dih[Phi][j], RAD2DEG * dih[Psi][j])));
944 if (bOm)
946 omega = RAD2DEG * dih[Om][j];
947 mat[static_cast<int>(((phi * NMAT) / 360) + gmx::exactDiv(NMAT, 2))]
948 [static_cast<int>(((psi * NMAT) / 360) + gmx::exactDiv(NMAT, 2))] += omega;
951 if (bViol)
953 gmx_ffclose(gp);
955 xvgrclose(fp);
956 if (bOm)
958 sprintf(fn, "ramomega%s.xpm", dlist[i].name);
959 fp = gmx_ffopen(fn, "w");
960 lo = hi = 0;
961 for (j = 0; (j < NMAT); j++)
963 for (k = 0; (k < NMAT); k++)
965 mat[j][k] /= nf;
966 lo = std::min(mat[j][k], lo);
967 hi = std::max(mat[j][k], hi);
970 /* Symmetrise */
971 if (std::abs(lo) > std::abs(hi))
973 hi = -lo;
975 else
977 lo = -hi;
979 /* Add 180 */
980 for (j = 0; (j < NMAT); j++)
982 for (k = 0; (k < NMAT); k++)
984 mat[j][k] += 180;
987 lo += 180;
988 hi += 180;
989 nlevels = 20;
990 write_xpm3(fp, 0, "Omega/Ramachandran Plot", "Deg", "Phi", "Psi", NMAT, NMAT, axis,
991 axis, mat, lo, 180.0, hi, rlo, rmid, rhi, &nlevels);
992 gmx_ffclose(fp);
993 for (j = 0; (j < NMAT); j++)
995 sfree(mat[j]);
997 sfree(mat);
1000 if ((has_dihedral(edChi1, &(dlist[i]))) && (has_dihedral(edChi2, &(dlist[i]))))
1002 sprintf(fn, "ramaX1X2%s.xvg", dlist[i].name);
1003 fp = rama_file(fn, "\\8c\\4\\s1\\N-\\8c\\4\\s2\\N Ramachandran Plot",
1004 "\\8c\\4\\s1\\N (deg)", "\\8c\\4\\s2\\N (deg)", oenv);
1005 Xi1 = dlist[i].j0[edChi1];
1006 Xi2 = dlist[i].j0[edChi2];
1007 for (j = 0; (j < nf); j++)
1009 fprintf(fp, "%10g %10g\n", RAD2DEG * dih[Xi1][j], RAD2DEG * dih[Xi2][j]);
1011 xvgrclose(fp);
1013 else
1015 fprintf(stderr, "No chi1 & chi2 angle for %s\n", dlist[i].name);
1021 static void print_transitions(const char* fn, int maxchi, int nlist, t_dlist dlist[], real dt, const gmx_output_env_t* oenv)
1023 /* based on order_params below */
1024 FILE* fp;
1025 int i, Dih, Xi;
1027 /* must correspond with enum in pp2shift.h:38 */
1028 char* leg[edMax];
1029 #define NLEG asize(leg)
1031 leg[0] = gmx_strdup("Phi");
1032 leg[1] = gmx_strdup("Psi");
1033 leg[2] = gmx_strdup("Omega");
1034 leg[3] = gmx_strdup("Chi1");
1035 leg[4] = gmx_strdup("Chi2");
1036 leg[5] = gmx_strdup("Chi3");
1037 leg[6] = gmx_strdup("Chi4");
1038 leg[7] = gmx_strdup("Chi5");
1039 leg[8] = gmx_strdup("Chi6");
1041 /* Print order parameters */
1042 fp = xvgropen(fn, "Dihedral Rotamer Transitions", "Residue", "Transitions/ns", oenv);
1043 xvgr_legend(fp, NONCHI + maxchi, leg, oenv);
1045 fprintf(fp, "%5s ", "#Res.");
1046 fprintf(fp, "%10s %10s %10s ", leg[edPhi], leg[edPsi], leg[edOmega]);
1047 for (Xi = 0; Xi < maxchi; Xi++)
1049 fprintf(fp, "%10s ", leg[NONCHI + Xi]);
1051 fprintf(fp, "\n");
1053 for (i = 0; (i < nlist); i++)
1055 fprintf(fp, "%5d ", dlist[i].resnr);
1056 for (Dih = 0; (Dih < NONCHI + maxchi); Dih++)
1058 fprintf(fp, "%10.3f ", dlist[i].ntr[Dih] / dt);
1060 /* fprintf(fp,"%12s\n",dlist[i].name); this confuses xmgrace */
1061 fprintf(fp, "\n");
1063 xvgrclose(fp);
1066 static void order_params(FILE* log,
1067 const char* fn,
1068 int maxchi,
1069 int nlist,
1070 t_dlist dlist[],
1071 const char* pdbfn,
1072 real bfac_init,
1073 t_atoms* atoms,
1074 const rvec x[],
1075 int ePBC,
1076 matrix box,
1077 gmx_bool bPhi,
1078 gmx_bool bPsi,
1079 gmx_bool bChi,
1080 const gmx_output_env_t* oenv)
1082 FILE* fp;
1083 int nh[edMax];
1084 int i, Dih, Xi;
1085 real S2Max, S2Min;
1087 /* except for S2Min/Max, must correspond with enum in pp2shift.h:38 */
1088 const char* const_leg[2 + edMax] = { "S2Min", "S2Max", "Phi", "Psi", "Omega", "Chi1",
1089 "Chi2", "Chi3", "Chi4", "Chi5", "Chi6" };
1090 #define NLEG asize(leg)
1092 char* leg[2 + edMax];
1094 for (i = 0; i < NLEG; i++)
1096 leg[i] = gmx_strdup(const_leg[i]);
1099 /* Print order parameters */
1100 fp = xvgropen(fn, "Dihedral Order Parameters", "Residue", "S2", oenv);
1101 xvgr_legend(fp, 2 + NONCHI + maxchi, const_leg, oenv);
1103 for (Dih = 0; (Dih < edMax); Dih++)
1105 nh[Dih] = 0;
1108 fprintf(fp, "%5s ", "#Res.");
1109 fprintf(fp, "%10s %10s ", leg[0], leg[1]);
1110 fprintf(fp, "%10s %10s %10s ", leg[2 + edPhi], leg[2 + edPsi], leg[2 + edOmega]);
1111 for (Xi = 0; Xi < maxchi; Xi++)
1113 fprintf(fp, "%10s ", leg[2 + NONCHI + Xi]);
1115 fprintf(fp, "\n");
1117 for (i = 0; (i < nlist); i++)
1119 S2Max = -10;
1120 S2Min = 10;
1121 for (Dih = 0; (Dih < NONCHI + maxchi); Dih++)
1123 if (dlist[i].S2[Dih] != 0)
1125 if (dlist[i].S2[Dih] > S2Max)
1127 S2Max = dlist[i].S2[Dih];
1129 if (dlist[i].S2[Dih] < S2Min)
1131 S2Min = dlist[i].S2[Dih];
1134 if (dlist[i].S2[Dih] > 0.8)
1136 nh[Dih]++;
1139 fprintf(fp, "%5d ", dlist[i].resnr);
1140 fprintf(fp, "%10.3f %10.3f ", S2Min, S2Max);
1141 for (Dih = 0; (Dih < NONCHI + maxchi); Dih++)
1143 fprintf(fp, "%10.3f ", dlist[i].S2[Dih]);
1145 fprintf(fp, "\n");
1146 /* fprintf(fp,"%12s\n",dlist[i].name); this confuses xmgrace */
1148 xvgrclose(fp);
1150 if (nullptr != pdbfn)
1152 real x0, y0, z0;
1154 atoms->havePdbInfo = TRUE;
1156 if (nullptr == atoms->pdbinfo)
1158 snew(atoms->pdbinfo, atoms->nr);
1160 for (i = 0; (i < atoms->nr); i++)
1162 atoms->pdbinfo[i].bfac = bfac_init;
1165 for (i = 0; (i < nlist); i++)
1167 atoms->pdbinfo[dlist[i].atm.N].bfac = -dlist[i].S2[0]; /* Phi */
1168 atoms->pdbinfo[dlist[i].atm.H].bfac = -dlist[i].S2[0]; /* Phi */
1169 atoms->pdbinfo[dlist[i].atm.C].bfac = -dlist[i].S2[1]; /* Psi */
1170 atoms->pdbinfo[dlist[i].atm.O].bfac = -dlist[i].S2[1]; /* Psi */
1171 for (Xi = 0; (Xi < maxchi); Xi++) /* Chi's */
1173 if (dlist[i].atm.Cn[Xi + 3] != -1)
1175 atoms->pdbinfo[dlist[i].atm.Cn[Xi + 1]].bfac = -dlist[i].S2[NONCHI + Xi];
1180 fp = gmx_ffopen(pdbfn, "w");
1181 fprintf(fp, "REMARK generated by g_chi\n");
1182 fprintf(fp,
1183 "REMARK "
1184 "B-factor field contains negative of dihedral order parameters\n");
1185 write_pdbfile(fp, nullptr, atoms, x, ePBC, box, ' ', 0, nullptr);
1186 x0 = y0 = z0 = 1000.0;
1187 for (i = 0; (i < atoms->nr); i++)
1189 x0 = std::min(x0, x[i][XX]);
1190 y0 = std::min(y0, x[i][YY]);
1191 z0 = std::min(z0, x[i][ZZ]);
1193 x0 *= 10.0; /* nm -> angstrom */
1194 y0 *= 10.0; /* nm -> angstrom */
1195 z0 *= 10.0; /* nm -> angstrom */
1196 for (i = 0; (i < 10); i++)
1198 gmx_fprintf_pdb_atomline(fp, epdbATOM, atoms->nr + 1 + i, "CA", ' ', "LEG", ' ',
1199 atoms->nres + 1, ' ', x0, y0, z0 + (1.2 * i), 0.0, -0.1 * i,
1200 "");
1202 gmx_ffclose(fp);
1205 fprintf(log, "Dihedrals with S2 > 0.8\n");
1206 fprintf(log, "Dihedral: ");
1207 if (bPhi)
1209 fprintf(log, " Phi ");
1211 if (bPsi)
1213 fprintf(log, " Psi ");
1215 if (bChi)
1217 for (Xi = 0; (Xi < maxchi); Xi++)
1219 fprintf(log, " %s ", leg[2 + NONCHI + Xi]);
1222 fprintf(log, "\nNumber: ");
1223 if (bPhi)
1225 fprintf(log, "%4d ", nh[0]);
1227 if (bPsi)
1229 fprintf(log, "%4d ", nh[1]);
1231 if (bChi)
1233 for (Xi = 0; (Xi < maxchi); Xi++)
1235 fprintf(log, "%4d ", nh[NONCHI + Xi]);
1238 fprintf(log, "\n");
1240 for (i = 0; i < NLEG; i++)
1242 sfree(leg[i]);
1246 int gmx_chi(int argc, char* argv[])
1248 const char* desc[] = {
1249 "[THISMODULE] computes [GRK]phi[grk], [GRK]psi[grk], [GRK]omega[grk],",
1250 "and [GRK]chi[grk] dihedrals for all your",
1251 "amino acid backbone and sidechains.",
1252 "It can compute dihedral angle as a function of time, and as",
1253 "histogram distributions.",
1254 "The distributions [TT](histo-(dihedral)(RESIDUE).xvg[tt]) are cumulative over all ",
1255 "residues of each type.[PAR]",
1256 "If option [TT]-corr[tt] is given, the program will",
1257 "calculate dihedral autocorrelation functions. The function used",
1258 "is C(t) = [CHEVRON][COS][GRK]chi[grk]([GRK]tau[grk])[cos] ",
1259 "[COS][GRK]chi[grk]([GRK]tau[grk]+t)[cos][chevron]. The use of cosines",
1260 "rather than angles themselves, resolves the problem of periodicity.",
1261 "(Van der Spoel & Berendsen (1997), Biophys. J. 72, 2032-2041).",
1262 "Separate files for each dihedral of each residue",
1263 "[TT](corr(dihedral)(RESIDUE)(nresnr).xvg[tt]) are output, as well as a",
1264 "file containing the information for all residues (argument of [TT]-corr[tt]).[PAR]",
1265 "With option [TT]-all[tt], the angles themselves as a function of time for",
1266 "each residue are printed to separate files [TT](dihedral)(RESIDUE)(nresnr).xvg[tt].",
1267 "These can be in radians or degrees.[PAR]",
1268 "A log file (argument [TT]-g[tt]) is also written. This contains",
1270 " * information about the number of residues of each type.",
1271 " * The NMR ^3J coupling constants from the Karplus equation.",
1272 " * a table for each residue of the number of transitions between ",
1273 " rotamers per nanosecond, and the order parameter S^2 of each dihedral.",
1274 " * a table for each residue of the rotamer occupancy.",
1276 "All rotamers are taken as 3-fold, except for [GRK]omega[grk] and [GRK]chi[grk] dihedrals",
1277 "to planar groups (i.e. [GRK]chi[grk][SUB]2[sub] of aromatics, Asp and Asn; ",
1278 "[GRK]chi[grk][SUB]3[sub] of Glu",
1279 "and Gln; and [GRK]chi[grk][SUB]4[sub] of Arg), which are 2-fold. \"rotamer 0\" means ",
1280 "that the dihedral was not in the core region of each rotamer. ",
1281 "The width of the core region can be set with [TT]-core_rotamer[tt][PAR]",
1283 "The S^2 order parameters are also output to an [REF].xvg[ref] file",
1284 "(argument [TT]-o[tt] ) and optionally as a [REF].pdb[ref] file with",
1285 "the S^2 values as B-factor (argument [TT]-p[tt]). ",
1286 "The total number of rotamer transitions per timestep",
1287 "(argument [TT]-ot[tt]), the number of transitions per rotamer",
1288 "(argument [TT]-rt[tt]), and the ^3J couplings (argument [TT]-jc[tt]), ",
1289 "can also be written to [REF].xvg[ref] files. Note that the analysis",
1290 "of rotamer transitions assumes that the supplied trajectory frames",
1291 "are equally spaced in time.[PAR]",
1293 "If [TT]-chi_prod[tt] is set (and [TT]-maxchi[tt] > 0), cumulative rotamers, e.g.",
1294 "1+9([GRK]chi[grk][SUB]1[sub]-1)+3([GRK]chi[grk][SUB]2[sub]-1)+",
1295 "([GRK]chi[grk][SUB]3[sub]-1) (if the residue has three 3-fold ",
1296 "dihedrals and [TT]-maxchi[tt] >= 3)",
1297 "are calculated. As before, if any dihedral is not in the core region,",
1298 "the rotamer is taken to be 0. The occupancies of these cumulative ",
1299 "rotamers (starting with rotamer 0) are written to the file",
1300 "that is the argument of [TT]-cp[tt], and if the [TT]-all[tt] flag",
1301 "is given, the rotamers as functions of time",
1302 "are written to [TT]chiproduct(RESIDUE)(nresnr).xvg[tt] ",
1303 "and their occupancies to [TT]histo-chiproduct(RESIDUE)(nresnr).xvg[tt].[PAR]",
1305 "The option [TT]-r[tt] generates a contour plot of the average [GRK]omega[grk] angle",
1306 "as a function of the [GRK]phi[grk] and [GRK]psi[grk] angles, that is, in a Ramachandran ",
1307 "plot the average [GRK]omega[grk] angle is plotted using color coding.",
1311 const char* bugs[] = {
1312 "Produces MANY output files (up to about 4 times the number of residues in the "
1313 "protein, twice that if autocorrelation functions are calculated). Typically "
1314 "several hundred files are output.",
1315 "[GRK]phi[grk] and [GRK]psi[grk] dihedrals are calculated in a "
1316 "non-standard way, using H-N-CA-C for [GRK]phi[grk] instead of "
1317 "C(-)-N-CA-C, and N-CA-C-O for [GRK]psi[grk] instead of N-CA-C-N(+). "
1318 "This causes (usually small) discrepancies with the output of other "
1319 "tools like [gmx-rama].",
1320 "[TT]-r0[tt] option does not work properly",
1321 "Rotamers with multiplicity 2 are printed in [TT]chi.log[tt] as if they had "
1322 "multiplicity 3, with the 3rd (g(+)) always having probability 0"
1325 /* defaults */
1326 static int r0 = 1, ndeg = 1, maxchi = 2;
1327 static gmx_bool bAll = FALSE;
1328 static gmx_bool bPhi = FALSE, bPsi = FALSE, bOmega = FALSE;
1329 static real bfac_init = -1.0, bfac_max = 0;
1330 static const char* maxchistr[] = { nullptr, "0", "1", "2", "3", "4", "5", "6", nullptr };
1331 static gmx_bool bRama = FALSE, bShift = FALSE, bViol = FALSE, bRamOmega = FALSE;
1332 static gmx_bool bNormHisto = TRUE, bChiProduct = FALSE, bHChi = FALSE, bRAD = FALSE, bPBC = TRUE;
1333 static real core_frac = 0.5;
1334 t_pargs pa[] = {
1335 { "-r0", FALSE, etINT, { &r0 }, "starting residue" },
1336 { "-phi", FALSE, etBOOL, { &bPhi }, "Output for [GRK]phi[grk] dihedral angles" },
1337 { "-psi", FALSE, etBOOL, { &bPsi }, "Output for [GRK]psi[grk] dihedral angles" },
1338 { "-omega",
1339 FALSE,
1340 etBOOL,
1341 { &bOmega },
1342 "Output for [GRK]omega[grk] dihedrals (peptide bonds)" },
1343 { "-rama",
1344 FALSE,
1345 etBOOL,
1346 { &bRama },
1347 "Generate [GRK]phi[grk]/[GRK]psi[grk] and "
1348 "[GRK]chi[grk][SUB]1[sub]/[GRK]chi[grk][SUB]2[sub] Ramachandran plots" },
1349 { "-viol",
1350 FALSE,
1351 etBOOL,
1352 { &bViol },
1353 "Write a file that gives 0 or 1 for violated Ramachandran angles" },
1354 { "-periodic", FALSE, etBOOL, { &bPBC }, "Print dihedral angles modulo 360 degrees" },
1355 { "-all", FALSE, etBOOL, { &bAll }, "Output separate files for every dihedral." },
1356 { "-rad",
1357 FALSE,
1358 etBOOL,
1359 { &bRAD },
1360 "in angle vs time files, use radians rather than degrees." },
1361 { "-shift",
1362 FALSE,
1363 etBOOL,
1364 { &bShift },
1365 "Compute chemical shifts from [GRK]phi[grk]/[GRK]psi[grk] angles" },
1366 { "-binwidth", FALSE, etINT, { &ndeg }, "bin width for histograms (degrees)" },
1367 { "-core_rotamer",
1368 FALSE,
1369 etREAL,
1370 { &core_frac },
1371 "only the central [TT]-core_rotamer[tt]\\*(360/multiplicity) belongs to each rotamer "
1372 "(the rest is assigned to rotamer 0)" },
1373 { "-maxchi", FALSE, etENUM, { maxchistr }, "calculate first ndih [GRK]chi[grk] dihedrals" },
1374 { "-normhisto", FALSE, etBOOL, { &bNormHisto }, "Normalize histograms" },
1375 { "-ramomega",
1376 FALSE,
1377 etBOOL,
1378 { &bRamOmega },
1379 "compute average omega as a function of [GRK]phi[grk]/[GRK]psi[grk] and plot it in an "
1380 "[REF].xpm[ref] plot" },
1381 { "-bfact",
1382 FALSE,
1383 etREAL,
1384 { &bfac_init },
1385 "B-factor value for [REF].pdb[ref] file for atoms with no calculated dihedral order "
1386 "parameter" },
1387 { "-chi_prod",
1388 FALSE,
1389 etBOOL,
1390 { &bChiProduct },
1391 "compute a single cumulative rotamer for each residue" },
1392 { "-HChi", FALSE, etBOOL, { &bHChi }, "Include dihedrals to sidechain hydrogens" },
1393 { "-bmax",
1394 FALSE,
1395 etREAL,
1396 { &bfac_max },
1397 "Maximum B-factor on any of the atoms that make up a dihedral, for the dihedral angle to "
1398 "be considere in the statistics. Applies to database work where a number of X-Ray "
1399 "structures is analyzed. [TT]-bmax[tt] <= 0 means no limit." }
1402 FILE* log;
1403 int nlist, idum, nbin;
1404 rvec* x;
1405 int ePBC;
1406 matrix box;
1407 char grpname[256];
1408 t_dlist* dlist;
1409 gmx_bool bChi, bCorr, bSSHisto;
1410 gmx_bool bDo_rt, bDo_oh, bDo_ot, bDo_jc;
1411 real dt = 0, traj_t_ns;
1412 gmx_output_env_t* oenv;
1414 int isize, *index;
1415 int ndih, nactdih, nf;
1416 real **dih, *trans_frac, *aver_angle, *time;
1417 int i, **chi_lookup, *multiplicity;
1419 t_filenm fnm[] = { { efSTX, "-s", nullptr, ffREAD },
1420 { efTRX, "-f", nullptr, ffREAD },
1421 { efXVG, "-o", "order", ffWRITE },
1422 { efPDB, "-p", "order", ffOPTWR },
1423 { efDAT, "-ss", "ssdump", ffOPTRD },
1424 { efXVG, "-jc", "Jcoupling", ffWRITE },
1425 { efXVG, "-corr", "dihcorr", ffOPTWR },
1426 { efLOG, "-g", "chi", ffWRITE },
1427 /* add two more arguments copying from g_angle */
1428 { efXVG, "-ot", "dihtrans", ffOPTWR },
1429 { efXVG, "-oh", "trhisto", ffOPTWR },
1430 { efXVG, "-rt", "restrans", ffOPTWR },
1431 { efXVG, "-cp", "chiprodhisto", ffOPTWR } };
1432 #define NFILE asize(fnm)
1433 int npargs;
1434 t_pargs* ppa;
1436 npargs = asize(pa);
1437 ppa = add_acf_pargs(&npargs, pa);
1438 if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, npargs, ppa,
1439 asize(desc), desc, asize(bugs), bugs, &oenv))
1441 sfree(ppa);
1442 return 0;
1445 /* Handle result from enumerated type */
1446 sscanf(maxchistr[0], "%d", &maxchi);
1447 bChi = (maxchi > 0);
1449 log = gmx_ffopen(ftp2fn(efLOG, NFILE, fnm), "w");
1451 if (bRamOmega)
1453 bOmega = TRUE;
1454 bPhi = TRUE;
1455 bPsi = TRUE;
1458 /* set some options */
1459 bDo_rt = (opt2bSet("-rt", NFILE, fnm));
1460 bDo_oh = (opt2bSet("-oh", NFILE, fnm));
1461 bDo_ot = (opt2bSet("-ot", NFILE, fnm));
1462 bDo_jc = (opt2bSet("-jc", NFILE, fnm));
1463 bCorr = (opt2bSet("-corr", NFILE, fnm));
1464 if (bCorr)
1466 fprintf(stderr, "Will calculate autocorrelation\n");
1469 if (core_frac > 1.0)
1471 fprintf(stderr, "core_rotamer fraction > 1.0 ; will use 1.0\n");
1472 core_frac = 1.0;
1474 if (core_frac < 0.0)
1476 fprintf(stderr, "core_rotamer fraction < 0.0 ; will use 0.0\n");
1477 core_frac = 0.0;
1480 if (maxchi > MAXCHI)
1482 fprintf(stderr, "Will only calculate first %d Chi dihedrals instead of %d.\n", MAXCHI, maxchi);
1483 maxchi = MAXCHI;
1485 bSSHisto = ftp2bSet(efDAT, NFILE, fnm);
1486 nbin = 360 / ndeg;
1488 /* Find the chi angles using atoms struct and a list of amino acids */
1489 t_topology* top;
1490 snew(top, 1);
1491 read_tps_conf(ftp2fn(efSTX, NFILE, fnm), top, &ePBC, &x, nullptr, box, FALSE);
1492 t_atoms& atoms = top->atoms;
1493 if (atoms.pdbinfo == nullptr)
1495 snew(atoms.pdbinfo, atoms.nr);
1497 fprintf(log, "Title: %s\n", *top->name);
1499 ResidueType rt;
1500 dlist = mk_dlist(log, &atoms, &nlist, bPhi, bPsi, bChi, bHChi, maxchi, r0, &rt);
1501 fprintf(stderr, "%d residues with dihedrals found\n", nlist);
1503 if (nlist == 0)
1505 gmx_fatal(FARGS, "No dihedrals in your structure!\n");
1508 /* Make a linear index for reading all. */
1509 index = make_chi_ind(nlist, dlist, &ndih);
1510 isize = 4 * ndih;
1511 fprintf(stderr, "%d dihedrals found\n", ndih);
1513 snew(dih, ndih);
1515 /* COMPUTE ALL DIHEDRALS! */
1516 read_ang_dih(ftp2fn(efTRX, NFILE, fnm), FALSE, TRUE, FALSE, bPBC, 1, &idum, &nf, &time, isize,
1517 index, &trans_frac, &aver_angle, dih, oenv);
1519 dt = (time[nf - 1] - time[0]) / (nf - 1); /* might want this for corr or n. transit*/
1520 if (bCorr)
1522 if (nf < 2)
1524 gmx_fatal(FARGS, "Need at least 2 frames for correlation");
1528 /* put angles in -M_PI to M_PI ! and correct phase factor for phi and psi
1529 * pass nactdih instead of ndih to low_ana_dih_trans and get_chi_product_traj
1530 * to prevent accessing off end of arrays when maxchi < 5 or 6. */
1531 nactdih = reset_em_all(nlist, dlist, nf, dih, maxchi);
1533 if (bAll)
1535 dump_em_all(nlist, dlist, nf, time, dih, maxchi, bPhi, bPsi, bChi, bOmega, bRAD, oenv);
1538 /* Histogramming & J coupling constants & calc of S2 order params */
1539 histogramming(log, nbin, &rt, nf, maxchi, dih, nlist, dlist, index, bPhi, bPsi, bOmega, bChi,
1540 bNormHisto, bSSHisto, ftp2fn(efDAT, NFILE, fnm), bfac_max, &atoms, bDo_jc,
1541 opt2fn("-jc", NFILE, fnm), oenv);
1543 /* transitions
1545 * added multiplicity */
1547 snew(multiplicity, ndih);
1548 mk_multiplicity_lookup(multiplicity, maxchi, nlist, dlist, ndih);
1550 std::strcpy(grpname, "All residues, ");
1551 if (bPhi)
1553 std::strcat(grpname, "Phi ");
1555 if (bPsi)
1557 std::strcat(grpname, "Psi ");
1559 if (bOmega)
1561 std::strcat(grpname, "Omega ");
1563 if (bChi)
1565 std::strcat(grpname, "Chi 1-");
1566 sprintf(grpname + std::strlen(grpname), "%i", maxchi);
1570 low_ana_dih_trans(bDo_ot, opt2fn("-ot", NFILE, fnm), bDo_oh, opt2fn("-oh", NFILE, fnm), maxchi, dih,
1571 nlist, dlist, nf, nactdih, grpname, multiplicity, time, FALSE, core_frac, oenv);
1573 /* Order parameters */
1574 order_params(log, opt2fn("-o", NFILE, fnm), maxchi, nlist, dlist, ftp2fn_null(efPDB, NFILE, fnm),
1575 bfac_init, &atoms, x, ePBC, box, bPhi, bPsi, bChi, oenv);
1577 /* Print ramachandran maps! */
1578 if (bRama)
1580 do_rama(nf, nlist, dlist, dih, bViol, bRamOmega, oenv);
1583 if (bShift)
1585 do_pp2shifts(log, nf, nlist, dlist, dih);
1588 /* rprint S^2, transitions, and rotamer occupancies to log */
1589 traj_t_ns = 0.001 * (time[nf - 1] - time[0]);
1590 pr_dlist(log, nlist, dlist, traj_t_ns, edPrintST, bPhi, bPsi, bChi, bOmega, maxchi);
1591 pr_dlist(log, nlist, dlist, traj_t_ns, edPrintRO, bPhi, bPsi, bChi, bOmega, maxchi);
1592 gmx_ffclose(log);
1593 /* transitions to xvg */
1594 if (bDo_rt)
1596 print_transitions(opt2fn("-rt", NFILE, fnm), maxchi, nlist, dlist, traj_t_ns, oenv);
1599 /* chi_product trajectories (ie one "rotamer number" for each residue) */
1600 if (bChiProduct && bChi)
1602 snew(chi_lookup, nlist);
1603 for (i = 0; i < nlist; i++)
1605 snew(chi_lookup[i], maxchi);
1607 mk_chi_lookup(chi_lookup, maxchi, nlist, dlist);
1609 get_chi_product_traj(dih, nf, nactdih, maxchi, dlist, time, chi_lookup, multiplicity, FALSE,
1610 bNormHisto, core_frac, bAll, opt2fn("-cp", NFILE, fnm), oenv);
1612 for (i = 0; i < nlist; i++)
1614 sfree(chi_lookup[i]);
1618 /* Correlation comes last because it messes up the angles */
1619 if (bCorr)
1621 do_dihcorr(opt2fn("-corr", NFILE, fnm), nf, ndih, dih, dt, nlist, dlist, time, maxchi, bPhi,
1622 bPsi, bChi, bOmega, oenv);
1626 do_view(oenv, opt2fn("-o", NFILE, fnm), "-nxy");
1627 do_view(oenv, opt2fn("-jc", NFILE, fnm), "-nxy");
1628 if (bCorr)
1630 do_view(oenv, opt2fn("-corr", NFILE, fnm), "-nxy");
1633 return 0;