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-2008, The GROMACS development team.
6 * Copyright (c) 2013,2014,2015,2016,2017,2018,2019, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
48 #include "gromacs/commandline/pargs.h"
49 #include "gromacs/commandline/viewit.h"
50 #include "gromacs/correlationfunctions/autocorr.h"
51 #include "gromacs/correlationfunctions/crosscorr.h"
52 #include "gromacs/correlationfunctions/expfit.h"
53 #include "gromacs/correlationfunctions/integrate.h"
54 #include "gromacs/fileio/matio.h"
55 #include "gromacs/fileio/tpxio.h"
56 #include "gromacs/fileio/trxio.h"
57 #include "gromacs/fileio/xvgr.h"
58 #include "gromacs/gmxana/gmx_ana.h"
59 #include "gromacs/gmxana/gstat.h"
60 #include "gromacs/math/functions.h"
61 #include "gromacs/math/units.h"
62 #include "gromacs/math/vec.h"
63 #include "gromacs/mdtypes/inputrec.h"
64 #include "gromacs/pbcutil/pbc.h"
65 #include "gromacs/topology/ifunc.h"
66 #include "gromacs/topology/index.h"
67 #include "gromacs/topology/topology.h"
68 #include "gromacs/utility/arraysize.h"
69 #include "gromacs/utility/cstringutil.h"
70 #include "gromacs/utility/exceptions.h"
71 #include "gromacs/utility/fatalerror.h"
72 #include "gromacs/utility/futil.h"
73 #include "gromacs/utility/gmxomp.h"
74 #include "gromacs/utility/pleasecite.h"
75 #include "gromacs/utility/programcontext.h"
76 #include "gromacs/utility/smalloc.h"
77 #include "gromacs/utility/snprintf.h"
80 typedef int t_hx[max_hx];
81 #define NRHXTYPES max_hx
82 static const char* hxtypenames[NRHXTYPES] = { "n-n", "n-n+1", "n-n+2", "n-n+3",
83 "n-n+4", "n-n+5", "n-n>6" };
86 static const int NOTSET = -49297;
88 /* -----------------------------------------*/
105 static const unsigned char c_acceptorMask = (1 << 0);
106 static const unsigned char c_donorMask = (1 << 1);
107 static const unsigned char c_inGroupMask = (1 << 2);
110 static const char* grpnames[grNR] = { "0", "1", "I" };
112 static gmx_bool bDebug = FALSE;
115 #define HB_YES 1 << 0
116 #define HB_INS 1 << 1
117 #define HB_YESINS (HB_YES | HB_INS)
118 #define HB_NR (1 << 2)
121 #define ISHB(h) ((h)&2)
122 #define ISDIST(h) ((h)&1)
123 #define ISDIST2(h) ((h)&4)
124 #define ISACC(h) ((h)&c_acceptorMask)
125 #define ISDON(h) ((h)&c_donorMask)
126 #define ISINGRP(h) ((h)&c_inGroupMask)
141 typedef int t_icell[grNR];
142 typedef int h_id[MAXHYDRO];
146 int history[MAXHYDRO];
147 /* Has this hbond existed ever? If so as hbDist or hbHB or both.
148 * Result is stored as a bitmap (1 = hbDist) || (2 = hbHB)
150 /* Bitmask array which tells whether a hbond is present
151 * at a given time. Either of these may be NULL
153 int n0; /* First frame a HB was found */
154 int nframes, maxframes; /* Amount of frames in this hbond */
157 /* See Xu and Berne, JPCB 105 (2001), p. 11929. We define the
158 * function g(t) = [1-h(t)] H(t) where H(t) is one when the donor-
159 * acceptor distance is less than the user-specified distance (typically
167 int* acc; /* Atom numbers of the acceptors */
168 int* grp; /* Group index */
169 int* aptr; /* Map atom number to acceptor index */
175 int* don; /* Atom numbers of the donors */
176 int* grp; /* Group index */
177 int* dptr; /* Map atom number to donor index */
178 int* nhydro; /* Number of hydrogens for each donor */
179 h_id* hydro; /* The atom numbers of the hydrogens */
180 h_id* nhbonds; /* The number of HBs per H at current */
185 gmx_bool bHBmap, bDAnr;
187 /* The following arrays are nframes long */
188 int nframes, max_frames, maxhydro;
194 /* These structures are initialized from the topology at start up */
197 /* This holds a matrix with all possible hydrogen bonds */
202 /* Changed argument 'bMerge' into 'oneHB' below,
203 * since -contact should cause maxhydro to be 1,
205 * - Erik Marklund May 29, 2006
208 static t_hbdata* mk_hbdata(gmx_bool bHBmap, gmx_bool bDAnr, gmx_bool oneHB)
213 hb->wordlen = 8 * sizeof(unsigned int);
222 hb->maxhydro = MAXHYDRO;
227 static void mk_hbmap(t_hbdata* hb)
231 snew(hb->hbmap, hb->d.nrd);
232 for (i = 0; (i < hb->d.nrd); i++)
234 snew(hb->hbmap[i], hb->a.nra);
235 if (hb->hbmap[i] == nullptr)
237 gmx_fatal(FARGS, "Could not allocate enough memory for hbmap");
239 for (j = 0; j < hb->a.nra; j++)
241 hb->hbmap[i][j] = nullptr;
246 static void add_frames(t_hbdata* hb, int nframes)
248 if (nframes >= hb->max_frames)
250 hb->max_frames += 4096;
251 srenew(hb->time, hb->max_frames);
252 srenew(hb->nhb, hb->max_frames);
253 srenew(hb->ndist, hb->max_frames);
254 srenew(hb->n_bound, hb->max_frames);
255 srenew(hb->nhx, hb->max_frames);
258 srenew(hb->danr, hb->max_frames);
261 hb->nframes = nframes;
264 #define OFFSET(frame) ((frame) / 32)
265 #define MASK(frame) (1 << ((frame) % 32))
267 static void _set_hb(unsigned int hbexist[], unsigned int frame, gmx_bool bValue)
271 hbexist[OFFSET(frame)] |= MASK(frame);
275 hbexist[OFFSET(frame)] &= ~MASK(frame);
279 static gmx_bool is_hb(const unsigned int hbexist[], int frame)
281 return (hbexist[OFFSET(frame)] & MASK(frame)) != 0;
284 static void set_hb(t_hbdata* hb, int id, int ih, int ia, int frame, int ihb)
286 unsigned int* ghptr = nullptr;
290 ghptr = hb->hbmap[id][ia]->h[ih];
292 else if (ihb == hbDist)
294 ghptr = hb->hbmap[id][ia]->g[ih];
298 gmx_fatal(FARGS, "Incomprehensible iValue %d in set_hb", ihb);
301 _set_hb(ghptr, frame - hb->hbmap[id][ia]->n0, TRUE);
304 static void add_ff(t_hbdata* hbd, int id, int h, int ia, int frame, int ihb)
307 t_hbond* hb = hbd->hbmap[id][ia];
308 int maxhydro = std::min(hbd->maxhydro, hbd->d.nhydro[id]);
309 int wlen = hbd->wordlen;
310 int delta = 32 * wlen;
315 hb->maxframes = delta;
316 for (i = 0; (i < maxhydro); i++)
318 snew(hb->h[i], hb->maxframes / wlen);
319 snew(hb->g[i], hb->maxframes / wlen);
324 hb->nframes = frame - hb->n0;
325 /* We need a while loop here because hbonds may be returning
328 while (hb->nframes >= hb->maxframes)
330 n = hb->maxframes + delta;
331 for (i = 0; (i < maxhydro); i++)
333 srenew(hb->h[i], n / wlen);
334 srenew(hb->g[i], n / wlen);
335 for (j = hb->maxframes / wlen; (j < n / wlen); j++)
347 set_hb(hbd, id, h, ia, frame, ihb);
351 static void inc_nhbonds(t_donors* ddd, int d, int h)
354 int dptr = ddd->dptr[d];
356 for (j = 0; (j < ddd->nhydro[dptr]); j++)
358 if (ddd->hydro[dptr][j] == h)
360 ddd->nhbonds[dptr][j]++;
364 if (j == ddd->nhydro[dptr])
366 gmx_fatal(FARGS, "No such hydrogen %d on donor %d\n", h + 1, d + 1);
370 static int _acceptor_index(t_acceptors* a, int grp, int i, const char* file, int line)
374 if (a->grp[ai] != grp)
378 fprintf(debug, "Acc. group inconsist.. grp[%d] = %d, grp = %d (%s, %d)\n", ai,
379 a->grp[ai], grp, file, line);
388 #define acceptor_index(a, grp, i) _acceptor_index(a, grp, i, __FILE__, __LINE__)
390 static int _donor_index(t_donors* d, int grp, int i, const char* file, int line)
399 if (d->grp[di] != grp)
403 fprintf(debug, "Don. group inconsist.. grp[%d] = %d, grp = %d (%s, %d)\n", di,
404 d->grp[di], grp, file, line);
413 #define donor_index(d, grp, i) _donor_index(d, grp, i, __FILE__, __LINE__)
415 static gmx_bool isInterchangable(t_hbdata* hb, int d, int a, int grpa, int grpd)
417 /* g_hbond doesn't allow overlapping groups */
422 return donor_index(&hb->d, grpd, a) != NOTSET && acceptor_index(&hb->a, grpa, d) != NOTSET;
427 add_hbond(t_hbdata* hb, int d, int a, int h, int grpd, int grpa, int frame, gmx_bool bMerge, int ihb, gmx_bool bContact)
430 gmx_bool daSwap = FALSE;
432 if ((id = hb->d.dptr[d]) == NOTSET)
434 gmx_fatal(FARGS, "No donor atom %d", d + 1);
436 else if (grpd != hb->d.grp[id])
438 gmx_fatal(FARGS, "Inconsistent donor groups, %d instead of %d, atom %d", grpd,
439 hb->d.grp[id], d + 1);
441 if ((ia = hb->a.aptr[a]) == NOTSET)
443 gmx_fatal(FARGS, "No acceptor atom %d", a + 1);
445 else if (grpa != hb->a.grp[ia])
447 gmx_fatal(FARGS, "Inconsistent acceptor groups, %d instead of %d, atom %d", grpa,
448 hb->a.grp[ia], a + 1);
454 if (isInterchangable(hb, d, a, grpd, grpa) && d > a)
455 /* Then swap identity so that the id of d is lower then that of a.
457 * This should really be redundant by now, as is_hbond() now ought to return
458 * hbNo in the cases where this conditional is TRUE. */
465 /* Now repeat donor/acc check. */
466 if ((id = hb->d.dptr[d]) == NOTSET)
468 gmx_fatal(FARGS, "No donor atom %d", d + 1);
470 else if (grpd != hb->d.grp[id])
472 gmx_fatal(FARGS, "Inconsistent donor groups, %d instead of %d, atom %d", grpd,
473 hb->d.grp[id], d + 1);
475 if ((ia = hb->a.aptr[a]) == NOTSET)
477 gmx_fatal(FARGS, "No acceptor atom %d", a + 1);
479 else if (grpa != hb->a.grp[ia])
481 gmx_fatal(FARGS, "Inconsistent acceptor groups, %d instead of %d, atom %d", grpa,
482 hb->a.grp[ia], a + 1);
489 /* Loop over hydrogens to find which hydrogen is in this particular HB */
490 if ((ihb == hbHB) && !bMerge && !bContact)
492 for (k = 0; (k < hb->d.nhydro[id]); k++)
494 if (hb->d.hydro[id][k] == h)
499 if (k == hb->d.nhydro[id])
501 gmx_fatal(FARGS, "Donor %d does not have hydrogen %d (a = %d)", d + 1, h + 1, a + 1);
516 if (hb->hbmap[id][ia] == nullptr)
518 snew(hb->hbmap[id][ia], 1);
519 snew(hb->hbmap[id][ia]->h, hb->maxhydro);
520 snew(hb->hbmap[id][ia]->g, hb->maxhydro);
522 add_ff(hb, id, k, ia, frame, ihb);
524 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
528 /* Strange construction with frame >=0 is a relic from old code
529 * for selected hbond analysis. It may be necessary again if that
530 * is made to work again.
534 hh = hb->hbmap[id][ia]->history[k];
540 hb->hbmap[id][ia]->history[k] = hh | 2;
551 hb->hbmap[id][ia]->history[k] = hh | 1;
575 if (bMerge && daSwap)
577 h = hb->d.hydro[id][0];
579 /* Increment number if HBonds per H */
580 if (ihb == hbHB && !bContact)
582 inc_nhbonds(&(hb->d), d, h);
586 static char* mkatomname(const t_atoms* atoms, int i)
591 rnr = atoms->atom[i].resind;
592 sprintf(buf, "%4s%d%-4s", *atoms->resinfo[rnr].name, atoms->resinfo[rnr].nr, *atoms->atomname[i]);
597 static void gen_datable(int* index, int isize, unsigned char* datable, int natoms)
599 /* Generates table of all atoms and sets the ingroup bit for atoms in index[] */
602 for (i = 0; i < isize; i++)
604 if (index[i] >= natoms)
606 gmx_fatal(FARGS, "Atom has index %d larger than number of atoms %d.", index[i], natoms);
608 datable[index[i]] |= c_inGroupMask;
612 static void clear_datable_grp(unsigned char* datable, int size)
614 /* Clears group information from the table */
618 for (i = 0; i < size; i++)
620 datable[i] &= ~c_inGroupMask;
625 static void add_acc(t_acceptors* a, int ia, int grp)
627 if (a->nra >= a->max_nra)
630 srenew(a->acc, a->max_nra);
631 srenew(a->grp, a->max_nra);
633 a->grp[a->nra] = grp;
634 a->acc[a->nra++] = ia;
637 static void search_acceptors(const t_topology* top,
645 unsigned char* datable)
651 for (i = 0; (i < isize); i++)
655 || (((*top->atoms.atomname[n])[0] == 'O')
656 || (bNitAcc && ((*top->atoms.atomname[n])[0] == 'N'))))
657 && ISINGRP(datable[n]))
659 datable[n] |= c_acceptorMask;
664 snew(a->aptr, top->atoms.nr);
665 for (i = 0; (i < top->atoms.nr); i++)
669 for (i = 0; (i < a->nra); i++)
671 a->aptr[a->acc[i]] = i;
675 static void add_h2d(int id, int ih, t_donors* ddd)
679 for (i = 0; (i < ddd->nhydro[id]); i++)
681 if (ddd->hydro[id][i] == ih)
683 printf("Hm. This isn't the first time I found this donor (%d,%d)\n", ddd->don[id], ih);
687 if (i == ddd->nhydro[id])
689 if (ddd->nhydro[id] >= MAXHYDRO)
691 gmx_fatal(FARGS, "Donor %d has more than %d hydrogens!", ddd->don[id], MAXHYDRO);
693 ddd->hydro[id][i] = ih;
698 static void add_dh(t_donors* ddd, int id, int ih, int grp, const unsigned char* datable)
702 if (!datable || ISDON(datable[id]))
704 if (ddd->dptr[id] == NOTSET) /* New donor */
716 if (ddd->nrd >= ddd->max_nrd)
719 srenew(ddd->don, ddd->max_nrd);
720 srenew(ddd->nhydro, ddd->max_nrd);
721 srenew(ddd->hydro, ddd->max_nrd);
722 srenew(ddd->nhbonds, ddd->max_nrd);
723 srenew(ddd->grp, ddd->max_nrd);
725 ddd->don[ddd->nrd] = id;
726 ddd->nhydro[ddd->nrd] = 0;
727 ddd->grp[ddd->nrd] = grp;
738 printf("Warning: Atom %d is not in the d/a-table!\n", id);
742 static void search_donors(const t_topology* top,
749 unsigned char* datable)
752 t_functype func_type;
757 snew(ddd->dptr, top->atoms.nr);
758 for (i = 0; (i < top->atoms.nr); i++)
760 ddd->dptr[i] = NOTSET;
768 for (i = 0; (i < isize); i++)
770 datable[index[i]] |= c_donorMask;
771 add_dh(ddd, index[i], -1, grp, datable);
777 for (func_type = 0; (func_type < F_NRE); func_type++)
779 const t_ilist* interaction = &(top->idef.il[func_type]);
780 if (func_type == F_POSRES || func_type == F_FBPOSRES)
782 /* The ilist looks strange for posre. Bug in grompp?
783 * We don't need posre interactions for hbonds anyway.*/
786 for (i = 0; i < interaction->nr;
787 i += interaction_function[top->idef.functype[interaction->iatoms[i]]].nratoms + 1)
790 if (func_type != top->idef.functype[interaction->iatoms[i]])
792 fprintf(stderr, "Error in func_type %s", interaction_function[func_type].longname);
796 /* check out this functype */
797 if (func_type == F_SETTLE)
799 nr1 = interaction->iatoms[i + 1];
800 nr2 = interaction->iatoms[i + 2];
801 nr3 = interaction->iatoms[i + 3];
803 if (ISINGRP(datable[nr1]))
805 if (ISINGRP(datable[nr2]))
807 datable[nr1] |= c_donorMask;
808 add_dh(ddd, nr1, nr1 + 1, grp, datable);
810 if (ISINGRP(datable[nr3]))
812 datable[nr1] |= c_donorMask;
813 add_dh(ddd, nr1, nr1 + 2, grp, datable);
817 else if (IS_CHEMBOND(func_type))
819 for (j = 0; j < 2; j++)
821 nr1 = interaction->iatoms[i + 1 + j];
822 nr2 = interaction->iatoms[i + 2 - j];
823 if ((*top->atoms.atomname[nr1][0] == 'H')
824 && ((*top->atoms.atomname[nr2][0] == 'O') || (*top->atoms.atomname[nr2][0] == 'N'))
825 && ISINGRP(datable[nr1]) && ISINGRP(datable[nr2]))
827 datable[nr2] |= c_donorMask;
828 add_dh(ddd, nr2, nr1, grp, datable);
835 for (func_type = 0; func_type < F_NRE; func_type++)
837 interaction = &top->idef.il[func_type];
838 for (i = 0; i < interaction->nr;
839 i += interaction_function[top->idef.functype[interaction->iatoms[i]]].nratoms + 1)
842 if (func_type != top->idef.functype[interaction->iatoms[i]])
844 gmx_incons("function type in search_donors");
847 if (interaction_function[func_type].flags & IF_VSITE)
849 nr1 = interaction->iatoms[i + 1];
850 if (*top->atoms.atomname[nr1][0] == 'H')
854 while (!stop && (*top->atoms.atomname[nr2][0] == 'H'))
866 && ((*top->atoms.atomname[nr2][0] == 'O') || (*top->atoms.atomname[nr2][0] == 'N'))
867 && ISINGRP(datable[nr1]) && ISINGRP(datable[nr2]))
869 datable[nr2] |= c_donorMask;
870 add_dh(ddd, nr2, nr1, grp, datable);
880 static t_gridcell*** init_grid(gmx_bool bBox, rvec box[], real rcut, ivec ngrid)
887 for (i = 0; i < DIM; i++)
889 ngrid[i] = static_cast<int>(box[i][i] / (1.2 * rcut));
893 if (!bBox || (ngrid[XX] < 3) || (ngrid[YY] < 3) || (ngrid[ZZ] < 3))
895 for (i = 0; i < DIM; i++)
902 printf("\nWill do grid-search on %dx%dx%d grid, rcut=%3.8f\n", ngrid[XX], ngrid[YY],
905 if (((ngrid[XX] * ngrid[YY] * ngrid[ZZ]) * sizeof(grid)) > INT_MAX)
908 "Failed to allocate memory for %d x %d x %d grid points, which is larger than "
909 "the maximum of %zu. "
910 "You are likely either using a box that is too large (box dimensions are %3.8f "
911 "nm x%3.8f nm x%3.8f nm) or a cutoff (%3.8f nm) that is too small.",
912 ngrid[XX], ngrid[YY], ngrid[ZZ], INT_MAX / sizeof(grid), box[XX][XX], box[YY][YY],
915 snew(grid, ngrid[ZZ]);
916 for (z = 0; z < ngrid[ZZ]; z++)
918 snew((grid)[z], ngrid[YY]);
919 for (y = 0; y < ngrid[YY]; y++)
921 snew((grid)[z][y], ngrid[XX]);
927 static void reset_nhbonds(t_donors* ddd)
931 for (i = 0; (i < ddd->nrd); i++)
933 for (j = 0; (j < MAXHH); j++)
935 ddd->nhbonds[i][j] = 0;
940 static void pbc_correct_gem(rvec dx, matrix box, const rvec hbox);
941 static void pbc_in_gridbox(rvec dx, matrix box);
943 static void build_grid(t_hbdata* hb,
954 int i, m, gr, xi, yi, zi, nr;
957 rvec invdelta, dshell;
959 gmx_bool bDoRshell, bInShell;
964 bDoRshell = (rshell > 0);
965 rshell2 = gmx::square(rshell);
969 if (debug && bDebug) \
970 fprintf(debug, "build_grid, line %d, %s = %d\n", __LINE__, #x, x)
972 for (m = 0; m < DIM; m++)
974 hbox[m] = box[m][m] * 0.5;
977 invdelta[m] = ngrid[m] / box[m][m];
978 if (1 / invdelta[m] < rcut)
981 "Your computational box has shrunk too much.\n"
982 "%s can not handle this situation, sorry.\n",
983 gmx::getProgramContext().displayName());
995 /* resetting atom counts */
996 for (gr = 0; (gr < grNR); gr++)
998 for (zi = 0; zi < ngrid[ZZ]; zi++)
1000 for (yi = 0; yi < ngrid[YY]; yi++)
1002 for (xi = 0; xi < ngrid[XX]; xi++)
1004 grid[zi][yi][xi].d[gr].nr = 0;
1005 grid[zi][yi][xi].a[gr].nr = 0;
1011 /* put atoms in grid cells */
1012 for (int acc = 0; acc < 2; acc++)
1025 for (i = 0; (i < nr); i++)
1027 /* check if we are inside the shell */
1028 /* if bDoRshell=FALSE then bInShell=TRUE always */
1033 rvec_sub(x[ad[i]], xshell, dshell);
1036 gmx_bool bDone = FALSE;
1040 for (m = DIM - 1; m >= 0 && bInShell; m--)
1042 if (dshell[m] < -hbox[m])
1045 rvec_inc(dshell, box[m]);
1047 if (dshell[m] >= hbox[m])
1050 dshell[m] -= 2 * hbox[m];
1054 for (m = DIM - 1; m >= 0 && bInShell; m--)
1056 /* if we're outside the cube, we're outside the sphere also! */
1057 if ((dshell[m] > rshell) || (-dshell[m] > rshell))
1063 /* if we're inside the cube, check if we're inside the sphere */
1066 bInShell = norm2(dshell) < rshell2;
1074 pbc_in_gridbox(x[ad[i]], box);
1076 for (m = DIM - 1; m >= 0; m--)
1077 { /* determine grid index of atom */
1078 grididx[m] = static_cast<int>(x[ad[i]][m] * invdelta[m]);
1079 grididx[m] = (grididx[m] + ngrid[m]) % ngrid[m];
1086 range_check(gx, 0, ngrid[XX]);
1087 range_check(gy, 0, ngrid[YY]);
1088 range_check(gz, 0, ngrid[ZZ]);
1092 /* add atom to grid cell */
1095 newgrid = &(grid[gz][gy][gx].a[gr]);
1099 newgrid = &(grid[gz][gy][gx].d[gr]);
1101 if (newgrid->nr >= newgrid->maxnr)
1103 newgrid->maxnr += 10;
1104 DBB(newgrid->maxnr);
1105 srenew(newgrid->atoms, newgrid->maxnr);
1108 newgrid->atoms[newgrid->nr] = ad[i];
1116 static void count_da_grid(const ivec ngrid, t_gridcell*** grid, t_icell danr)
1120 for (gr = 0; (gr < grNR); gr++)
1123 for (zi = 0; zi < ngrid[ZZ]; zi++)
1125 for (yi = 0; yi < ngrid[YY]; yi++)
1127 for (xi = 0; xi < ngrid[XX]; xi++)
1129 danr[gr] += grid[zi][yi][xi].d[gr].nr;
1137 * Without a box, the grid is 1x1x1, so all loops are 1 long.
1138 * With a rectangular box (bTric==FALSE) all loops are 3 long.
1139 * With a triclinic box all loops are 3 long, except when a cell is
1140 * located next to one of the box edges which is not parallel to the
1141 * x/y-plane, in that case all cells in a line or layer are searched.
1142 * This could be implemented slightly more efficient, but the code
1143 * would get much more complicated.
1145 static inline int grid_loop_begin(int n, int x, gmx_bool bTric, gmx_bool bEdge)
1147 return ((n == 1) ? x : bTric && bEdge ? 0 : (x - 1));
1149 static inline int grid_loop_end(int n, int x, gmx_bool bTric, gmx_bool bEdge)
1151 return ((n == 1) ? x : bTric && bEdge ? (n - 1) : (x + 1));
1153 static inline int grid_mod(int j, int n)
1155 return (j + n) % (n);
1158 static void dump_grid(FILE* fp, ivec ngrid, t_gridcell*** grid)
1160 int gr, x, y, z, sum[grNR];
1162 fprintf(fp, "grid %dx%dx%d\n", ngrid[XX], ngrid[YY], ngrid[ZZ]);
1163 for (gr = 0; gr < grNR; gr++)
1166 fprintf(fp, "GROUP %d (%s)\n", gr, grpnames[gr]);
1167 for (z = 0; z < ngrid[ZZ]; z += 2)
1169 fprintf(fp, "Z=%d,%d\n", z, z + 1);
1170 for (y = 0; y < ngrid[YY]; y++)
1172 for (x = 0; x < ngrid[XX]; x++)
1174 fprintf(fp, "%3d", grid[x][y][z].d[gr].nr);
1175 sum[gr] += grid[z][y][x].d[gr].nr;
1176 fprintf(fp, "%3d", grid[x][y][z].a[gr].nr);
1177 sum[gr] += grid[z][y][x].a[gr].nr;
1180 if ((z + 1) < ngrid[ZZ])
1182 for (x = 0; x < ngrid[XX]; x++)
1184 fprintf(fp, "%3d", grid[z + 1][y][x].d[gr].nr);
1185 sum[gr] += grid[z + 1][y][x].d[gr].nr;
1186 fprintf(fp, "%3d", grid[z + 1][y][x].a[gr].nr);
1187 sum[gr] += grid[z + 1][y][x].a[gr].nr;
1194 fprintf(fp, "TOTALS:");
1195 for (gr = 0; gr < grNR; gr++)
1197 fprintf(fp, " %d=%d", gr, sum[gr]);
1202 /* New GMX record! 5 * in a row. Congratulations!
1203 * Sorry, only four left.
1205 static void free_grid(const ivec ngrid, t_gridcell**** grid)
1208 t_gridcell*** g = *grid;
1210 for (z = 0; z < ngrid[ZZ]; z++)
1212 for (y = 0; y < ngrid[YY]; y++)
1222 static void pbc_correct_gem(rvec dx, matrix box, const rvec hbox)
1225 gmx_bool bDone = FALSE;
1229 for (m = DIM - 1; m >= 0; m--)
1231 if (dx[m] < -hbox[m])
1234 rvec_inc(dx, box[m]);
1236 if (dx[m] >= hbox[m])
1239 rvec_dec(dx, box[m]);
1245 static void pbc_in_gridbox(rvec dx, matrix box)
1248 gmx_bool bDone = FALSE;
1252 for (m = DIM - 1; m >= 0; m--)
1257 rvec_inc(dx, box[m]);
1259 if (dx[m] >= box[m][m])
1262 rvec_dec(dx, box[m]);
1268 /* Added argument r2cut, changed contact and implemented
1269 * use of second cut-off.
1270 * - Erik Marklund, June 29, 2006
1272 static int is_hbond(t_hbdata* hb,
1292 rvec r_da, r_ha, r_dh;
1293 real rc2, r2c2, rda2, rha2, ca;
1294 gmx_bool HAinrange = FALSE; /* If !bDA. Needed for returning hbDist in a correct way. */
1295 gmx_bool daSwap = FALSE;
1302 if (((id = donor_index(&hb->d, grpd, d)) == NOTSET) || (acceptor_index(&hb->a, grpa, a) == NOTSET))
1308 r2c2 = r2cut * r2cut;
1310 rvec_sub(x[d], x[a], r_da);
1311 /* Insert projection code here */
1313 if (bMerge && d > a && isInterchangable(hb, d, a, grpd, grpa))
1315 /* Then this hbond/contact will be found again, or it has already been found. */
1321 && isInterchangable(hb, d, a, grpd, grpa)) /* acceptor is also a donor and vice versa? */
1322 { /* return hbNo; */
1323 daSwap = TRUE; /* If so, then their history should be filed with donor and acceptor swapped. */
1325 pbc_correct_gem(r_da, box, hbox);
1327 rda2 = iprod(r_da, r_da);
1331 if (daSwap && grpa == grpd)
1339 else if (rda2 < r2c2)
1350 if (bDA && (rda2 > rc2))
1355 for (h = 0; (h < hb->d.nhydro[id]); h++)
1357 hh = hb->d.hydro[id][h];
1361 rvec_sub(x[hh], x[a], r_ha);
1364 pbc_correct_gem(r_ha, box, hbox);
1366 rha2 = iprod(r_ha, r_ha);
1369 if (bDA || (rha2 <= rc2))
1371 rvec_sub(x[d], x[hh], r_dh);
1374 pbc_correct_gem(r_dh, box, hbox);
1381 ca = cos_angle(r_dh, r_da);
1382 /* if angle is smaller, cos is larger */
1386 *d_ha = std::sqrt(bDA ? rda2 : rha2);
1387 *ang = std::acos(ca);
1392 if (bDA || HAinrange)
1402 /* Merging is now done on the fly, so do_merge is most likely obsolete now.
1403 * Will do some more testing before removing the function entirely.
1404 * - Erik Marklund, MAY 10 2010 */
1405 static void do_merge(t_hbdata* hb, int ntmp, bool htmp[], bool gtmp[], t_hbond* hb0, t_hbond* hb1)
1407 /* Here we need to make sure we're treating periodicity in
1408 * the right way for the geminate recombination kinetics. */
1410 int m, mm, n00, n01, nn0, nnframes;
1412 /* Decide where to start from when merging */
1415 nn0 = std::min(n00, n01);
1416 nnframes = std::max(n00 + hb0->nframes, n01 + hb1->nframes) - nn0;
1417 /* Initiate tmp arrays */
1418 for (m = 0; (m < ntmp); m++)
1423 /* Fill tmp arrays with values due to first HB */
1424 /* Once again '<' had to be replaced with '<='
1425 to catch the last frame in which the hbond
1427 - Erik Marklund, June 1, 2006 */
1428 for (m = 0; (m <= hb0->nframes); m++)
1431 htmp[mm] = is_hb(hb0->h[0], m);
1433 for (m = 0; (m <= hb0->nframes); m++)
1436 gtmp[mm] = is_hb(hb0->g[0], m);
1439 for (m = 0; (m <= hb1->nframes); m++)
1442 htmp[mm] = htmp[mm] || is_hb(hb1->h[0], m);
1443 gtmp[mm] = gtmp[mm] || is_hb(hb1->g[0], m);
1445 /* Reallocate target array */
1446 if (nnframes > hb0->maxframes)
1448 srenew(hb0->h[0], 4 + nnframes / hb->wordlen);
1449 srenew(hb0->g[0], 4 + nnframes / hb->wordlen);
1452 /* Copy temp array to target array */
1453 for (m = 0; (m <= nnframes); m++)
1455 _set_hb(hb0->h[0], m, htmp[m]);
1456 _set_hb(hb0->g[0], m, gtmp[m]);
1459 /* Set scalar variables */
1461 hb0->maxframes = nnframes;
1464 static void merge_hb(t_hbdata* hb, gmx_bool bTwo, gmx_bool bContact)
1466 int i, inrnew, indnew, j, ii, jj, id, ia, ntmp;
1471 indnew = hb->nrdist;
1473 /* Check whether donors are also acceptors */
1474 printf("Merging hbonds with Acceptor and Donor swapped\n");
1476 ntmp = 2 * hb->max_frames;
1479 for (i = 0; (i < hb->d.nrd); i++)
1481 fprintf(stderr, "\r%d/%d", i + 1, hb->d.nrd);
1484 ii = hb->a.aptr[id];
1485 for (j = 0; (j < hb->a.nra); j++)
1488 jj = hb->d.dptr[ia];
1489 if ((id != ia) && (ii != NOTSET) && (jj != NOTSET)
1490 && (!bTwo || (hb->d.grp[i] != hb->a.grp[j])))
1492 hb0 = hb->hbmap[i][j];
1493 hb1 = hb->hbmap[jj][ii];
1494 if (hb0 && hb1 && ISHB(hb0->history[0]) && ISHB(hb1->history[0]))
1496 do_merge(hb, ntmp, htmp, gtmp, hb0, hb1);
1497 if (ISHB(hb1->history[0]))
1501 else if (ISDIST(hb1->history[0]))
1507 gmx_incons("No contact history");
1511 gmx_incons("Neither hydrogen bond nor distance");
1515 hb1->h[0] = nullptr;
1516 hb1->g[0] = nullptr;
1517 hb1->history[0] = hbNo;
1522 fprintf(stderr, "\n");
1523 printf("- Reduced number of hbonds from %d to %d\n", hb->nrhb, inrnew);
1524 printf("- Reduced number of distances from %d to %d\n", hb->nrdist, indnew);
1526 hb->nrdist = indnew;
1531 static void do_nhb_dist(FILE* fp, t_hbdata* hb, real t)
1533 int i, j, k, n_bound[MAXHH], nbtot;
1535 /* Set array to 0 */
1536 for (k = 0; (k < MAXHH); k++)
1540 /* Loop over possible donors */
1541 for (i = 0; (i < hb->d.nrd); i++)
1543 for (j = 0; (j < hb->d.nhydro[i]); j++)
1545 n_bound[hb->d.nhbonds[i][j]]++;
1548 fprintf(fp, "%12.5e", t);
1550 for (k = 0; (k < MAXHH); k++)
1552 fprintf(fp, " %8d", n_bound[k]);
1553 nbtot += n_bound[k] * k;
1555 fprintf(fp, " %8d\n", nbtot);
1558 static void do_hblife(const char* fn, t_hbdata* hb, gmx_bool bMerge, gmx_bool bContact, const gmx_output_env_t* oenv)
1561 const char* leg[] = { "p(t)", "t p(t)" };
1563 int i, j, j0, k, m, nh, ihb, ohb, nhydro, ndump = 0;
1564 int nframes = hb->nframes;
1567 double sum, integral;
1570 snew(h, hb->maxhydro);
1571 snew(histo, nframes + 1);
1572 /* Total number of hbonds analyzed here */
1573 for (i = 0; (i < hb->d.nrd); i++)
1575 for (k = 0; (k < hb->a.nra); k++)
1577 hbh = hb->hbmap[i][k];
1595 for (m = 0; (m < hb->maxhydro); m++)
1599 h[nhydro++] = bContact ? hbh->g[m] : hbh->h[m];
1603 for (nh = 0; (nh < nhydro); nh++)
1608 for (j = 0; (j <= hbh->nframes); j++)
1610 ihb = static_cast<int>(is_hb(h[nh], j));
1611 if (debug && (ndump < 10))
1613 fprintf(debug, "%5d %5d\n", j, ihb);
1633 fprintf(stderr, "\n");
1636 fp = xvgropen(fn, "Uninterrupted contact lifetime", output_env_get_xvgr_tlabel(oenv), "()", oenv);
1640 fp = xvgropen(fn, "Uninterrupted hydrogen bond lifetime", output_env_get_xvgr_tlabel(oenv),
1644 xvgr_legend(fp, asize(leg), leg, oenv);
1646 while ((j0 > 0) && (histo[j0] == 0))
1651 for (i = 0; (i <= j0); i++)
1655 dt = hb->time[1] - hb->time[0];
1658 for (i = 1; (i <= j0); i++)
1660 t = hb->time[i] - hb->time[0] - 0.5 * dt;
1661 x1 = t * histo[i] / sum;
1662 fprintf(fp, "%8.3f %10.3e %10.3e\n", t, histo[i] / sum, x1);
1667 printf("%s lifetime = %.2f ps\n", bContact ? "Contact" : "HB", integral);
1668 printf("Note that the lifetime obtained in this manner is close to useless\n");
1669 printf("Use the -ac option instead and check the Forward lifetime\n");
1670 please_cite(stdout, "Spoel2006b");
1675 static void dump_ac(t_hbdata* hb, gmx_bool oneHB, int nDump)
1678 int i, j, k, m, nd, ihb, idist;
1679 int nframes = hb->nframes;
1687 fp = gmx_ffopen("debug-ac.xvg", "w");
1688 for (j = 0; (j < nframes); j++)
1690 fprintf(fp, "%10.3f", hb->time[j]);
1691 for (i = nd = 0; (i < hb->d.nrd) && (nd < nDump); i++)
1693 for (k = 0; (k < hb->a.nra) && (nd < nDump); k++)
1697 hbh = hb->hbmap[i][k];
1702 ihb = static_cast<int>(is_hb(hbh->h[0], j));
1703 idist = static_cast<int>(is_hb(hbh->g[0], j));
1709 for (m = 0; (m < hb->maxhydro) && !ihb; m++)
1711 ihb = static_cast<int>((ihb != 0)
1712 || (((hbh->h[m]) != nullptr) && is_hb(hbh->h[m], j)));
1713 idist = static_cast<int>((idist != 0)
1714 || (((hbh->g[m]) != nullptr) && is_hb(hbh->g[m], j)));
1716 /* This is not correct! */
1717 /* What isn't correct? -Erik M */
1722 fprintf(fp, " %1d-%1d", ihb, idist);
1732 static real calc_dg(real tau, real temp)
1743 return kbt * std::log(kbt * tau / PLANCK);
1749 int n0, n1, nparams, ndelta;
1751 real *t, *ct, *nt, *kt, *sigma_ct, *sigma_nt, *sigma_kt;
1754 static real compute_weighted_rates(int n,
1771 real kkk = 0, kkp = 0, kk2 = 0, kp2 = 0, chi2;
1776 for (i = 0; (i < n); i++)
1778 if (t[i] >= fit_start)
1791 tl.sigma_ct = sigma_ct;
1792 tl.sigma_nt = sigma_nt;
1793 tl.sigma_kt = sigma_kt;
1797 chi2 = 0; /*optimize_luzar_parameters(debug, &tl, 1000, 1e-3); */
1799 *kp = tl.kkk[1] = *kp;
1801 for (j = 0; (j < NK); j++)
1805 kk2 += gmx::square(tl.kkk[0]);
1806 kp2 += gmx::square(tl.kkk[1]);
1809 *sigma_k = std::sqrt(kk2 / NK - gmx::square(kkk / NK));
1810 *sigma_kp = std::sqrt(kp2 / NK - gmx::square(kkp / NK));
1815 void analyse_corr(int n,
1827 real k = 1, kp = 1, kow = 1;
1828 real Q = 0, chi2, tau_hb, dtau, tau_rlx, e_1, sigma_k, sigma_kp, ddg;
1829 double tmp, sn2 = 0, sc2 = 0, sk2 = 0, scn = 0, sck = 0, snk = 0;
1830 gmx_bool bError = (sigma_ct != nullptr) && (sigma_nt != nullptr) && (sigma_kt != nullptr);
1832 for (i0 = 0; (i0 < n - 2) && ((t[i0] - t[0]) < fit_start); i0++) {}
1835 for (i = i0; (i < n); i++)
1837 sc2 += gmx::square(ct[i]);
1838 sn2 += gmx::square(nt[i]);
1839 sk2 += gmx::square(kt[i]);
1840 sck += ct[i] * kt[i];
1841 snk += nt[i] * kt[i];
1842 scn += ct[i] * nt[i];
1844 printf("Hydrogen bond thermodynamics at T = %g K\n", temp);
1845 tmp = (sn2 * sc2 - gmx::square(scn));
1846 if ((tmp > 0) && (sn2 > 0))
1848 k = (sn2 * sck - scn * snk) / tmp;
1849 kp = (k * scn - snk) / sn2;
1853 for (i = i0; (i < n); i++)
1855 chi2 += gmx::square(k * ct[i] - kp * nt[i] - kt[i]);
1857 compute_weighted_rates(n, t, ct, nt, kt, sigma_ct, sigma_nt, sigma_kt, &k, &kp,
1858 &sigma_k, &sigma_kp, fit_start);
1859 Q = 0; /* quality_of_fit(chi2, 2);*/
1860 ddg = BOLTZ * temp * sigma_k / k;
1861 printf("Fitting paramaters chi^2 = %10g, Quality of fit = %10g\n", chi2, Q);
1862 printf("The Rate and Delta G are followed by an error estimate\n");
1863 printf("----------------------------------------------------------\n"
1864 "Type Rate (1/ps) Sigma Time (ps) DG (kJ/mol) Sigma\n");
1865 printf("Forward %10.3f %6.2f %8.3f %10.3f %6.2f\n", k, sigma_k, 1 / k,
1866 calc_dg(1 / k, temp), ddg);
1867 ddg = BOLTZ * temp * sigma_kp / kp;
1868 printf("Backward %10.3f %6.2f %8.3f %10.3f %6.2f\n", kp, sigma_kp, 1 / kp,
1869 calc_dg(1 / kp, temp), ddg);
1874 for (i = i0; (i < n); i++)
1876 chi2 += gmx::square(k * ct[i] - kp * nt[i] - kt[i]);
1878 printf("Fitting parameters chi^2 = %10g\nQ = %10g\n", chi2, Q);
1879 printf("--------------------------------------------------\n"
1880 "Type Rate (1/ps) Time (ps) DG (kJ/mol) Chi^2\n");
1881 printf("Forward %10.3f %8.3f %10.3f %10g\n", k, 1 / k, calc_dg(1 / k, temp), chi2);
1882 printf("Backward %10.3f %8.3f %10.3f\n", kp, 1 / kp, calc_dg(1 / kp, temp));
1887 kow = 2 * sck / sc2;
1888 printf("One-way %10.3f %s%8.3f %10.3f\n", kow, bError ? " " : "", 1 / kow,
1889 calc_dg(1 / kow, temp));
1893 printf(" - Numerical problems computing HB thermodynamics:\n"
1894 "sc2 = %g sn2 = %g sk2 = %g sck = %g snk = %g scn = %g\n",
1895 sc2, sn2, sk2, sck, snk, scn);
1897 /* Determine integral of the correlation function */
1898 tau_hb = evaluate_integral(n, t, ct, nullptr, (t[n - 1] - t[0]) / 2, &dtau);
1899 printf("Integral %10.3f %s%8.3f %10.3f\n", 1 / tau_hb, bError ? " " : "", tau_hb,
1900 calc_dg(tau_hb, temp));
1901 e_1 = std::exp(-1.0);
1902 for (i = 0; (i < n - 2); i++)
1904 if ((ct[i] > e_1) && (ct[i + 1] <= e_1))
1911 /* Determine tau_relax from linear interpolation */
1912 tau_rlx = t[i] - t[0] + (e_1 - ct[i]) * (t[i + 1] - t[i]) / (ct[i + 1] - ct[i]);
1913 printf("Relaxation %10.3f %8.3f %s%10.3f\n", 1 / tau_rlx, tau_rlx,
1914 bError ? " " : "", calc_dg(tau_rlx, temp));
1919 printf("Correlation functions too short to compute thermodynamics\n");
1923 void compute_derivative(int nn, const real x[], const real y[], real dydx[])
1927 /* Compute k(t) = dc(t)/dt */
1928 for (j = 1; (j < nn - 1); j++)
1930 dydx[j] = (y[j + 1] - y[j - 1]) / (x[j + 1] - x[j - 1]);
1932 /* Extrapolate endpoints */
1933 dydx[0] = 2 * dydx[1] - dydx[2];
1934 dydx[nn - 1] = 2 * dydx[nn - 2] - dydx[nn - 3];
1937 static void normalizeACF(real* ct, real* gt, int nhb, int len)
1939 real ct_fac, gt_fac = 0;
1942 /* Xu and Berne use the same normalization constant */
1944 ct_fac = 1.0 / ct[0];
1950 printf("Normalization for c(t) = %g for gh(t) = %g\n", ct_fac, gt_fac);
1951 for (i = 0; i < len; i++)
1961 static void do_hbac(const char* fn,
1969 const gmx_output_env_t* oenv,
1973 int i, j, k, m, ihb, idist, n2, nn;
1975 const char* legLuzar[] = { "Ac\\sfin sys\\v{}\\z{}(t)", "Ac(t)", "Cc\\scontact,hb\\v{}\\z{}(t)",
1976 "-dAc\\sfs\\v{}\\z{}/dt" };
1977 gmx_bool bNorm = FALSE;
1979 real * rhbex = nullptr, *ht, *gt, *ght, *dght, *kt;
1980 real * ct, tail, tail2, dtail, *cct;
1981 const real tol = 1e-3;
1982 int nframes = hb->nframes;
1983 unsigned int **h = nullptr, **g = nullptr;
1984 int nh, nhbonds, nhydro;
1987 int* dondata = nullptr;
1997 const bool bOMP = GMX_OPENMP;
1999 printf("Doing autocorrelation ");
2002 printf("according to the theory of Luzar and Chandler.\n");
2005 /* build hbexist matrix in reals for autocorr */
2006 /* Allocate memory for computing ACF (rhbex) and aggregating the ACF (ct) */
2008 while (n2 < nframes)
2015 if (acType != AC_NN || bOMP)
2017 snew(h, hb->maxhydro);
2018 snew(g, hb->maxhydro);
2021 /* Dump hbonds for debugging */
2022 dump_ac(hb, bMerge || bContact, nDump);
2024 /* Total number of hbonds analyzed here */
2027 if (acType != AC_LUZAR && bOMP)
2029 nThreads = std::min((nThreads <= 0) ? INT_MAX : nThreads, gmx_omp_get_max_threads());
2031 gmx_omp_set_num_threads(nThreads);
2032 snew(dondata, nThreads);
2033 for (i = 0; i < nThreads; i++)
2037 printf("ACF calculations parallelized with OpenMP using %i threads.\n"
2038 "Expect close to linear scaling over this donor-loop.\n",
2041 fprintf(stderr, "Donors: [thread no]\n");
2044 for (i = 0; i < nThreads; i++)
2046 snprintf(tmpstr, 7, "[%i]", i);
2047 fprintf(stderr, "%-7s", tmpstr);
2050 fprintf(stderr, "\n");
2055 snew(rhbex, 2 * n2);
2065 for (i = 0; (i < hb->d.nrd); i++)
2067 for (k = 0; (k < hb->a.nra); k++)
2070 hbh = hb->hbmap[i][k];
2074 if (bMerge || bContact)
2076 if (ISHB(hbh->history[0]))
2085 for (m = 0; (m < hb->maxhydro); m++)
2087 if (bContact ? ISDIST(hbh->history[m]) : ISHB(hbh->history[m]))
2089 g[nhydro] = hbh->g[m];
2090 h[nhydro] = hbh->h[m];
2096 int nf = hbh->nframes;
2097 for (nh = 0; (nh < nhydro); nh++)
2099 int nrint = bContact ? hb->nrdist : hb->nrhb;
2100 if ((((nhbonds + 1) % 10) == 0) || (nhbonds + 1 == nrint))
2102 fprintf(stderr, "\rACF %d/%d", nhbonds + 1, nrint);
2106 for (j = 0; (j < nframes); j++)
2110 ihb = static_cast<int>(is_hb(h[nh], j));
2111 idist = static_cast<int>(is_hb(g[nh], j));
2118 /* For contacts: if a second cut-off is provided, use it,
2119 * otherwise use g(t) = 1-h(t) */
2120 if (!R2 && bContact)
2126 gt[j] = idist * (1 - ihb);
2132 /* The autocorrelation function is normalized after summation only */
2133 low_do_autocorr(nullptr, oenv, nullptr, nframes, 1, -1, &rhbex,
2134 hb->time[1] - hb->time[0], eacNormal, 1, FALSE, bNorm, FALSE, 0,
2137 /* Cross correlation analysis for thermodynamics */
2138 for (j = nframes; (j < n2); j++)
2144 cross_corr(n2, ht, gt, dght);
2146 for (j = 0; (j < nn); j++)
2155 fprintf(stderr, "\n");
2158 normalizeACF(ct, ght, static_cast<int>(nhb), nn);
2160 /* Determine tail value for statistics */
2163 for (j = nn / 2; (j < nn); j++)
2166 tail2 += ct[j] * ct[j];
2168 tail /= (nn - int{ nn / 2 });
2169 tail2 /= (nn - int{ nn / 2 });
2170 dtail = std::sqrt(tail2 - tail * tail);
2172 /* Check whether the ACF is long enough */
2175 printf("\nWARNING: Correlation function is probably not long enough\n"
2176 "because the standard deviation in the tail of C(t) > %g\n"
2177 "Tail value (average C(t) over second half of acf): %g +/- %g\n",
2180 for (j = 0; (j < nn); j++)
2183 ct[j] = (cct[j] - tail) / (1 - tail);
2185 /* Compute negative derivative k(t) = -dc(t)/dt */
2186 compute_derivative(nn, hb->time, ct, kt);
2187 for (j = 0; (j < nn); j++)
2195 fp = xvgropen(fn, "Contact Autocorrelation", output_env_get_xvgr_tlabel(oenv), "C(t)", oenv);
2199 fp = xvgropen(fn, "Hydrogen Bond Autocorrelation", output_env_get_xvgr_tlabel(oenv), "C(t)", oenv);
2201 xvgr_legend(fp, asize(legLuzar), legLuzar, oenv);
2204 for (j = 0; (j < nn); j++)
2206 fprintf(fp, "%10g %10g %10g %10g %10g\n", hb->time[j] - hb->time[0], ct[j], cct[j],
2211 analyse_corr(nn, hb->time, ct, ght, kt, nullptr, nullptr, nullptr, fit_start, temp);
2213 do_view(oenv, fn, nullptr);
2224 static void init_hbframe(t_hbdata* hb, int nframes, real t)
2228 hb->time[nframes] = t;
2229 hb->nhb[nframes] = 0;
2230 hb->ndist[nframes] = 0;
2231 for (i = 0; (i < max_hx); i++)
2233 hb->nhx[nframes][i] = 0;
2237 static FILE* open_donor_properties_file(const char* fn, t_hbdata* hb, const gmx_output_env_t* oenv)
2240 const char* leg[] = { "Nbound", "Nfree" };
2247 fp = xvgropen(fn, "Donor properties", output_env_get_xvgr_tlabel(oenv), "Number", oenv);
2248 xvgr_legend(fp, asize(leg), leg, oenv);
2253 static void analyse_donor_properties(FILE* fp, t_hbdata* hb, int nframes, real t)
2255 int i, j, k, nbound, nb, nhtot;
2263 for (i = 0; (i < hb->d.nrd); i++)
2265 for (k = 0; (k < hb->d.nhydro[i]); k++)
2269 for (j = 0; (j < hb->a.nra) && (nb == 0); j++)
2271 if (hb->hbmap[i][j] && hb->hbmap[i][j]->h[k] && is_hb(hb->hbmap[i][j]->h[k], nframes))
2279 fprintf(fp, "%10.3e %6d %6d\n", t, nbound, nhtot - nbound);
2282 static void dump_hbmap(t_hbdata* hb,
2290 const t_atoms* atoms)
2293 int ddd, hhh, aaa, i, j, k, m, grp;
2294 char ds[32], hs[32], as[32];
2297 fp = opt2FILE("-hbn", nfile, fnm, "w");
2298 if (opt2bSet("-g", nfile, fnm))
2300 fplog = gmx_ffopen(opt2fn("-g", nfile, fnm), "w");
2301 fprintf(fplog, "# %10s %12s %12s\n", "Donor", "Hydrogen", "Acceptor");
2307 for (grp = gr0; grp <= (bTwo ? gr1 : gr0); grp++)
2309 fprintf(fp, "[ %s ]", grpnames[grp]);
2310 for (i = 0; i < isize[grp]; i++)
2312 fprintf(fp, (i % 15) ? " " : "\n");
2313 fprintf(fp, " %4d", index[grp][i] + 1);
2319 fprintf(fp, "[ donors_hydrogens_%s ]\n", grpnames[grp]);
2320 for (i = 0; (i < hb->d.nrd); i++)
2322 if (hb->d.grp[i] == grp)
2324 for (j = 0; (j < hb->d.nhydro[i]); j++)
2326 fprintf(fp, " %4d %4d", hb->d.don[i] + 1, hb->d.hydro[i][j] + 1);
2332 fprintf(fp, "[ acceptors_%s ]", grpnames[grp]);
2333 for (i = 0; (i < hb->a.nra); i++)
2335 if (hb->a.grp[i] == grp)
2337 fprintf(fp, (i % 15 && !first) ? " " : "\n");
2338 fprintf(fp, " %4d", hb->a.acc[i] + 1);
2347 fprintf(fp, bContact ? "[ contacts_%s-%s ]\n" : "[ hbonds_%s-%s ]\n", grpnames[0], grpnames[1]);
2351 fprintf(fp, bContact ? "[ contacts_%s ]" : "[ hbonds_%s ]\n", grpnames[0]);
2354 for (i = 0; (i < hb->d.nrd); i++)
2357 for (k = 0; (k < hb->a.nra); k++)
2360 for (m = 0; (m < hb->d.nhydro[i]); m++)
2362 if (hb->hbmap[i][k] && ISHB(hb->hbmap[i][k]->history[m]))
2364 sprintf(ds, "%s", mkatomname(atoms, ddd));
2365 sprintf(as, "%s", mkatomname(atoms, aaa));
2368 fprintf(fp, " %6d %6d\n", ddd + 1, aaa + 1);
2371 fprintf(fplog, "%12s %12s\n", ds, as);
2376 hhh = hb->d.hydro[i][m];
2377 sprintf(hs, "%s", mkatomname(atoms, hhh));
2378 fprintf(fp, " %6d %6d %6d\n", ddd + 1, hhh + 1, aaa + 1);
2381 fprintf(fplog, "%12s %12s %12s\n", ds, hs, as);
2395 /* sync_hbdata() updates the parallel t_hbdata p_hb using hb as template.
2396 * It mimics add_frames() and init_frame() to some extent. */
2397 static void sync_hbdata(t_hbdata* p_hb, int nframes)
2399 if (nframes >= p_hb->max_frames)
2401 p_hb->max_frames += 4096;
2402 srenew(p_hb->nhb, p_hb->max_frames);
2403 srenew(p_hb->ndist, p_hb->max_frames);
2404 srenew(p_hb->n_bound, p_hb->max_frames);
2405 srenew(p_hb->nhx, p_hb->max_frames);
2408 srenew(p_hb->danr, p_hb->max_frames);
2410 std::memset(&(p_hb->nhb[nframes]), 0, sizeof(int) * (p_hb->max_frames - nframes));
2411 std::memset(&(p_hb->ndist[nframes]), 0, sizeof(int) * (p_hb->max_frames - nframes));
2412 p_hb->nhb[nframes] = 0;
2413 p_hb->ndist[nframes] = 0;
2415 p_hb->nframes = nframes;
2417 std::memset(&(p_hb->nhx[nframes]), 0, sizeof(int) * max_hx); /* zero the helix count for this frame */
2420 int gmx_hbond(int argc, char* argv[])
2422 const char* desc[] = {
2423 "[THISMODULE] computes and analyzes hydrogen bonds. Hydrogen bonds are",
2424 "determined based on cutoffs for the angle Hydrogen - Donor - Acceptor",
2425 "(zero is extended) and the distance Donor - Acceptor",
2426 "(or Hydrogen - Acceptor using [TT]-noda[tt]).",
2427 "OH and NH groups are regarded as donors, O is an acceptor always,",
2428 "N is an acceptor by default, but this can be switched using",
2429 "[TT]-nitacc[tt]. Dummy hydrogen atoms are assumed to be connected",
2430 "to the first preceding non-hydrogen atom.[PAR]",
2432 "You need to specify two groups for analysis, which must be either",
2433 "identical or non-overlapping. All hydrogen bonds between the two",
2434 "groups are analyzed.[PAR]",
2436 "If you set [TT]-shell[tt], you will be asked for an additional index group",
2437 "which should contain exactly one atom. In this case, only hydrogen",
2438 "bonds between atoms within the shell distance from the one atom are", "considered.[PAR]",
2440 "With option -ac, rate constants for hydrogen bonding can be derived with the",
2441 "model of Luzar and Chandler (Nature 379:55, 1996; J. Chem. Phys. 113:23, 2000).",
2442 "If contact kinetics are analyzed by using the -contact option, then",
2443 "n(t) can be defined as either all pairs that are not within contact distance r at time t",
2444 "(corresponding to leaving the -r2 option at the default value 0) or all pairs that",
2445 "are within distance r2 (corresponding to setting a second cut-off value with option -r2).",
2446 "See mentioned literature for more details and definitions.", "[PAR]",
2448 /* "It is also possible to analyse specific hydrogen bonds with",
2449 "[TT]-sel[tt]. This index file must contain a group of atom triplets",
2450 "Donor Hydrogen Acceptor, in the following way::",
2457 "Note that the triplets need not be on separate lines.",
2458 "Each atom triplet specifies a hydrogen bond to be analyzed,",
2459 "note also that no check is made for the types of atoms.[PAR]",
2462 "[BB]Output:[bb]", "", " * [TT]-num[tt]: number of hydrogen bonds as a function of time.",
2463 " * [TT]-ac[tt]: average over all autocorrelations of the existence",
2464 " functions (either 0 or 1) of all hydrogen bonds.",
2465 " * [TT]-dist[tt]: distance distribution of all hydrogen bonds.",
2466 " * [TT]-ang[tt]: angle distribution of all hydrogen bonds.",
2467 " * [TT]-hx[tt]: the number of n-n+i hydrogen bonds as a function of time",
2468 " where n and n+i stand for residue numbers and i ranges from 0 to 6.",
2469 " This includes the n-n+3, n-n+4 and n-n+5 hydrogen bonds associated",
2470 " with helices in proteins.",
2471 " * [TT]-hbn[tt]: all selected groups, donors, hydrogens and acceptors",
2472 " for selected groups, all hydrogen bonded atoms from all groups and",
2473 " all solvent atoms involved in insertion.",
2474 " * [TT]-hbm[tt]: existence matrix for all hydrogen bonds over all",
2475 " frames, this also contains information on solvent insertion",
2476 " into hydrogen bonds. Ordering is identical to that in [TT]-hbn[tt]", " index file.",
2477 " * [TT]-dan[tt]: write out the number of donors and acceptors analyzed for",
2478 " each timeframe. This is especially useful when using [TT]-shell[tt].",
2479 " * [TT]-nhbdist[tt]: compute the number of HBonds per hydrogen in order to",
2480 " compare results to Raman Spectroscopy.", "",
2481 "Note: options [TT]-ac[tt], [TT]-life[tt], [TT]-hbn[tt] and [TT]-hbm[tt]",
2482 "require an amount of memory proportional to the total numbers of donors",
2483 "times the total number of acceptors in the selected group(s)."
2486 static real acut = 30, abin = 1, rcut = 0.35, r2cut = 0, rbin = 0.005, rshell = -1;
2487 static real maxnhb = 0, fit_start = 1, fit_end = 60, temp = 298.15;
2488 static gmx_bool bNitAcc = TRUE, bDA = TRUE, bMerge = TRUE;
2489 static int nDump = 0;
2490 static int nThreads = 0;
2492 static gmx_bool bContact = FALSE;
2496 { "-a", FALSE, etREAL, { &acut }, "Cutoff angle (degrees, Hydrogen - Donor - Acceptor)" },
2497 { "-r", FALSE, etREAL, { &rcut }, "Cutoff radius (nm, X - Acceptor, see next option)" },
2502 "Use distance Donor-Acceptor (if TRUE) or Hydrogen-Acceptor (FALSE)" },
2507 "Second cutoff radius. Mainly useful with [TT]-contact[tt] and [TT]-ac[tt]" },
2508 { "-abin", FALSE, etREAL, { &abin }, "Binwidth angle distribution (degrees)" },
2509 { "-rbin", FALSE, etREAL, { &rbin }, "Binwidth distance distribution (nm)" },
2510 { "-nitacc", FALSE, etBOOL, { &bNitAcc }, "Regard nitrogen atoms as acceptors" },
2515 "Do not look for hydrogen bonds, but merely for contacts within the cut-off distance" },
2520 "when > 0, only calculate hydrogen bonds within # nm shell around "
2526 "Time (ps) from which to start fitting the correlation functions in order to obtain the "
2527 "forward and backward rate constants for HB breaking and formation. With [TT]-gemfit[tt] "
2528 "we suggest [TT]-fitstart 0[tt]" },
2533 "Time (ps) to which to stop fitting the correlation functions in order to obtain the "
2534 "forward and backward rate constants for HB breaking and formation (only with "
2535 "[TT]-gemfit[tt])" },
2540 "Temperature (K) for computing the Gibbs energy corresponding to HB breaking and "
2546 "Dump the first N hydrogen bond ACFs in a single [REF].xvg[ref] file for debugging" },
2551 "Theoretical maximum number of hydrogen bonds used for normalizing HB autocorrelation "
2552 "function. Can be useful in case the program estimates it wrongly" },
2557 "H-bonds between the same donor and acceptor, but with different hydrogen are treated as "
2558 "a single H-bond. Mainly important for the ACF." },
2564 "Number of threads used for the parallel loop over autocorrelations. nThreads <= 0 means "
2565 "maximum number of threads. Requires linking with OpenMP. The number of threads is "
2566 "limited by the number of cores (before OpenMP v.3 ) or environment variable "
2567 "OMP_THREAD_LIMIT (OpenMP v.3)" },
2570 const char* bugs[] = {
2571 "The option [TT]-sel[tt] that used to work on selected hbonds is out of order, and "
2572 "therefore not available for the time being."
2574 t_filenm fnm[] = { { efTRX, "-f", nullptr, ffREAD },
2575 { efTPR, nullptr, nullptr, ffREAD },
2576 { efNDX, nullptr, nullptr, ffOPTRD },
2577 /* { efNDX, "-sel", "select", ffOPTRD },*/
2578 { efXVG, "-num", "hbnum", ffWRITE },
2579 { efLOG, "-g", "hbond", ffOPTWR },
2580 { efXVG, "-ac", "hbac", ffOPTWR },
2581 { efXVG, "-dist", "hbdist", ffOPTWR },
2582 { efXVG, "-ang", "hbang", ffOPTWR },
2583 { efXVG, "-hx", "hbhelix", ffOPTWR },
2584 { efNDX, "-hbn", "hbond", ffOPTWR },
2585 { efXPM, "-hbm", "hbmap", ffOPTWR },
2586 { efXVG, "-don", "donor", ffOPTWR },
2587 { efXVG, "-dan", "danum", ffOPTWR },
2588 { efXVG, "-life", "hblife", ffOPTWR },
2589 { efXVG, "-nhbdist", "nhbdist", ffOPTWR }
2592 #define NFILE asize(fnm)
2594 char hbmap[HB_NR] = { ' ', 'o', '-', '*' };
2595 const char* hbdesc[HB_NR] = { "None", "Present", "Inserted", "Present & Inserted" };
2596 t_rgb hbrgb[HB_NR] = { { 1, 1, 1 }, { 1, 0, 0 }, { 0, 0, 1 }, { 1, 0, 1 } };
2598 t_trxstatus* status;
2599 bool trrStatus = true;
2602 int npargs, natoms, nframes = 0, shatom;
2608 real t, ccut, dist = 0.0, ang = 0.0;
2609 double max_nhb, aver_nhb, aver_dist;
2610 int h = 0, i = 0, j, k = 0, ogrp, nsel;
2611 int xi = 0, yi, zi, ai;
2612 int xj, yj, zj, aj, xjj, yjj, zjj;
2613 gmx_bool bSelected, bHBmap, bStop, bTwo, bBox, bTric;
2614 int * adist, *rdist;
2615 int grp, nabin, nrbin, resdist, ihb;
2618 FILE * fp, *fpnhb = nullptr, *donor_properties = nullptr;
2620 t_ncell * icell, *jcell;
2622 unsigned char* datable;
2623 gmx_output_env_t* oenv;
2624 int ii, hh, actual_nThreads;
2627 gmx_bool bEdge_yjj, bEdge_xjj;
2629 t_hbdata** p_hb = nullptr; /* one per thread, then merge after the frame loop */
2630 int ** p_adist = nullptr, **p_rdist = nullptr; /* a histogram for each thread. */
2632 const bool bOMP = GMX_OPENMP;
2635 ppa = add_acf_pargs(&npargs, pa);
2637 if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT, NFILE, fnm, npargs, ppa,
2638 asize(desc), desc, asize(bugs), bugs, &oenv))
2646 ccut = std::cos(acut * DEG2RAD);
2652 gmx_fatal(FARGS, "Can not analyze selected contacts.");
2656 gmx_fatal(FARGS, "Can not analyze contact between H and A: turn off -noda");
2660 /* Initiate main data structure! */
2661 bHBmap = (opt2bSet("-ac", NFILE, fnm) || opt2bSet("-life", NFILE, fnm)
2662 || opt2bSet("-hbn", NFILE, fnm) || opt2bSet("-hbm", NFILE, fnm));
2664 if (opt2bSet("-nhbdist", NFILE, fnm))
2666 const char* leg[MAXHH + 1] = { "0 HBs", "1 HB", "2 HBs", "3 HBs", "Total" };
2667 fpnhb = xvgropen(opt2fn("-nhbdist", NFILE, fnm), "Number of donor-H with N HBs",
2668 output_env_get_xvgr_tlabel(oenv), "N", oenv);
2669 xvgr_legend(fpnhb, asize(leg), leg, oenv);
2672 hb = mk_hbdata(bHBmap, opt2bSet("-dan", NFILE, fnm), bMerge || bContact);
2675 t_inputrec irInstance;
2676 t_inputrec* ir = &irInstance;
2677 read_tpx_top(ftp2fn(efTPR, NFILE, fnm), ir, box, &natoms, nullptr, nullptr, &top);
2679 snew(grpnames, grNR);
2682 /* Make Donor-Acceptor table */
2683 snew(datable, top.atoms.nr);
2687 /* analyze selected hydrogen bonds */
2688 printf("Select group with selected atoms:\n");
2689 get_index(&(top.atoms), opt2fn("-sel", NFILE, fnm), 1, &nsel, index, grpnames);
2693 "Number of atoms in group '%s' not a multiple of 3\n"
2694 "and therefore cannot contain triplets of "
2695 "Donor-Hydrogen-Acceptor",
2700 for (i = 0; (i < nsel); i += 3)
2702 int dd = index[0][i];
2703 int aa = index[0][i + 2];
2704 /* int */ hh = index[0][i + 1];
2705 add_dh(&hb->d, dd, hh, i, datable);
2706 add_acc(&hb->a, aa, i);
2707 /* Should this be here ? */
2708 snew(hb->d.dptr, top.atoms.nr);
2709 snew(hb->a.aptr, top.atoms.nr);
2710 add_hbond(hb, dd, aa, hh, gr0, gr0, 0, bMerge, 0, bContact);
2712 printf("Analyzing %d selected hydrogen bonds from '%s'\n", isize[0], grpnames[0]);
2716 /* analyze all hydrogen bonds: get group(s) */
2717 printf("Specify 2 groups to analyze:\n");
2718 get_index(&(top.atoms), ftp2fn_null(efNDX, NFILE, fnm), 2, isize, index, grpnames);
2720 /* check if we have two identical or two non-overlapping groups */
2721 bTwo = isize[0] != isize[1];
2722 for (i = 0; (i < isize[0]) && !bTwo; i++)
2724 bTwo = index[0][i] != index[1][i];
2728 printf("Checking for overlap in atoms between %s and %s\n", grpnames[0], grpnames[1]);
2730 gen_datable(index[0], isize[0], datable, top.atoms.nr);
2732 for (i = 0; i < isize[1]; i++)
2734 if (ISINGRP(datable[index[1][i]]))
2736 gmx_fatal(FARGS, "Partial overlap between groups '%s' and '%s'", grpnames[0],
2743 printf("Calculating %s "
2744 "between %s (%d atoms) and %s (%d atoms)\n",
2745 bContact ? "contacts" : "hydrogen bonds", grpnames[0], isize[0], grpnames[1],
2750 fprintf(stderr, "Calculating %s in %s (%d atoms)\n",
2751 bContact ? "contacts" : "hydrogen bonds", grpnames[0], isize[0]);
2756 /* search donors and acceptors in groups */
2757 snew(datable, top.atoms.nr);
2758 for (i = 0; (i < grNR); i++)
2760 if (((i == gr0) && !bSelected) || ((i == gr1) && bTwo))
2762 gen_datable(index[i], isize[i], datable, top.atoms.nr);
2765 search_acceptors(&top, isize[i], index[i], &hb->a, i, bNitAcc, TRUE,
2766 (bTwo && (i == gr0)) || !bTwo, datable);
2767 search_donors(&top, isize[i], index[i], &hb->d, i, TRUE,
2768 (bTwo && (i == gr1)) || !bTwo, datable);
2772 search_acceptors(&top, isize[i], index[i], &hb->a, i, bNitAcc, FALSE, TRUE, datable);
2773 search_donors(&top, isize[i], index[i], &hb->d, i, FALSE, TRUE, datable);
2777 clear_datable_grp(datable, top.atoms.nr);
2782 printf("Found %d donors and %d acceptors\n", hb->d.nrd, hb->a.nra);
2784 snew(donors[gr0D], dons[gr0D].nrd);*/
2786 donor_properties = open_donor_properties_file(opt2fn_null("-don", NFILE, fnm), hb, oenv);
2790 printf("Making hbmap structure...");
2791 /* Generate hbond data structure */
2798 if (hb->d.nrd + hb->a.nra == 0)
2800 printf("No Donors or Acceptors found\n");
2807 printf("No Donors found\n");
2812 printf("No Acceptors found\n");
2818 gmx_fatal(FARGS, "Nothing to be done");
2827 /* get index group with atom for shell */
2830 printf("Select atom for shell (1 atom):\n");
2831 get_index(&(top.atoms), ftp2fn_null(efNDX, NFILE, fnm), 1, &shisz, &shidx, &shgrpnm);
2834 printf("group contains %d atoms, should be 1 (one)\n", shisz);
2836 } while (shisz != 1);
2838 printf("Will calculate hydrogen bonds within a shell "
2839 "of %g nm around atom %i\n",
2840 rshell, shatom + 1);
2843 /* Analyze trajectory */
2844 natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box);
2845 if (natoms > top.atoms.nr)
2847 gmx_fatal(FARGS, "Topology (%d atoms) does not match trajectory (%d atoms)", top.atoms.nr, natoms);
2850 bBox = (ir->ePBC != epbcNONE);
2851 grid = init_grid(bBox, box, (rcut > r2cut) ? rcut : r2cut, ngrid);
2852 nabin = static_cast<int>(acut / abin);
2853 nrbin = static_cast<int>(rcut / rbin);
2854 snew(adist, nabin + 1);
2855 snew(rdist, nrbin + 1);
2858 # define __ADIST adist
2859 # define __RDIST rdist
2860 # define __HBDATA hb
2861 #else /* GMX_OPENMP ================================================== \
2862 * Set up the OpenMP stuff, | \
2863 * like the number of threads and such | \
2864 * Also start the parallel loop. | \
2866 # define __ADIST p_adist[threadNr]
2867 # define __RDIST p_rdist[threadNr]
2868 # define __HBDATA p_hb[threadNr]
2872 bParallel = !bSelected;
2876 actual_nThreads = std::min((nThreads <= 0) ? INT_MAX : nThreads, gmx_omp_get_max_threads());
2878 gmx_omp_set_num_threads(actual_nThreads);
2879 printf("Frame loop parallelized with OpenMP using %i threads.\n", actual_nThreads);
2884 actual_nThreads = 1;
2887 snew(p_hb, actual_nThreads);
2888 snew(p_adist, actual_nThreads);
2889 snew(p_rdist, actual_nThreads);
2890 for (i = 0; i < actual_nThreads; i++)
2893 snew(p_adist[i], nabin + 1);
2894 snew(p_rdist[i], nrbin + 1);
2896 p_hb[i]->max_frames = 0;
2897 p_hb[i]->nhb = nullptr;
2898 p_hb[i]->ndist = nullptr;
2899 p_hb[i]->n_bound = nullptr;
2900 p_hb[i]->time = nullptr;
2901 p_hb[i]->nhx = nullptr;
2903 p_hb[i]->bHBmap = hb->bHBmap;
2904 p_hb[i]->bDAnr = hb->bDAnr;
2905 p_hb[i]->wordlen = hb->wordlen;
2906 p_hb[i]->nframes = hb->nframes;
2907 p_hb[i]->maxhydro = hb->maxhydro;
2908 p_hb[i]->danr = hb->danr;
2911 p_hb[i]->hbmap = hb->hbmap;
2912 p_hb[i]->time = hb->time; /* This may need re-syncing at every frame. */
2915 p_hb[i]->nrdist = 0;
2919 /* Make a thread pool here,
2920 * instead of forking anew at every frame. */
2922 #pragma omp parallel firstprivate(i) private( \
2923 j, h, ii, hh, xi, yi, zi, xj, yj, zj, threadNr, dist, ang, icell, jcell, grp, ogrp, ai, \
2924 aj, xjj, yjj, zjj, ihb, resdist, k, bTric, bEdge_xjj, bEdge_yjj) default(shared)
2925 { /* Start of parallel region */
2928 threadNr = gmx_omp_get_thread_num();
2933 bTric = bBox && TRICLINIC(box);
2939 sync_hbdata(p_hb[threadNr], nframes);
2941 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
2947 build_grid(hb, x, x[shatom], bBox, box, hbox, (rcut > r2cut) ? rcut : r2cut,
2948 rshell, ngrid, grid);
2949 reset_nhbonds(&(hb->d));
2951 if (debug && bDebug)
2953 dump_grid(debug, ngrid, grid);
2956 add_frames(hb, nframes);
2957 init_hbframe(hb, nframes, output_env_conv_time(oenv, t));
2961 count_da_grid(ngrid, grid, hb->danr[nframes]);
2964 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
2969 p_hb[threadNr]->time = hb->time; /* This pointer may have changed. */
2979 /* Do not parallelize this just yet. */
2981 for (ii = 0; (ii < nsel); ii++)
2983 int dd = index[0][i];
2984 int aa = index[0][i + 2];
2985 /* int */ hh = index[0][i + 1];
2986 ihb = is_hbond(hb, ii, ii, dd, aa, rcut, r2cut, ccut, x, bBox, box,
2987 hbox, &dist, &ang, bDA, &h, bContact, bMerge);
2991 /* add to index if not already there */
2993 add_hbond(hb, dd, aa, hh, ii, ii, nframes, bMerge, ihb, bContact);
2997 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
2999 } /* if (bSelected) */
3002 /* The outer grid loop will have to do for now. */
3003 #pragma omp for schedule(dynamic)
3004 for (xi = 0; xi < ngrid[XX]; xi++)
3008 for (yi = 0; (yi < ngrid[YY]); yi++)
3010 for (zi = 0; (zi < ngrid[ZZ]); zi++)
3013 /* loop over donor groups gr0 (always) and gr1 (if necessary) */
3014 for (grp = gr0; (grp <= (bTwo ? gr1 : gr0)); grp++)
3016 icell = &(grid[zi][yi][xi].d[grp]);
3027 /* loop over all hydrogen atoms from group (grp)
3028 * in this gridcell (icell)
3030 for (ai = 0; (ai < icell->nr); ai++)
3032 i = icell->atoms[ai];
3034 /* loop over all adjacent gridcells (xj,yj,zj) */
3035 for (zjj = grid_loop_begin(ngrid[ZZ], zi, bTric, FALSE);
3036 zjj <= grid_loop_end(ngrid[ZZ], zi, bTric, FALSE); zjj++)
3038 zj = grid_mod(zjj, ngrid[ZZ]);
3039 bEdge_yjj = (zj == 0) || (zj == ngrid[ZZ] - 1);
3040 for (yjj = grid_loop_begin(ngrid[YY], yi, bTric, bEdge_yjj);
3041 yjj <= grid_loop_end(ngrid[YY], yi, bTric, bEdge_yjj);
3044 yj = grid_mod(yjj, ngrid[YY]);
3045 bEdge_xjj = (yj == 0) || (yj == ngrid[YY] - 1)
3046 || (zj == 0) || (zj == ngrid[ZZ] - 1);
3047 for (xjj = grid_loop_begin(ngrid[XX], xi, bTric, bEdge_xjj);
3048 xjj <= grid_loop_end(ngrid[XX], xi, bTric, bEdge_xjj);
3051 xj = grid_mod(xjj, ngrid[XX]);
3052 jcell = &(grid[zj][yj][xj].a[ogrp]);
3053 /* loop over acceptor atoms from other group
3054 * (ogrp) in this adjacent gridcell (jcell)
3056 for (aj = 0; (aj < jcell->nr); aj++)
3058 j = jcell->atoms[aj];
3060 /* check if this once was a h-bond */
3061 ihb = is_hbond(__HBDATA, grp, ogrp, i, j,
3062 rcut, r2cut, ccut, x, bBox,
3063 box, hbox, &dist, &ang, bDA,
3064 &h, bContact, bMerge);
3068 /* add to index if not already there */
3070 add_hbond(__HBDATA, i, j, h, grp, ogrp,
3071 nframes, bMerge, ihb, bContact);
3073 /* make angle and distance distributions */
3074 if (ihb == hbHB && !bContact)
3080 "distance is higher "
3081 "than what is allowed "
3086 __ADIST[static_cast<int>(ang / abin)]++;
3087 __RDIST[static_cast<int>(dist / rbin)]++;
3090 if (donor_index(&hb->d, grp, i) == NOTSET)
3094 "Invalid donor %d", i);
3096 if (acceptor_index(&hb->a, ogrp, j)
3105 top.atoms.atom[i].resind
3106 - top.atoms.atom[j].resind);
3107 if (resdist >= max_hx)
3109 resdist = max_hx - 1;
3111 __HBDATA->nhx[nframes][resdist]++;
3121 } /* for xi,yi,zi */
3124 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3126 } /* if (bSelected) {...} else */
3129 /* Better wait for all threads to finnish using x[] before updating it. */
3132 #pragma omp critical
3136 /* Sum up histograms and counts from p_hb[] into hb */
3139 hb->nhb[k] += p_hb[threadNr]->nhb[k];
3140 hb->ndist[k] += p_hb[threadNr]->ndist[k];
3141 for (j = 0; j < max_hx; j++)
3143 hb->nhx[k][j] += p_hb[threadNr]->nhx[k][j];
3147 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3150 /* Here are a handful of single constructs
3151 * to share the workload a bit. The most
3152 * important one is of course the last one,
3153 * where there's a potential bottleneck in form
3160 analyse_donor_properties(donor_properties, hb, k, t);
3162 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3171 do_nhb_dist(fpnhb, hb, t);
3174 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3181 trrStatus = (read_next_x(oenv, status, &t, x, box));
3184 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3188 } while (trrStatus);
3192 #pragma omp critical
3194 hb->nrhb += p_hb[threadNr]->nrhb;
3195 hb->nrdist += p_hb[threadNr]->nrdist;
3198 /* Free parallel datastructures */
3199 sfree(p_hb[threadNr]->nhb);
3200 sfree(p_hb[threadNr]->ndist);
3201 sfree(p_hb[threadNr]->nhx);
3204 for (i = 0; i < nabin; i++)
3208 for (j = 0; j < actual_nThreads; j++)
3211 adist[i] += p_adist[j][i];
3214 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3217 for (i = 0; i <= nrbin; i++)
3221 for (j = 0; j < actual_nThreads; j++)
3223 rdist[i] += p_rdist[j][i];
3226 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3229 sfree(p_adist[threadNr]);
3230 sfree(p_rdist[threadNr]);
3232 } /* End of parallel region */
3239 if (nframes < 2 && (opt2bSet("-ac", NFILE, fnm) || opt2bSet("-life", NFILE, fnm)))
3242 "Cannot calculate autocorrelation of life times with less than two frames");
3245 free_grid(ngrid, &grid);
3249 if (donor_properties)
3251 xvgrclose(donor_properties);
3259 /* Compute maximum possible number of different hbonds */
3266 max_nhb = 0.5 * (hb->d.nrd * hb->a.nra);
3273 printf("No %s found!!\n", bContact ? "contacts" : "hydrogen bonds");
3277 printf("Found %d different %s in trajectory\n"
3278 "Found %d different atom-pairs within %s distance\n",
3279 hb->nrhb, bContact ? "contacts" : "hydrogen bonds", hb->nrdist,
3280 (r2cut > 0) ? "second cut-off" : "hydrogen bonding");
3284 merge_hb(hb, bTwo, bContact);
3287 if (opt2bSet("-hbn", NFILE, fnm))
3289 dump_hbmap(hb, NFILE, fnm, bTwo, bContact, isize, index, grpnames, &top.atoms);
3292 /* Moved the call to merge_hb() to a line BEFORE dump_hbmap
3293 * to make the -hbn and -hmb output match eachother.
3294 * - Erik Marklund, May 30, 2006 */
3297 /* Print out number of hbonds and distances */
3300 fp = xvgropen(opt2fn("-num", NFILE, fnm), bContact ? "Contacts" : "Hydrogen Bonds",
3301 output_env_get_xvgr_tlabel(oenv), "Number", oenv);
3303 snew(leg[0], STRLEN);
3304 snew(leg[1], STRLEN);
3305 sprintf(leg[0], "%s", bContact ? "Contacts" : "Hydrogen bonds");
3306 sprintf(leg[1], "Pairs within %g nm", (r2cut > 0) ? r2cut : rcut);
3307 xvgr_legend(fp, 2, leg, oenv);
3311 for (i = 0; (i < nframes); i++)
3313 fprintf(fp, "%10g %10d %10d\n", hb->time[i], hb->nhb[i], hb->ndist[i]);
3314 aver_nhb += hb->nhb[i];
3315 aver_dist += hb->ndist[i];
3318 aver_nhb /= nframes;
3319 aver_dist /= nframes;
3320 /* Print HB distance distribution */
3321 if (opt2bSet("-dist", NFILE, fnm))
3326 for (i = 0; i < nrbin; i++)
3331 fp = xvgropen(opt2fn("-dist", NFILE, fnm), "Hydrogen Bond Distribution",
3332 bDA ? "Donor - Acceptor Distance (nm)" : "Hydrogen - Acceptor Distance (nm)",
3334 for (i = 0; i < nrbin; i++)
3336 fprintf(fp, "%10g %10g\n", (i + 0.5) * rbin, rdist[i] / (rbin * sum));
3341 /* Print HB angle distribution */
3342 if (opt2bSet("-ang", NFILE, fnm))
3347 for (i = 0; i < nabin; i++)
3352 fp = xvgropen(opt2fn("-ang", NFILE, fnm), "Hydrogen Bond Distribution",
3353 "Hydrogen - Donor - Acceptor Angle (\\SO\\N)", "", oenv);
3354 for (i = 0; i < nabin; i++)
3356 fprintf(fp, "%10g %10g\n", (i + 0.5) * abin, adist[i] / (abin * sum));
3361 /* Print HB in alpha-helix */
3362 if (opt2bSet("-hx", NFILE, fnm))
3364 fp = xvgropen(opt2fn("-hx", NFILE, fnm), "Hydrogen Bonds", output_env_get_xvgr_tlabel(oenv),
3366 xvgr_legend(fp, NRHXTYPES, hxtypenames, oenv);
3367 for (i = 0; i < nframes; i++)
3369 fprintf(fp, "%10g", hb->time[i]);
3370 for (j = 0; j < max_hx; j++)
3372 fprintf(fp, " %6d", hb->nhx[i][j]);
3379 printf("Average number of %s per timeframe %.3f out of %g possible\n",
3380 bContact ? "contacts" : "hbonds", bContact ? aver_dist : aver_nhb, max_nhb);
3382 /* Do Autocorrelation etc. */
3386 Added support for -contact in ac and hbm calculations below.
3387 - Erik Marklund, May 29, 2006
3389 if (opt2bSet("-ac", NFILE, fnm) || opt2bSet("-life", NFILE, fnm))
3391 please_cite(stdout, "Spoel2006b");
3393 if (opt2bSet("-ac", NFILE, fnm))
3395 do_hbac(opt2fn("-ac", NFILE, fnm), hb, nDump, bMerge, bContact, fit_start, temp,
3396 r2cut > 0, oenv, nThreads);
3398 if (opt2bSet("-life", NFILE, fnm))
3400 do_hblife(opt2fn("-life", NFILE, fnm), hb, bMerge, bContact, oenv);
3402 if (opt2bSet("-hbm", NFILE, fnm))
3405 int id, ia, hh, x, y;
3408 if ((nframes > 0) && (hb->nrhb > 0))
3413 mat.matrix.resize(mat.nx, mat.ny);
3414 for (auto& value : mat.matrix.toArrayRef())
3419 for (id = 0; (id < hb->d.nrd); id++)
3421 for (ia = 0; (ia < hb->a.nra); ia++)
3423 for (hh = 0; (hh < hb->maxhydro); hh++)
3425 if (hb->hbmap[id][ia])
3427 if (ISHB(hb->hbmap[id][ia]->history[hh]))
3429 for (x = 0; (x <= hb->hbmap[id][ia]->nframes); x++)
3431 int nn0 = hb->hbmap[id][ia]->n0;
3432 range_check(y, 0, mat.ny);
3433 mat.matrix(x + nn0, y) = static_cast<t_matelmt>(
3434 is_hb(hb->hbmap[id][ia]->h[hh], x));
3442 std::copy(hb->time, hb->time + mat.nx, mat.axis_x.begin());
3443 mat.axis_y.resize(mat.ny);
3444 std::iota(mat.axis_y.begin(), mat.axis_y.end(), 0);
3445 mat.title = (bContact ? "Contact Existence Map" : "Hydrogen Bond Existence Map");
3446 mat.legend = bContact ? "Contacts" : "Hydrogen Bonds";
3447 mat.label_x = output_env_get_xvgr_tlabel(oenv);
3448 mat.label_y = bContact ? "Contact Index" : "Hydrogen Bond Index";
3449 mat.bDiscrete = true;
3451 for (auto& m : mat.map)
3453 m.code.c1 = hbmap[i];
3457 fp = opt2FILE("-hbm", NFILE, fnm, "w");
3458 write_xpm_m(fp, mat);
3464 "No hydrogen bonds/contacts found. No hydrogen bond map will be "
3476 #define USE_THIS_GROUP(j) (((j) == gr0) || (bTwo && ((j) == gr1)))
3478 fp = xvgropen(opt2fn("-dan", NFILE, fnm), "Donors and Acceptors",
3479 output_env_get_xvgr_tlabel(oenv), "Count", oenv);
3480 nleg = (bTwo ? 2 : 1) * 2;
3481 snew(legnames, nleg);
3483 for (j = 0; j < grNR; j++)
3485 if (USE_THIS_GROUP(j))
3487 sprintf(buf, "Donors %s", grpnames[j]);
3488 legnames[i++] = gmx_strdup(buf);
3489 sprintf(buf, "Acceptors %s", grpnames[j]);
3490 legnames[i++] = gmx_strdup(buf);
3495 gmx_incons("number of legend entries");
3497 xvgr_legend(fp, nleg, legnames, oenv);
3498 for (i = 0; i < nframes; i++)
3500 fprintf(fp, "%10g", hb->time[i]);
3501 for (j = 0; (j < grNR); j++)
3503 if (USE_THIS_GROUP(j))
3505 fprintf(fp, " %6d", hb->danr[i][j]);