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,2021, 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.
49 #include "gromacs/commandline/pargs.h"
50 #include "gromacs/commandline/viewit.h"
51 #include "gromacs/correlationfunctions/autocorr.h"
52 #include "gromacs/fileio/confio.h"
53 #include "gromacs/fileio/matio.h"
54 #include "gromacs/fileio/pdbio.h"
55 #include "gromacs/fileio/xvgr.h"
56 #include "gromacs/gmxana/gmx_ana.h"
57 #include "gromacs/gmxana/gstat.h"
58 #include "gromacs/math/units.h"
59 #include "gromacs/math/utilities.h"
60 #include "gromacs/math/vec.h"
61 #include "gromacs/topology/residuetypes.h"
62 #include "gromacs/topology/topology.h"
63 #include "gromacs/utility/arraysize.h"
64 #include "gromacs/utility/cstringutil.h"
65 #include "gromacs/utility/fatalerror.h"
66 #include "gromacs/utility/futil.h"
67 #include "gromacs/utility/smalloc.h"
68 #include "gromacs/utility/stringutil.h"
69 #include "gromacs/utility/unique_cptr.h"
71 static gmx_bool bAllowed(real phi, real psi)
73 static const char* map[] = { "1100000000000000001111111000000000001111111111111111111111111",
74 "1100000000000000001111110000000000011111111111111111111111111",
75 "1100000000000000001111110000000000011111111111111111111111111",
76 "1100000000000000001111100000000000111111111111111111111111111",
77 "1100000000000000001111100000000000111111111111111111111111111",
78 "1100000000000000001111100000000001111111111111111111111111111",
79 "1100000000000000001111100000000001111111111111111111111111111",
80 "1100000000000000001111100000000011111111111111111111111111111",
81 "1110000000000000001111110000000111111111111111111111111111111",
82 "1110000000000000001111110000001111111111111111111111111111111",
83 "1110000000000000001111111000011111111111111111111111111111111",
84 "1110000000000000001111111100111111111111111111111111111111111",
85 "1110000000000000001111111111111111111111111111111111111111111",
86 "1110000000000000001111111111111111111111111111111111111111111",
87 "1110000000000000001111111111111111111111111111111111111111111",
88 "1110000000000000001111111111111111111111111111111111111111111",
89 "1110000000000000001111111111111110011111111111111111111111111",
90 "1110000000000000001111111111111100000111111111111111111111111",
91 "1110000000000000001111111111111000000000001111111111111111111",
92 "1100000000000000001111111111110000000000000011111111111111111",
93 "1100000000000000001111111111100000000000000011111111111111111",
94 "1000000000000000001111111111000000000000000001111111111111110",
95 "0000000000000000001111111110000000000000000000111111111111100",
96 "0000000000000000000000000000000000000000000000000000000000000",
97 "0000000000000000000000000000000000000000000000000000000000000",
98 "0000000000000000000000000000000000000000000000000000000000000",
99 "0000000000000000000000000000000000000000000000000000000000000",
100 "0000000000000000000000000000000000000000000000000000000000000",
101 "0000000000000000000000000000000000000000000000000000000000000",
102 "0000000000000000000000000000000000000000000000000000000000000",
103 "0000000000000000000000000000000000000000000000000000000000000",
104 "0000000000000000000000000000000000000000000000000000000000000",
105 "0000000000000000000000000000000000000000000000000000000000000",
106 "0000000000000000000000000000000000000000000000000000000000000",
107 "0000000000000000000000000000000000000000000000000000000000000",
108 "0000000000000000000000000000000000000000000000000000000000000",
109 "0000000000000000000000000000000000000000000000000000000000000",
110 "0000000000000000000000000000000000000000000000000000000000000",
111 "0000000000000000000000000000000000111111111111000000000000000",
112 "1100000000000000000000000000000001111111111111100000000000111",
113 "1100000000000000000000000000000001111111111111110000000000111",
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 "0000000000000000000000000000000000000000000000000000000000000",
131 "0000000000000000000000000000000000000000000000000000000000000",
132 "0000000000000000000000000000000000000000000000000000000000000",
133 "0000000000000000000000000000000000000000000000000000000000000" };
136 #define INDEX(ppp) (((static_cast<int>(360 + (ppp)*gmx::c_rad2Deg)) % 360) / 6)
141 return map[x][y] == '1';
144 static std::vector<int> make_chi_ind(gmx::ArrayRef<t_dlist> dlist)
146 /* There are dlist.size() residues with max edMax dihedrals with 4
147 * atoms each. This may be an over-allocation, which is reduced
149 std::vector<int> id(dlist.size() * edMax * 4);
152 for (auto& dihedral : dlist)
154 /* Phi, fake the first one */
155 dihedral.j0[edPhi] = n / 4;
156 if (dihedral.atm.minC >= 0)
158 id[n++] = dihedral.atm.minC;
162 id[n++] = dihedral.atm.H;
164 id[n++] = dihedral.atm.N;
165 id[n++] = dihedral.atm.Cn[1];
166 id[n++] = dihedral.atm.C;
170 for (auto& dihedral : dlist)
172 /* Psi, fake the last one */
173 dihedral.j0[edPsi] = n / 4;
174 id[n++] = dihedral.atm.N;
175 id[n++] = dihedral.atm.Cn[1];
176 id[n++] = dihedral.atm.C;
177 if (i < (gmx::ssize(dlist) - 1))
179 id[n++] = dlist[i + 1].atm.N;
183 id[n++] = dihedral.atm.O;
188 for (auto& dihedral : dlist)
191 if (has_dihedral(edOmega, dihedral))
193 dihedral.j0[edOmega] = n / 4;
194 id[n++] = dihedral.atm.minCalpha;
195 id[n++] = dihedral.atm.minC;
196 id[n++] = dihedral.atm.N;
197 id[n++] = dihedral.atm.Cn[1];
200 for (int Xi = 0; (Xi < MAXCHI); Xi++)
203 for (auto& dihedral : dlist)
205 if (dihedral.atm.Cn[Xi + 3] != -1)
207 dihedral.j0[edChi1 + Xi] = n / 4;
208 id[n++] = dihedral.atm.Cn[Xi];
209 id[n++] = dihedral.atm.Cn[Xi + 1];
210 id[n++] = dihedral.atm.Cn[Xi + 2];
211 id[n++] = dihedral.atm.Cn[Xi + 3];
220 static void do_dihcorr(const char* fn,
225 gmx::ArrayRef<const t_dlist> dlist,
232 const gmx_output_env_t* oenv)
234 char name1[256], name2[256];
237 do_autocorr(fn, oenv, "Dihedral Autocorrelation Function", nf, ndih, dih, dt, eacCos, FALSE);
240 for (const auto& dihedral : dlist)
244 print_one(oenv, "corrphi", dihedral.name, "Phi ACF for", "C(t)", nf / 2, time, dih[j]);
248 for (const auto& dihedral : dlist)
252 print_one(oenv, "corrpsi", dihedral.name, "Psi ACF for", "C(t)", nf / 2, time, dih[j]);
256 for (const auto& dihedral : dlist)
258 if (has_dihedral(edOmega, dihedral))
262 print_one(oenv, "corromega", dihedral.name, "Omega ACF for", "C(t)", nf / 2, time, dih[j]);
267 for (Xi = 0; (Xi < maxchi); Xi++)
269 sprintf(name1, "corrchi%d", Xi + 1);
270 sprintf(name2, "Chi%d ACF for", Xi + 1);
271 for (const auto& dihedral : dlist)
273 if (dihedral.atm.Cn[Xi + 3] != -1)
277 print_one(oenv, name1, dihedral.name, name2, "C(t)", nf / 2, time, dih[j]);
283 fprintf(stderr, "\n");
286 static void copy_dih_data(const real in[], real out[], int nf, gmx_bool bLEAVE)
288 /* if bLEAVE, do nothing to data in copying to out
289 * otherwise multiply by 180/pi to convert rad to deg */
298 mult = (180.0 / M_PI);
300 for (i = 0; (i < nf); i++)
302 out[i] = in[i] * mult;
306 static void dump_em_all(gmx::ArrayRef<const t_dlist> dlist,
316 const gmx_output_env_t* oenv)
318 char name[256], titlestr[256], ystr[256];
322 gmx::sfree_guard dataGuard(data);
325 std::strcpy(ystr, "Angle (rad)");
329 std::strcpy(ystr, "Angle (degrees)");
334 for (const auto& dihedral : dlist)
338 copy_dih_data(dih[j], data, nf, bRAD);
339 print_one(oenv, "phi", dihedral.name, "\\xf\\f{}", ystr, nf, time, data);
343 for (const auto& dihedral : dlist)
347 copy_dih_data(dih[j], data, nf, bRAD);
348 print_one(oenv, "psi", dihedral.name, "\\xy\\f{}", ystr, nf, time, data);
352 for (const auto& dihedral : dlist)
354 if (has_dihedral(edOmega, dihedral))
358 copy_dih_data(dih[j], data, nf, bRAD);
359 print_one(oenv, "omega", dihedral.name, "\\xw\\f{}", ystr, nf, time, data);
365 for (int Xi = 0; (Xi < maxchi); Xi++)
367 for (const auto& dihedral : dlist)
369 if (dihedral.atm.Cn[Xi + 3] != -1)
373 sprintf(name, "chi%d", Xi + 1);
374 sprintf(titlestr, "\\xc\\f{}\\s%d\\N", Xi + 1);
375 copy_dih_data(dih[j], data, nf, bRAD);
376 print_one(oenv, name, dihedral.name, titlestr, ystr, nf, time, data);
382 fprintf(stderr, "\n");
385 static void reset_one(real dih[], int nf, real phase)
389 for (j = 0; (j < nf); j++)
392 while (dih[j] < -M_PI)
396 while (dih[j] >= M_PI)
403 static int reset_em_all(gmx::ArrayRef<const t_dlist> dlist, int nf, real** dih, int maxchi)
408 for (const auto& dihedral : dlist)
410 if (dihedral.atm.minC == -1)
412 reset_one(dih[j++], nf, M_PI);
416 reset_one(dih[j++], nf, 0);
420 for (size_t i = 0; i < dlist.size() - 1; ++i)
422 reset_one(dih[j++], nf, 0);
424 /* last Psi is faked from O */
425 reset_one(dih[j++], nf, M_PI);
428 for (const auto& dihedral : dlist)
430 if (has_dihedral(edOmega, dihedral))
432 reset_one(dih[j++], nf, 0);
435 /* Chi 1 thru maxchi */
436 for (int Xi = 0; (Xi < maxchi); Xi++)
438 for (const auto& dihedral : dlist)
440 if (dihedral.atm.Cn[Xi + 3] != -1)
442 reset_one(dih[j], nf, 0);
447 fprintf(stderr, "j after resetting (nr. active dihedrals) = %d\n", j);
451 static void histogramming(FILE* log,
457 gmx::ArrayRef<t_dlist> dlist,
458 gmx::ArrayRef<const int> index,
467 const t_atoms* atoms,
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
475 # pragma warning(disable : 4838)
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 } };
486 # pragma warning(default : 4838)
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" };
498 int m, n, nn, nres, hindex, angle;
499 gmx_bool bBfac, bOccup;
500 char hisfile[256], hhisfile[256], title[256], *ss_str = nullptr;
503 size_t rt_size = rt->numberOfEntries();
506 fp = gmx_ffopen(ssdump, "r");
507 if (1 != fscanf(fp, "%d", &nres))
509 gmx_fatal(FARGS, "Error reading from file %s", ssdump);
512 snew(ss_str, nres + 1);
513 if (1 != fscanf(fp, "%s", ss_str))
515 gmx_fatal(FARGS, "Error reading from file %s", ssdump);
521 // Build the lookup tables for data relating to the all dihedrals
522 // from each unique residue name represented in the dihedral list.
523 std::array<std::vector<std::vector<std::vector<int>>>, 3> his_aa_ss;
526 for (auto& secondaryStructure : his_aa_ss)
528 // Construct the vector nest
529 secondaryStructure = { rt_size + 1, { edMax, std::vector<int>(nbin, 0) } };
532 std::vector<std::vector<std::vector<int>>> his_aa = { edMax,
533 { rt_size + 1, std::vector<int>(nbin, 0) } };
536 snew(Jc, dlist.size());
537 snew(Jcsig, dlist.size());
538 for (size_t i = 0; i < dlist.size(); i++)
546 for (int Dih = 0; (Dih < NONCHI + maxchi); Dih++)
549 for (auto& dihedral : dlist)
551 if (((Dih < edOmega)) || ((Dih == edOmega) && (has_dihedral(edOmega, dihedral)))
552 || ((Dih > edOmega) && (dihedral.atm.Cn[Dih - NONCHI + 3] != -1)))
554 make_histo(log, nf, dih[j], nbin, histmp, -M_PI, M_PI);
558 /* Assume there is only one structure, the first.
559 * Compute index in histogram.
561 /* Check the atoms to see whether their B-factors are low enough
562 * Check atoms to see their occupancy is 1.
564 bBfac = bOccup = TRUE;
565 for (nn = 0; (nn < 4); nn++, n++)
567 bBfac = bBfac && (atoms->pdbinfo[index[n]].bfac <= bfac_max);
568 bOccup = bOccup && (atoms->pdbinfo[index[n]].occup == 1);
570 if (bOccup && ((bfac_max <= 0) || bBfac))
572 hindex = static_cast<int>(((dih[j][0] + M_PI) * nbin) / (2 * M_PI));
573 range_check(hindex, 0, nbin);
575 /* Assign dihedral to either of the structure determined
578 switch (ss_str[dihedral.resnr])
580 case 'E': his_aa_ss[0][dihedral.index][Dih][hindex]++; break;
581 case 'H': his_aa_ss[1][dihedral.index][Dih][hindex]++; break;
582 default: his_aa_ss[2][dihedral.index][Dih][hindex]++; break;
587 fprintf(debug, "Res. %d has imcomplete occupancy or bfacs > %g\n", dihedral.resnr, bfac_max);
598 calc_distribution_props(nbin, histmp, -M_PI, NKKKPHI, kkkphi, &S2);
600 for (m = 0; (m < NKKKPHI); m++)
602 Jc[i][m] = kkkphi[m].Jc;
603 Jcsig[i][m] = kkkphi[m].Jcsig;
607 calc_distribution_props(nbin, histmp, -M_PI, NKKKPSI, kkkpsi, &S2);
609 for (m = 0; (m < NKKKPSI); m++)
611 Jc[i][NKKKPHI + m] = kkkpsi[m].Jc;
612 Jcsig[i][NKKKPHI + m] = kkkpsi[m].Jcsig;
616 calc_distribution_props(nbin, histmp, -M_PI, NKKKCHI, kkkchi1, &S2);
617 for (m = 0; (m < NKKKCHI); m++)
619 Jc[i][NKKKPHI + NKKKPSI + m] = kkkchi1[m].Jc;
620 Jcsig[i][NKKKPHI + NKKKPSI + m] = kkkchi1[m].Jcsig;
623 default: /* covers edOmega and higher Chis than Chi1 */
624 calc_distribution_props(nbin, histmp, -M_PI, 0, nullptr, &S2);
627 dihedral.S2[Dih] = S2;
629 /* Sum distribution per amino acid type as well */
630 for (int k = 0; (k < nbin); k++)
632 his_aa[Dih][dihedral.index][k] += histmp[k];
637 else /* dihed not defined */
639 dihedral.S2[Dih] = 0.0;
646 /* Print out Jcouplings */
647 fprintf(log, "\n *** J-Couplings from simulation (plus std. dev.) ***\n\n");
648 fprintf(log, "Residue ");
649 for (int i = 0; (i < NKKKPHI); i++)
651 fprintf(log, "%7s SD", kkkphi[i].name);
653 for (int i = 0; (i < NKKKPSI); i++)
655 fprintf(log, "%7s SD", kkkpsi[i].name);
657 for (int i = 0; (i < NKKKCHI); i++)
659 fprintf(log, "%7s SD", kkkchi1[i].name);
662 for (int i = 0; (i < NJC + 1); i++)
664 fprintf(log, "------------");
669 for (const auto& dihedral : dlist)
671 fprintf(log, "%-10s", dihedral.name);
672 for (int j = 0; (j < NJC); j++)
674 fprintf(log, " %5.2f %4.2f", Jc[i][j], Jcsig[i][j]);
682 /* and to -jc file... */
685 fp = xvgropen(fn, "\\S3\\NJ-Couplings from Karplus Equation", "Residue", "Coupling", oenv);
687 for (int i = 0; (i < NKKKPHI); i++)
689 leg[i] = gmx_strdup(kkkphi[i].name);
691 for (int i = 0; (i < NKKKPSI); i++)
693 leg[i + NKKKPHI] = gmx_strdup(kkkpsi[i].name);
695 for (int i = 0; (i < NKKKCHI); i++)
697 leg[i + NKKKPHI + NKKKPSI] = gmx_strdup(kkkchi1[i].name);
699 xvgr_legend(fp, NJC, leg, oenv);
700 fprintf(fp, "%5s ", "#Res.");
701 for (int i = 0; (i < NJC); i++)
703 fprintf(fp, "%10s ", leg[i]);
708 for (const auto& dihedral : dlist)
710 fprintf(fp, "%5d ", dihedral.resnr);
711 for (int j = 0; (j < NJC); j++)
713 fprintf(fp, " %8.3f", Jc[i][j]);
720 for (int i = 0; (i < NJC); i++)
726 /* finished -jc stuff */
728 std::vector<real> normhisto(nbin);
729 for (size_t i = 0; (i < rt_size); i++)
731 for (int Dih = 0; (Dih < edMax); Dih++)
733 /* First check whether something is in there */
735 for (j = 0; (j < nbin); j++)
737 if (his_aa[Dih][i][j] != 0)
743 && ((bPhi && (Dih == edPhi)) || (bPsi && (Dih == edPsi))
744 || (bOmega && (Dih == edOmega)) || (bChi && (Dih >= edChi1))))
748 normalize_histo(his_aa[Dih][i], (360.0 / nbin), normhisto);
751 std::string residueName = rt->nameFromResidueIndex(i);
755 sprintf(hisfile, "histo-phi%s", residueName.c_str());
756 sprintf(title, "\\xf\\f{} Distribution for %s", residueName.c_str());
759 sprintf(hisfile, "histo-psi%s", residueName.c_str());
760 sprintf(title, "\\xy\\f{} Distribution for %s", residueName.c_str());
763 sprintf(hisfile, "histo-omega%s", residueName.c_str());
764 sprintf(title, "\\xw\\f{} Distribution for %s", residueName.c_str());
767 sprintf(hisfile, "histo-chi%d%s", Dih - NONCHI + 1, residueName.c_str());
769 "\\xc\\f{}\\s%d\\N Distribution for %s",
771 residueName.c_str());
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))
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");
796 for (int 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 (int j = 0; (j < nbin); j++)
804 angle = -180 + (360 / nbin) * j;
807 fprintf(fp, "%5d %10g\n", angle, normhisto[j]);
811 fprintf(fp, "%5d %10d\n", angle, his_aa[Dih][i][j]);
815 for (int 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) ? "&" : "");
825 for (int k = 0; (k < 3); k++)
827 fprintf(ssfp[k], "%s\n", output_env_get_print_xvgr_codes(oenv) ? "&" : "");
828 gmx_ffclose(ssfp[k]);
839 for (size_t i = 0; i < dlist.size(); i++)
848 static FILE* rama_file(const char* fn, const char* title, const char* xaxis, const char* yaxis, const gmx_output_env_t* oenv)
852 fp = xvgropen(fn, title, xaxis, yaxis, oenv);
853 if (output_env_get_print_xvgr_codes(oenv))
855 fprintf(fp, "@ with g0\n");
857 xvgr_world(fp, -180, -180, 180, 180, oenv);
858 if (output_env_get_print_xvgr_codes(oenv))
860 fprintf(fp, "@ xaxis tick on\n");
861 fprintf(fp, "@ xaxis tick major 90\n");
862 fprintf(fp, "@ xaxis tick minor 30\n");
863 fprintf(fp, "@ xaxis ticklabel prec 0\n");
864 fprintf(fp, "@ yaxis tick on\n");
865 fprintf(fp, "@ yaxis tick major 90\n");
866 fprintf(fp, "@ yaxis tick minor 30\n");
867 fprintf(fp, "@ yaxis ticklabel prec 0\n");
868 fprintf(fp, "@ s0 type xy\n");
869 fprintf(fp, "@ s0 symbol 2\n");
870 fprintf(fp, "@ s0 symbol size 0.410000\n");
871 fprintf(fp, "@ s0 symbol fill 1\n");
872 fprintf(fp, "@ s0 symbol color 1\n");
873 fprintf(fp, "@ s0 symbol linewidth 1\n");
874 fprintf(fp, "@ s0 symbol linestyle 1\n");
875 fprintf(fp, "@ s0 symbol center false\n");
876 fprintf(fp, "@ s0 symbol char 0\n");
877 fprintf(fp, "@ s0 skip 0\n");
878 fprintf(fp, "@ s0 linestyle 0\n");
879 fprintf(fp, "@ s0 linewidth 1\n");
880 fprintf(fp, "@ type xy\n");
885 static void do_rama(int nf,
886 gmx::ArrayRef<const t_dlist> dlist,
890 const gmx_output_env_t* oenv)
892 FILE * fp, *gp = nullptr;
895 int Xi1, Xi2, Phi, Psi, Om = 0, nlevels;
896 constexpr int NMAT = 120;
897 real ** mat = nullptr, phi, psi, omega, axis[NMAT], lo, hi;
898 t_rgb rlo = { 1.0, 0.0, 0.0 };
899 t_rgb rmid = { 1.0, 1.0, 1.0 };
900 t_rgb rhi = { 0.0, 0.0, 1.0 };
902 for (const auto& dihedral : dlist)
904 if ((has_dihedral(edPhi, dihedral)) && has_dihedral(edPsi, dihedral))
906 sprintf(fn, "ramaPhiPsi%s.xvg", dihedral.name);
907 fp = rama_file(fn, "Ramachandran Plot", "\\8f\\4 (deg)", "\\8y\\4 (deg)", oenv);
908 bOm = bRamOmega && has_dihedral(edOmega, dihedral);
911 Om = dihedral.j0[edOmega];
913 for (int j = 0; (j < NMAT); j++)
916 axis[j] = -180 + gmx::exactDiv(360 * j, NMAT);
921 sprintf(fn, "violPhiPsi%s.xvg", dihedral.name);
922 gp = gmx_ffopen(fn, "w");
924 Phi = dihedral.j0[edPhi];
925 Psi = dihedral.j0[edPsi];
926 for (int j = 0; (j < nf); j++)
928 phi = gmx::c_rad2Deg * dih[Phi][j];
929 psi = gmx::c_rad2Deg * dih[Psi][j];
930 fprintf(fp, "%10g %10g\n", phi, psi);
935 static_cast<int>(!bAllowed(dih[Phi][j], gmx::c_rad2Deg * dih[Psi][j])));
939 omega = gmx::c_rad2Deg * dih[Om][j];
940 mat[static_cast<int>(((phi * NMAT) / 360) + gmx::exactDiv(NMAT, 2))]
941 [static_cast<int>(((psi * NMAT) / 360) + gmx::exactDiv(NMAT, 2))] += omega;
951 sprintf(fn, "ramomega%s.xpm", dihedral.name);
952 fp = gmx_ffopen(fn, "w");
954 for (int j = 0; (j < NMAT); j++)
956 for (int k = 0; (k < NMAT); k++)
959 lo = std::min(mat[j][k], lo);
960 hi = std::max(mat[j][k], hi);
964 if (std::abs(lo) > std::abs(hi))
973 for (int j = 0; (j < NMAT); j++)
975 for (int k = 0; (k < NMAT); k++)
985 "Omega/Ramachandran Plot",
1002 for (int j = 0; (j < NMAT); j++)
1009 if (has_dihedral(edChi1, dihedral) && has_dihedral(edChi2, dihedral))
1011 sprintf(fn, "ramaX1X2%s.xvg", dihedral.name);
1013 "\\8c\\4\\s1\\N-\\8c\\4\\s2\\N Ramachandran Plot",
1014 "\\8c\\4\\s1\\N (deg)",
1015 "\\8c\\4\\s2\\N (deg)",
1017 Xi1 = dihedral.j0[edChi1];
1018 Xi2 = dihedral.j0[edChi2];
1019 for (int j = 0; (j < nf); j++)
1021 fprintf(fp, "%10g %10g\n", gmx::c_rad2Deg * dih[Xi1][j], gmx::c_rad2Deg * dih[Xi2][j]);
1027 fprintf(stderr, "No chi1 & chi2 angle for %s\n", dihedral.name);
1033 static void print_transitions(const char* fn,
1035 gmx::ArrayRef<const t_dlist> dlist,
1037 const gmx_output_env_t* oenv)
1039 /* based on order_params below */
1042 /* must correspond with enum in gstat.h */
1043 const char* leg[edMax] = {
1044 "Phi", "Psi", "Omega", "Chi1", "Chi2", "Chi3", "Chi4", "Chi5", "Chi6",
1046 /* Print order parameters */
1047 fp = xvgropen(fn, "Dihedral Rotamer Transitions", "Residue", "Transitions/ns", oenv);
1048 xvgr_legend(fp, NONCHI + maxchi, leg, oenv);
1050 fprintf(fp, "%5s ", "#Res.");
1051 fprintf(fp, "%10s %10s %10s ", leg[edPhi], leg[edPsi], leg[edOmega]);
1052 for (int Xi = 0; Xi < maxchi; Xi++)
1054 fprintf(fp, "%10s ", leg[NONCHI + Xi]);
1058 for (const auto& dihedral : dlist)
1060 fprintf(fp, "%5d ", dihedral.resnr);
1061 for (int Dih = 0; (Dih < NONCHI + maxchi); Dih++)
1063 fprintf(fp, "%10.3f ", dihedral.ntr[Dih] / dt);
1065 /* fprintf(fp,"%12s\n",dihedral.name); this confuses xmgrace */
1071 static void order_params(FILE* log,
1074 gmx::ArrayRef<const t_dlist> dlist,
1084 const gmx_output_env_t* oenv)
1090 /* except for S2Min/Max, must correspond with enum in pp2shift.h:38 */
1091 const char* const_leg[2 + edMax] = { "S2Min", "S2Max", "Phi", "Psi", "Omega", "Chi1",
1092 "Chi2", "Chi3", "Chi4", "Chi5", "Chi6" };
1093 #define NLEG asize(leg)
1095 char* leg[2 + edMax];
1097 for (int i = 0; i < NLEG; i++)
1099 leg[i] = gmx_strdup(const_leg[i]);
1102 /* Print order parameters */
1103 fp = xvgropen(fn, "Dihedral Order Parameters", "Residue", "S2", oenv);
1104 xvgr_legend(fp, 2 + NONCHI + maxchi, const_leg, oenv);
1106 for (int Dih = 0; (Dih < edMax); Dih++)
1111 fprintf(fp, "%5s ", "#Res.");
1112 fprintf(fp, "%10s %10s ", leg[0], leg[1]);
1113 fprintf(fp, "%10s %10s %10s ", leg[2 + edPhi], leg[2 + edPsi], leg[2 + edOmega]);
1114 for (int Xi = 0; Xi < maxchi; Xi++)
1116 fprintf(fp, "%10s ", leg[2 + NONCHI + Xi]);
1120 for (const auto& dihedral : dlist)
1124 for (int Dih = 0; (Dih < NONCHI + maxchi); Dih++)
1126 if (dihedral.S2[Dih] != 0)
1128 if (dihedral.S2[Dih] > S2Max)
1130 S2Max = dihedral.S2[Dih];
1132 if (dihedral.S2[Dih] < S2Min)
1134 S2Min = dihedral.S2[Dih];
1137 if (dihedral.S2[Dih] > 0.8)
1142 fprintf(fp, "%5d ", dihedral.resnr);
1143 fprintf(fp, "%10.3f %10.3f ", S2Min, S2Max);
1144 for (int Dih = 0; (Dih < NONCHI + maxchi); Dih++)
1146 fprintf(fp, "%10.3f ", dihedral.S2[Dih]);
1149 /* fprintf(fp,"%12s\n",dihedral.name); this confuses xmgrace */
1153 if (nullptr != pdbfn)
1157 atoms->havePdbInfo = TRUE;
1159 if (nullptr == atoms->pdbinfo)
1161 snew(atoms->pdbinfo, atoms->nr);
1163 for (int i = 0; (i < atoms->nr); i++)
1165 atoms->pdbinfo[i].bfac = bfac_init;
1168 for (const auto& dihedral : dlist)
1170 atoms->pdbinfo[dihedral.atm.N].bfac = -dihedral.S2[0]; /* Phi */
1171 atoms->pdbinfo[dihedral.atm.H].bfac = -dihedral.S2[0]; /* Phi */
1172 atoms->pdbinfo[dihedral.atm.C].bfac = -dihedral.S2[1]; /* Psi */
1173 atoms->pdbinfo[dihedral.atm.O].bfac = -dihedral.S2[1]; /* Psi */
1174 for (int Xi = 0; (Xi < maxchi); Xi++) /* Chi's */
1176 if (dihedral.atm.Cn[Xi + 3] != -1)
1178 atoms->pdbinfo[dihedral.atm.Cn[Xi + 1]].bfac = -dihedral.S2[NONCHI + Xi];
1183 fp = gmx_ffopen(pdbfn, "w");
1184 fprintf(fp, "REMARK generated by g_chi\n");
1187 "B-factor field contains negative of dihedral order parameters\n");
1188 write_pdbfile(fp, nullptr, atoms, x, pbcType, box, ' ', 0, nullptr);
1189 x0 = y0 = z0 = 1000.0;
1190 for (int i = 0; (i < atoms->nr); i++)
1192 x0 = std::min(x0, x[i][XX]);
1193 y0 = std::min(y0, x[i][YY]);
1194 z0 = std::min(z0, x[i][ZZ]);
1196 x0 *= 10.0; /* nm -> angstrom */
1197 y0 *= 10.0; /* nm -> angstrom */
1198 z0 *= 10.0; /* nm -> angstrom */
1199 for (int i = 0; (i < 10); i++)
1201 gmx_fprintf_pdb_atomline(fp,
1202 PdbRecordType::Atom,
1220 fprintf(log, "Dihedrals with S2 > 0.8\n");
1221 fprintf(log, "Dihedral: ");
1224 fprintf(log, " Phi ");
1228 fprintf(log, " Psi ");
1232 for (int Xi = 0; (Xi < maxchi); Xi++)
1234 fprintf(log, " %s ", leg[2 + NONCHI + Xi]);
1237 fprintf(log, "\nNumber: ");
1240 fprintf(log, "%4d ", nh[0]);
1244 fprintf(log, "%4d ", nh[1]);
1248 for (int Xi = 0; (Xi < maxchi); Xi++)
1250 fprintf(log, "%4d ", nh[NONCHI + Xi]);
1255 for (int i = 0; i < NLEG; i++)
1261 int gmx_chi(int argc, char* argv[])
1263 const char* desc[] = {
1264 "[THISMODULE] computes [GRK]phi[grk], [GRK]psi[grk], [GRK]omega[grk],",
1265 "and [GRK]chi[grk] dihedrals for all your",
1266 "amino acid backbone and sidechains.",
1267 "It can compute dihedral angle as a function of time, and as",
1268 "histogram distributions.",
1269 "The distributions [TT](histo-(dihedral)(RESIDUE).xvg[tt]) are cumulative over all ",
1270 "residues of each type.[PAR]",
1271 "If option [TT]-corr[tt] is given, the program will",
1272 "calculate dihedral autocorrelation functions. The function used",
1273 "is C(t) = [CHEVRON][COS][GRK]chi[grk]([GRK]tau[grk])[cos] ",
1274 "[COS][GRK]chi[grk]([GRK]tau[grk]+t)[cos][chevron]. The use of cosines",
1275 "rather than angles themselves, resolves the problem of periodicity.",
1276 "(Van der Spoel & Berendsen (1997), Biophys. J. 72, 2032-2041).",
1277 "Separate files for each dihedral of each residue",
1278 "[TT](corr(dihedral)(RESIDUE)(nresnr).xvg[tt]) are output, as well as a",
1279 "file containing the information for all residues (argument of [TT]-corr[tt]).[PAR]",
1280 "With option [TT]-all[tt], the angles themselves as a function of time for",
1281 "each residue are printed to separate files [TT](dihedral)(RESIDUE)(nresnr).xvg[tt].",
1282 "These can be in radians or degrees.[PAR]",
1283 "A log file (argument [TT]-g[tt]) is also written. This contains",
1285 " * information about the number of residues of each type.",
1286 " * The NMR ^3J coupling constants from the Karplus equation.",
1287 " * a table for each residue of the number of transitions between ",
1288 " rotamers per nanosecond, and the order parameter S^2 of each dihedral.",
1289 " * a table for each residue of the rotamer occupancy.",
1291 "All rotamers are taken as 3-fold, except for [GRK]omega[grk] and [GRK]chi[grk] dihedrals",
1292 "to planar groups (i.e. [GRK]chi[grk][SUB]2[sub] of aromatics, Asp and Asn; ",
1293 "[GRK]chi[grk][SUB]3[sub] of Glu",
1294 "and Gln; and [GRK]chi[grk][SUB]4[sub] of Arg), which are 2-fold. \"rotamer 0\" means ",
1295 "that the dihedral was not in the core region of each rotamer. ",
1296 "The width of the core region can be set with [TT]-core_rotamer[tt][PAR]",
1298 "The S^2 order parameters are also output to an [REF].xvg[ref] file",
1299 "(argument [TT]-o[tt] ) and optionally as a [REF].pdb[ref] file with",
1300 "the S^2 values as B-factor (argument [TT]-p[tt]). ",
1301 "The total number of rotamer transitions per timestep",
1302 "(argument [TT]-ot[tt]), the number of transitions per rotamer",
1303 "(argument [TT]-rt[tt]), and the ^3J couplings (argument [TT]-jc[tt]), ",
1304 "can also be written to [REF].xvg[ref] files. Note that the analysis",
1305 "of rotamer transitions assumes that the supplied trajectory frames",
1306 "are equally spaced in time.[PAR]",
1308 "If [TT]-chi_prod[tt] is set (and [TT]-maxchi[tt] > 0), cumulative rotamers, e.g.",
1309 "1+9([GRK]chi[grk][SUB]1[sub]-1)+3([GRK]chi[grk][SUB]2[sub]-1)+",
1310 "([GRK]chi[grk][SUB]3[sub]-1) (if the residue has three 3-fold ",
1311 "dihedrals and [TT]-maxchi[tt] >= 3)",
1312 "are calculated. As before, if any dihedral is not in the core region,",
1313 "the rotamer is taken to be 0. The occupancies of these cumulative ",
1314 "rotamers (starting with rotamer 0) are written to the file",
1315 "that is the argument of [TT]-cp[tt], and if the [TT]-all[tt] flag",
1316 "is given, the rotamers as functions of time",
1317 "are written to [TT]chiproduct(RESIDUE)(nresnr).xvg[tt] ",
1318 "and their occupancies to [TT]histo-chiproduct(RESIDUE)(nresnr).xvg[tt].[PAR]",
1320 "The option [TT]-r[tt] generates a contour plot of the average [GRK]omega[grk] angle",
1321 "as a function of the [GRK]phi[grk] and [GRK]psi[grk] angles, that is, in a Ramachandran ",
1322 "plot the average [GRK]omega[grk] angle is plotted using color coding.",
1326 const char* bugs[] = {
1327 "Produces MANY output files (up to about 4 times the number of residues in the "
1328 "protein, twice that if autocorrelation functions are calculated). Typically "
1329 "several hundred files are output.",
1330 "[GRK]phi[grk] and [GRK]psi[grk] dihedrals are calculated in a "
1331 "non-standard way, using H-N-CA-C for [GRK]phi[grk] instead of "
1332 "C(-)-N-CA-C, and N-CA-C-O for [GRK]psi[grk] instead of N-CA-C-N(+). "
1333 "This causes (usually small) discrepancies with the output of other "
1334 "tools like [gmx-rama].",
1335 "[TT]-r0[tt] option does not work properly",
1336 "Rotamers with multiplicity 2 are printed in [TT]chi.log[tt] as if they had ",
1337 "multiplicity 3, with the 3rd (g(+)) always having probability 0"
1341 static int r0 = 1, ndeg = 1, maxchi = 2;
1342 static gmx_bool bAll = FALSE;
1343 static gmx_bool bPhi = FALSE, bPsi = FALSE, bOmega = FALSE;
1344 static real bfac_init = -1.0, bfac_max = 0;
1345 static const char* maxchistr[] = { nullptr, "0", "1", "2", "3", "4", "5", "6", nullptr };
1346 static gmx_bool bRama = FALSE, bShift = FALSE, bViol = FALSE, bRamOmega = FALSE;
1347 static gmx_bool bNormHisto = TRUE, bChiProduct = FALSE, bHChi = FALSE, bRAD = FALSE, bPBC = TRUE;
1348 static real core_frac = 0.5;
1350 { "-r0", FALSE, etINT, { &r0 }, "starting residue" },
1351 { "-phi", FALSE, etBOOL, { &bPhi }, "Output for [GRK]phi[grk] dihedral angles" },
1352 { "-psi", FALSE, etBOOL, { &bPsi }, "Output for [GRK]psi[grk] dihedral angles" },
1357 "Output for [GRK]omega[grk] dihedrals (peptide bonds)" },
1362 "Generate [GRK]phi[grk]/[GRK]psi[grk] and "
1363 "[GRK]chi[grk][SUB]1[sub]/[GRK]chi[grk][SUB]2[sub] Ramachandran plots" },
1368 "Write a file that gives 0 or 1 for violated Ramachandran angles" },
1369 { "-periodic", FALSE, etBOOL, { &bPBC }, "Print dihedral angles modulo 360 degrees" },
1370 { "-all", FALSE, etBOOL, { &bAll }, "Output separate files for every dihedral." },
1375 "in angle vs time files, use radians rather than degrees." },
1380 "Compute chemical shifts from [GRK]phi[grk]/[GRK]psi[grk] angles" },
1381 { "-binwidth", FALSE, etINT, { &ndeg }, "bin width for histograms (degrees)" },
1386 "only the central [TT]-core_rotamer[tt]\\*(360/multiplicity) belongs to each rotamer "
1387 "(the rest is assigned to rotamer 0)" },
1388 { "-maxchi", FALSE, etENUM, { maxchistr }, "calculate first ndih [GRK]chi[grk] dihedrals" },
1389 { "-normhisto", FALSE, etBOOL, { &bNormHisto }, "Normalize histograms" },
1394 "compute average omega as a function of [GRK]phi[grk]/[GRK]psi[grk] and plot it in an "
1395 "[REF].xpm[ref] plot" },
1400 "B-factor value for [REF].pdb[ref] file for atoms with no calculated dihedral order "
1406 "compute a single cumulative rotamer for each residue" },
1407 { "-HChi", FALSE, etBOOL, { &bHChi }, "Include dihedrals to sidechain hydrogens" },
1412 "Maximum B-factor on any of the atoms that make up a dihedral, for the dihedral angle to "
1413 "be considere in the statistics. Applies to database work where a number of X-Ray "
1414 "structures is analyzed. [TT]-bmax[tt] <= 0 means no limit." }
1423 gmx_bool bChi, bCorr, bSSHisto;
1424 gmx_bool bDo_rt, bDo_oh, bDo_ot, bDo_jc;
1425 real dt = 0, traj_t_ns;
1426 gmx_output_env_t* oenv;
1429 real **dih, *trans_frac, *aver_angle, *time;
1430 int ** chi_lookup, *multiplicity;
1432 t_filenm fnm[] = { { efSTX, "-s", nullptr, ffREAD },
1433 { efTRX, "-f", nullptr, ffREAD },
1434 { efXVG, "-o", "order", ffWRITE },
1435 { efPDB, "-p", "order", ffOPTWR },
1436 { efDAT, "-ss", "ssdump", ffOPTRD },
1437 { efXVG, "-jc", "Jcoupling", ffWRITE },
1438 { efXVG, "-corr", "dihcorr", ffOPTWR },
1439 { efLOG, "-g", "chi", ffWRITE },
1440 /* add two more arguments copying from g_angle */
1441 { efXVG, "-ot", "dihtrans", ffOPTWR },
1442 { efXVG, "-oh", "trhisto", ffOPTWR },
1443 { efXVG, "-rt", "restrans", ffOPTWR },
1444 { efXVG, "-cp", "chiprodhisto", ffOPTWR } };
1445 #define NFILE asize(fnm)
1450 ppa = add_acf_pargs(&npargs, pa);
1451 gmx::sfree_guard ppaGuard(ppa);
1452 if (!parse_common_args(
1453 &argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, npargs, ppa, asize(desc), desc, asize(bugs), bugs, &oenv))
1457 gmx::unique_cptr<gmx_output_env_t, output_env_done> oenvGuard(oenv);
1459 /* Handle result from enumerated type */
1460 sscanf(maxchistr[0], "%d", &maxchi);
1461 bChi = (maxchi > 0);
1463 log = gmx_ffopen(ftp2fn(efLOG, NFILE, fnm), "w");
1472 /* set some options */
1473 bDo_rt = (opt2bSet("-rt", NFILE, fnm));
1474 bDo_oh = (opt2bSet("-oh", NFILE, fnm));
1475 bDo_ot = (opt2bSet("-ot", NFILE, fnm));
1476 bDo_jc = (opt2bSet("-jc", NFILE, fnm));
1477 bCorr = (opt2bSet("-corr", NFILE, fnm));
1480 fprintf(stderr, "Will calculate autocorrelation\n");
1483 if (core_frac > 1.0)
1485 fprintf(stderr, "core_rotamer fraction > 1.0 ; will use 1.0\n");
1488 if (core_frac < 0.0)
1490 fprintf(stderr, "core_rotamer fraction < 0.0 ; will use 0.0\n");
1494 if (maxchi > MAXCHI)
1496 fprintf(stderr, "Will only calculate first %d Chi dihedrals instead of %d.\n", MAXCHI, maxchi);
1499 bSSHisto = ftp2bSet(efDAT, NFILE, fnm);
1502 /* Find the chi angles using atoms struct and a list of amino acids */
1506 open_symtab(&symtab);
1507 gmx::unique_cptr<t_symtab, done_symtab> symtabGuard(&symtab);
1508 readConfAndAtoms(ftp2fn(efSTX, NFILE, fnm), &symtab, &name, &atoms, &pbcType, &x, nullptr, box);
1509 gmx::sfree_guard nameGuard(name);
1510 gmx::sfree_guard xGuard(x);
1511 gmx::unique_cptr<t_atoms, done_atom> atomsGuard(&atoms);
1512 if (atoms.pdbinfo == nullptr)
1514 snew(atoms.pdbinfo, atoms.nr);
1516 fprintf(log, "Title: %s\n", name);
1519 std::vector<t_dlist> dlist = mk_dlist(log, &atoms, bPhi, bPsi, bChi, bHChi, maxchi, r0, &rt);
1520 fprintf(stderr, "%zu residues with dihedrals found\n", dlist.size());
1524 gmx_fatal(FARGS, "No dihedrals in your structure!\n");
1527 /* Make a linear index for reading all dihedral atoms (4 per dihedral). */
1528 std::vector<int> index = make_chi_ind(dlist);
1529 int ndih = index.size() / 4; // 4 atoms per dihedral
1530 fprintf(stderr, "%d dihedrals found\n", ndih);
1534 /* COMPUTE ALL DIHEDRALS! */
1535 read_ang_dih(ftp2fn(efTRX, NFILE, fnm),
1550 gmx::sfree_guard timeGuard(time);
1551 gmx::sfree_guard transFracGuard(trans_frac);
1552 gmx::sfree_guard averAngleGuard(aver_angle);
1554 dt = (time[nf - 1] - time[0]) / (nf - 1); /* might want this for corr or n. transit*/
1559 gmx_fatal(FARGS, "Need at least 2 frames for correlation");
1563 /* put angles in -M_PI to M_PI ! and correct phase factor for phi and psi
1564 * pass nactdih instead of ndih to low_ana_dih_trans
1565 * to prevent accessing off end of arrays when maxchi < 5 or 6. */
1566 nactdih = reset_em_all(dlist, nf, dih, maxchi);
1570 dump_em_all(dlist, nf, time, dih, maxchi, bPhi, bPsi, bChi, bOmega, bRAD, oenv);
1573 /* Histogramming & J coupling constants & calc of S2 order params */
1588 ftp2fn(efDAT, NFILE, fnm),
1592 opt2fn("-jc", NFILE, fnm),
1597 * added multiplicity */
1599 snew(multiplicity, ndih);
1600 gmx::sfree_guard multiplicityGuard(multiplicity);
1601 mk_multiplicity_lookup(multiplicity, maxchi, dlist, ndih);
1603 std::strcpy(grpname, "All residues, ");
1606 std::strcat(grpname, "Phi ");
1610 std::strcat(grpname, "Psi ");
1614 std::strcat(grpname, "Omega ");
1618 std::strcat(grpname, "Chi 1-");
1619 sprintf(grpname + std::strlen(grpname), "%i", maxchi);
1623 low_ana_dih_trans(bDo_ot,
1624 opt2fn("-ot", NFILE, fnm),
1626 opt2fn("-oh", NFILE, fnm),
1639 /* Order parameters */
1641 opt2fn("-o", NFILE, fnm),
1644 ftp2fn_null(efPDB, NFILE, fnm),
1655 /* Print ramachandran maps! */
1658 do_rama(nf, dlist, dih, bViol, bRamOmega, oenv);
1663 do_pp2shifts(log, nf, dlist, dih);
1666 /* rprint S^2, transitions, and rotamer occupancies to log */
1667 traj_t_ns = 0.001 * (time[nf - 1] - time[0]);
1668 pr_dlist(log, dlist, traj_t_ns, edPrintST, bPhi, bPsi, bChi, bOmega, maxchi);
1669 pr_dlist(log, dlist, traj_t_ns, edPrintRO, bPhi, bPsi, bChi, bOmega, maxchi);
1671 /* transitions to xvg */
1674 print_transitions(opt2fn("-rt", NFILE, fnm), maxchi, dlist, traj_t_ns, oenv);
1677 /* chi_product trajectories (ie one "rotamer number" for each residue) */
1678 if (bChiProduct && bChi)
1680 snew(chi_lookup, dlist.size());
1681 for (size_t i = 0; i < dlist.size(); i++)
1683 snew(chi_lookup[i], maxchi);
1685 mk_chi_lookup(chi_lookup, maxchi, dlist);
1687 get_chi_product_traj(dih,
1698 opt2fn("-cp", NFILE, fnm),
1701 for (size_t i = 0; i < dlist.size(); i++)
1703 sfree(chi_lookup[i]);
1708 /* Correlation comes last because it messes up the angles */
1711 do_dihcorr(opt2fn("-corr", NFILE, fnm), nf, ndih, dih, dt, dlist, time, maxchi, bPhi, bPsi, bChi, bOmega, oenv);
1715 do_view(oenv, opt2fn("-o", NFILE, fnm), "-nxy");
1716 do_view(oenv, opt2fn("-jc", NFILE, fnm), "-nxy");
1719 do_view(oenv, opt2fn("-corr", NFILE, fnm), "-nxy");
1722 for (int i = 0; (i < ndih); i++)