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 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/correlationfunctions/crosscorr.h"
53 #include "gromacs/correlationfunctions/expfit.h"
54 #include "gromacs/correlationfunctions/integrate.h"
55 #include "gromacs/fileio/matio.h"
56 #include "gromacs/fileio/tpxio.h"
57 #include "gromacs/fileio/trxio.h"
58 #include "gromacs/fileio/xvgr.h"
59 #include "gromacs/gmxana/gmx_ana.h"
60 #include "gromacs/gmxana/gstat.h"
61 #include "gromacs/math/functions.h"
62 #include "gromacs/math/units.h"
63 #include "gromacs/math/vec.h"
64 #include "gromacs/mdtypes/inputrec.h"
65 #include "gromacs/pbcutil/pbc.h"
66 #include "gromacs/topology/ifunc.h"
67 #include "gromacs/topology/index.h"
68 #include "gromacs/topology/topology.h"
69 #include "gromacs/utility/arraysize.h"
70 #include "gromacs/utility/cstringutil.h"
71 #include "gromacs/utility/exceptions.h"
72 #include "gromacs/utility/fatalerror.h"
73 #include "gromacs/utility/futil.h"
74 #include "gromacs/utility/gmxomp.h"
75 #include "gromacs/utility/pleasecite.h"
76 #include "gromacs/utility/programcontext.h"
77 #include "gromacs/utility/smalloc.h"
78 #include "gromacs/utility/snprintf.h"
81 typedef int t_hx[max_hx];
82 #define NRHXTYPES max_hx
83 static const char* hxtypenames[NRHXTYPES] = { "n-n", "n-n+1", "n-n+2", "n-n+3",
84 "n-n+4", "n-n+5", "n-n>6" };
87 static const int NOTSET = -49297;
89 /* -----------------------------------------*/
106 static const unsigned char c_acceptorMask = (1 << 0);
107 static const unsigned char c_donorMask = (1 << 1);
108 static const unsigned char c_inGroupMask = (1 << 2);
111 static const char* grpnames[grNR] = { "0", "1", "I" };
113 static gmx_bool bDebug = FALSE;
116 #define HB_YES 1 << 0
117 #define HB_INS 1 << 1
118 #define HB_YESINS (HB_YES | HB_INS)
119 #define HB_NR (1 << 2)
122 #define ISHB(h) ((h)&2)
123 #define ISDIST(h) ((h)&1)
124 #define ISDIST2(h) ((h)&4)
125 #define ISACC(h) ((h)&c_acceptorMask)
126 #define ISDON(h) ((h)&c_donorMask)
127 #define ISINGRP(h) ((h)&c_inGroupMask)
142 typedef int t_icell[grNR];
143 typedef int h_id[MAXHYDRO];
147 int history[MAXHYDRO];
148 /* Has this hbond existed ever? If so as hbDist or hbHB or both.
149 * Result is stored as a bitmap (1 = hbDist) || (2 = hbHB)
151 /* Bitmask array which tells whether a hbond is present
152 * at a given time. Either of these may be NULL
154 int n0; /* First frame a HB was found */
155 int nframes, maxframes; /* Amount of frames in this hbond */
158 /* See Xu and Berne, JPCB 105 (2001), p. 11929. We define the
159 * function g(t) = [1-h(t)] H(t) where H(t) is one when the donor-
160 * acceptor distance is less than the user-specified distance (typically
168 int* acc; /* Atom numbers of the acceptors */
169 int* grp; /* Group index */
170 int* aptr; /* Map atom number to acceptor index */
176 int* don; /* Atom numbers of the donors */
177 int* grp; /* Group index */
178 int* dptr; /* Map atom number to donor index */
179 int* nhydro; /* Number of hydrogens for each donor */
180 h_id* hydro; /* The atom numbers of the hydrogens */
181 h_id* nhbonds; /* The number of HBs per H at current */
186 gmx_bool bHBmap, bDAnr;
188 /* The following arrays are nframes long */
189 int nframes, max_frames, maxhydro;
195 /* These structures are initialized from the topology at start up */
198 /* This holds a matrix with all possible hydrogen bonds */
203 /* Changed argument 'bMerge' into 'oneHB' below,
204 * since -contact should cause maxhydro to be 1,
206 * - Erik Marklund May 29, 2006
209 static t_hbdata* mk_hbdata(gmx_bool bHBmap, gmx_bool bDAnr, gmx_bool oneHB)
214 hb->wordlen = 8 * sizeof(unsigned int);
223 hb->maxhydro = MAXHYDRO;
228 static void mk_hbmap(t_hbdata* hb)
232 snew(hb->hbmap, hb->d.nrd);
233 for (i = 0; (i < hb->d.nrd); i++)
235 snew(hb->hbmap[i], hb->a.nra);
236 if (hb->hbmap[i] == nullptr)
238 gmx_fatal(FARGS, "Could not allocate enough memory for hbmap");
240 for (j = 0; j < hb->a.nra; j++)
242 hb->hbmap[i][j] = nullptr;
247 static void add_frames(t_hbdata* hb, int nframes)
249 if (nframes >= hb->max_frames)
251 hb->max_frames += 4096;
252 srenew(hb->time, hb->max_frames);
253 srenew(hb->nhb, hb->max_frames);
254 srenew(hb->ndist, hb->max_frames);
255 srenew(hb->n_bound, hb->max_frames);
256 srenew(hb->nhx, hb->max_frames);
259 srenew(hb->danr, hb->max_frames);
262 hb->nframes = nframes;
265 #define OFFSET(frame) ((frame) / 32)
266 #define MASK(frame) (1 << ((frame) % 32))
268 static void _set_hb(unsigned int hbexist[], unsigned int frame, gmx_bool bValue)
272 hbexist[OFFSET(frame)] |= MASK(frame);
276 hbexist[OFFSET(frame)] &= ~MASK(frame);
280 static gmx_bool is_hb(const unsigned int hbexist[], int frame)
282 return (hbexist[OFFSET(frame)] & MASK(frame)) != 0;
285 static void set_hb(t_hbdata* hb, int id, int ih, int ia, int frame, int ihb)
287 unsigned int* ghptr = nullptr;
291 ghptr = hb->hbmap[id][ia]->h[ih];
293 else if (ihb == hbDist)
295 ghptr = hb->hbmap[id][ia]->g[ih];
299 gmx_fatal(FARGS, "Incomprehensible iValue %d in set_hb", ihb);
302 _set_hb(ghptr, frame - hb->hbmap[id][ia]->n0, TRUE);
305 static void add_ff(t_hbdata* hbd, int id, int h, int ia, int frame, int ihb)
308 t_hbond* hb = hbd->hbmap[id][ia];
309 int maxhydro = std::min(hbd->maxhydro, hbd->d.nhydro[id]);
310 int wlen = hbd->wordlen;
311 int delta = 32 * wlen;
316 hb->maxframes = delta;
317 for (i = 0; (i < maxhydro); i++)
319 snew(hb->h[i], hb->maxframes / wlen);
320 snew(hb->g[i], hb->maxframes / wlen);
325 hb->nframes = frame - hb->n0;
326 /* We need a while loop here because hbonds may be returning
329 while (hb->nframes >= hb->maxframes)
331 n = hb->maxframes + delta;
332 for (i = 0; (i < maxhydro); i++)
334 srenew(hb->h[i], n / wlen);
335 srenew(hb->g[i], n / wlen);
336 for (j = hb->maxframes / wlen; (j < n / wlen); j++)
348 set_hb(hbd, id, h, ia, frame, ihb);
352 static void inc_nhbonds(t_donors* ddd, int d, int h)
355 int dptr = ddd->dptr[d];
357 for (j = 0; (j < ddd->nhydro[dptr]); j++)
359 if (ddd->hydro[dptr][j] == h)
361 ddd->nhbonds[dptr][j]++;
365 if (j == ddd->nhydro[dptr])
367 gmx_fatal(FARGS, "No such hydrogen %d on donor %d\n", h + 1, d + 1);
371 static int _acceptor_index(t_acceptors* a, int grp, int i, const char* file, int line)
375 if (a->grp[ai] != grp)
379 fprintf(debug, "Acc. group inconsist.. grp[%d] = %d, grp = %d (%s, %d)\n", ai, 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, d->grp[di], grp, file, line);
412 #define donor_index(d, grp, i) _donor_index(d, grp, i, __FILE__, __LINE__)
414 static gmx_bool isInterchangable(t_hbdata* hb, int d, int a, int grpa, int grpd)
416 /* g_hbond doesn't allow overlapping groups */
421 return donor_index(&hb->d, grpd, a) != NOTSET && acceptor_index(&hb->a, grpa, d) != NOTSET;
426 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)
429 gmx_bool daSwap = FALSE;
431 if ((id = hb->d.dptr[d]) == NOTSET)
433 gmx_fatal(FARGS, "No donor atom %d", d + 1);
435 else if (grpd != hb->d.grp[id])
437 gmx_fatal(FARGS, "Inconsistent donor groups, %d instead of %d, atom %d", grpd, hb->d.grp[id], d + 1);
439 if ((ia = hb->a.aptr[a]) == NOTSET)
441 gmx_fatal(FARGS, "No acceptor atom %d", a + 1);
443 else if (grpa != hb->a.grp[ia])
445 gmx_fatal(FARGS, "Inconsistent acceptor groups, %d instead of %d, atom %d", grpa, hb->a.grp[ia], a + 1);
451 if (isInterchangable(hb, d, a, grpd, grpa) && d > a)
452 /* Then swap identity so that the id of d is lower then that of a.
454 * This should really be redundant by now, as is_hbond() now ought to return
455 * hbNo in the cases where this conditional is TRUE. */
462 /* Now repeat donor/acc check. */
463 if ((id = hb->d.dptr[d]) == NOTSET)
465 gmx_fatal(FARGS, "No donor atom %d", d + 1);
467 else if (grpd != hb->d.grp[id])
470 "Inconsistent donor groups, %d instead of %d, atom %d",
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])
482 "Inconsistent acceptor groups, %d instead of %d, atom %d",
492 /* Loop over hydrogens to find which hydrogen is in this particular HB */
493 if ((ihb == hbHB) && !bMerge && !bContact)
495 for (k = 0; (k < hb->d.nhydro[id]); k++)
497 if (hb->d.hydro[id][k] == h)
502 if (k == hb->d.nhydro[id])
504 gmx_fatal(FARGS, "Donor %d does not have hydrogen %d (a = %d)", d + 1, h + 1, a + 1);
519 if (hb->hbmap[id][ia] == nullptr)
521 snew(hb->hbmap[id][ia], 1);
522 snew(hb->hbmap[id][ia]->h, hb->maxhydro);
523 snew(hb->hbmap[id][ia]->g, hb->maxhydro);
525 add_ff(hb, id, k, ia, frame, ihb);
527 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
531 /* Strange construction with frame >=0 is a relic from old code
532 * for selected hbond analysis. It may be necessary again if that
533 * is made to work again.
537 hh = hb->hbmap[id][ia]->history[k];
543 hb->hbmap[id][ia]->history[k] = hh | 2;
554 hb->hbmap[id][ia]->history[k] = hh | 1;
578 if (bMerge && daSwap)
580 h = hb->d.hydro[id][0];
582 /* Increment number if HBonds per H */
583 if (ihb == hbHB && !bContact)
585 inc_nhbonds(&(hb->d), d, h);
589 static char* mkatomname(const t_atoms* atoms, int i)
594 rnr = atoms->atom[i].resind;
595 sprintf(buf, "%4s%d%-4s", *atoms->resinfo[rnr].name, atoms->resinfo[rnr].nr, *atoms->atomname[i]);
600 static void gen_datable(int* index, int isize, unsigned char* datable, int natoms)
602 /* Generates table of all atoms and sets the ingroup bit for atoms in index[] */
605 for (i = 0; i < isize; i++)
607 if (index[i] >= natoms)
609 gmx_fatal(FARGS, "Atom has index %d larger than number of atoms %d.", index[i], natoms);
611 datable[index[i]] |= c_inGroupMask;
615 static void clear_datable_grp(unsigned char* datable, int size)
617 /* Clears group information from the table */
621 for (i = 0; i < size; i++)
623 datable[i] &= ~c_inGroupMask;
628 static void add_acc(t_acceptors* a, int ia, int grp)
630 if (a->nra >= a->max_nra)
633 srenew(a->acc, a->max_nra);
634 srenew(a->grp, a->max_nra);
636 a->grp[a->nra] = grp;
637 a->acc[a->nra++] = ia;
640 static void search_acceptors(const t_topology* top,
648 unsigned char* datable)
654 for (i = 0; (i < isize); i++)
658 || (((*top->atoms.atomname[n])[0] == 'O')
659 || (bNitAcc && ((*top->atoms.atomname[n])[0] == 'N'))))
660 && ISINGRP(datable[n]))
662 datable[n] |= c_acceptorMask;
667 snew(a->aptr, top->atoms.nr);
668 for (i = 0; (i < top->atoms.nr); i++)
672 for (i = 0; (i < a->nra); i++)
674 a->aptr[a->acc[i]] = i;
678 static void add_h2d(int id, int ih, t_donors* ddd)
682 for (i = 0; (i < ddd->nhydro[id]); i++)
684 if (ddd->hydro[id][i] == ih)
686 printf("Hm. This isn't the first time I found this donor (%d,%d)\n", ddd->don[id], ih);
690 if (i == ddd->nhydro[id])
692 if (ddd->nhydro[id] >= MAXHYDRO)
694 gmx_fatal(FARGS, "Donor %d has more than %d hydrogens!", ddd->don[id], MAXHYDRO);
696 ddd->hydro[id][i] = ih;
701 static void add_dh(t_donors* ddd, int id, int ih, int grp, const unsigned char* datable)
705 if (!datable || ISDON(datable[id]))
707 if (ddd->dptr[id] == NOTSET) /* New donor */
719 if (ddd->nrd >= ddd->max_nrd)
722 srenew(ddd->don, ddd->max_nrd);
723 srenew(ddd->nhydro, ddd->max_nrd);
724 srenew(ddd->hydro, ddd->max_nrd);
725 srenew(ddd->nhbonds, ddd->max_nrd);
726 srenew(ddd->grp, ddd->max_nrd);
728 ddd->don[ddd->nrd] = id;
729 ddd->nhydro[ddd->nrd] = 0;
730 ddd->grp[ddd->nrd] = grp;
741 printf("Warning: Atom %d is not in the d/a-table!\n", id);
745 static void search_donors(const t_topology* top,
752 unsigned char* datable)
755 t_functype func_type;
760 snew(ddd->dptr, top->atoms.nr);
761 for (i = 0; (i < top->atoms.nr); i++)
763 ddd->dptr[i] = NOTSET;
771 for (i = 0; (i < isize); i++)
773 datable[index[i]] |= c_donorMask;
774 add_dh(ddd, index[i], -1, grp, datable);
780 for (func_type = 0; (func_type < F_NRE); func_type++)
782 const t_ilist* interaction = &(top->idef.il[func_type]);
783 if (func_type == F_POSRES || func_type == F_FBPOSRES)
785 /* The ilist looks strange for posre. Bug in grompp?
786 * We don't need posre interactions for hbonds anyway.*/
789 for (i = 0; i < interaction->nr;
790 i += interaction_function[top->idef.functype[interaction->iatoms[i]]].nratoms + 1)
793 if (func_type != top->idef.functype[interaction->iatoms[i]])
795 fprintf(stderr, "Error in func_type %s", interaction_function[func_type].longname);
799 /* check out this functype */
800 if (func_type == F_SETTLE)
802 nr1 = interaction->iatoms[i + 1];
803 nr2 = interaction->iatoms[i + 2];
804 nr3 = interaction->iatoms[i + 3];
806 if (ISINGRP(datable[nr1]))
808 if (ISINGRP(datable[nr2]))
810 datable[nr1] |= c_donorMask;
811 add_dh(ddd, nr1, nr1 + 1, grp, datable);
813 if (ISINGRP(datable[nr3]))
815 datable[nr1] |= c_donorMask;
816 add_dh(ddd, nr1, nr1 + 2, grp, datable);
820 else if (IS_CHEMBOND(func_type))
822 for (j = 0; j < 2; j++)
824 nr1 = interaction->iatoms[i + 1 + j];
825 nr2 = interaction->iatoms[i + 2 - j];
826 if ((*top->atoms.atomname[nr1][0] == 'H')
827 && ((*top->atoms.atomname[nr2][0] == 'O') || (*top->atoms.atomname[nr2][0] == 'N'))
828 && ISINGRP(datable[nr1]) && ISINGRP(datable[nr2]))
830 datable[nr2] |= c_donorMask;
831 add_dh(ddd, nr2, nr1, grp, datable);
838 for (func_type = 0; func_type < F_NRE; func_type++)
840 interaction = &top->idef.il[func_type];
841 for (i = 0; i < interaction->nr;
842 i += interaction_function[top->idef.functype[interaction->iatoms[i]]].nratoms + 1)
845 if (func_type != top->idef.functype[interaction->iatoms[i]])
847 gmx_incons("function type in search_donors");
850 if (interaction_function[func_type].flags & IF_VSITE)
852 nr1 = interaction->iatoms[i + 1];
853 if (*top->atoms.atomname[nr1][0] == 'H')
857 while (!stop && (*top->atoms.atomname[nr2][0] == 'H'))
869 && ((*top->atoms.atomname[nr2][0] == 'O') || (*top->atoms.atomname[nr2][0] == 'N'))
870 && ISINGRP(datable[nr1]) && ISINGRP(datable[nr2]))
872 datable[nr2] |= c_donorMask;
873 add_dh(ddd, nr2, nr1, grp, datable);
883 static t_gridcell*** init_grid(gmx_bool bBox, rvec box[], real rcut, ivec ngrid)
890 for (i = 0; i < DIM; i++)
892 ngrid[i] = static_cast<int>(box[i][i] / (1.2 * rcut));
896 if (!bBox || (ngrid[XX] < 3) || (ngrid[YY] < 3) || (ngrid[ZZ] < 3))
898 for (i = 0; i < DIM; i++)
905 printf("\nWill do grid-search on %dx%dx%d grid, rcut=%3.8f\n", ngrid[XX], ngrid[YY], ngrid[ZZ], rcut);
907 if (((ngrid[XX] * ngrid[YY] * ngrid[ZZ]) * sizeof(grid)) > INT_MAX)
910 "Failed to allocate memory for %d x %d x %d grid points, which is larger than "
911 "the maximum of %zu. "
912 "You are likely either using a box that is too large (box dimensions are %3.8f "
913 "nm x%3.8f nm x%3.8f nm) or a cutoff (%3.8f nm) that is too small.",
917 INT_MAX / sizeof(grid),
923 snew(grid, ngrid[ZZ]);
924 for (z = 0; z < ngrid[ZZ]; z++)
926 snew((grid)[z], ngrid[YY]);
927 for (y = 0; y < ngrid[YY]; y++)
929 snew((grid)[z][y], ngrid[XX]);
935 static void reset_nhbonds(t_donors* ddd)
939 for (i = 0; (i < ddd->nrd); i++)
941 for (j = 0; (j < MAXHH); j++)
943 ddd->nhbonds[i][j] = 0;
948 static void pbc_correct_gem(rvec dx, matrix box, const rvec hbox);
949 static void pbc_in_gridbox(rvec dx, matrix box);
951 static void build_grid(t_hbdata* hb,
962 int i, m, gr, xi, yi, zi, nr;
965 rvec invdelta, dshell;
967 gmx_bool bDoRshell, bInShell;
972 bDoRshell = (rshell > 0);
973 rshell2 = gmx::square(rshell);
977 if (debug && bDebug) \
978 fprintf(debug, "build_grid, line %d, %s = %d\n", __LINE__, #x, x)
980 for (m = 0; m < DIM; m++)
982 hbox[m] = box[m][m] * 0.5;
985 invdelta[m] = ngrid[m] / box[m][m];
986 if (1 / invdelta[m] < rcut)
989 "Your computational box has shrunk too much.\n"
990 "%s can not handle this situation, sorry.\n",
991 gmx::getProgramContext().displayName());
1003 /* resetting atom counts */
1004 for (gr = 0; (gr < grNR); gr++)
1006 for (zi = 0; zi < ngrid[ZZ]; zi++)
1008 for (yi = 0; yi < ngrid[YY]; yi++)
1010 for (xi = 0; xi < ngrid[XX]; xi++)
1012 grid[zi][yi][xi].d[gr].nr = 0;
1013 grid[zi][yi][xi].a[gr].nr = 0;
1019 /* put atoms in grid cells */
1020 for (int acc = 0; acc < 2; acc++)
1033 for (i = 0; (i < nr); i++)
1035 /* check if we are inside the shell */
1036 /* if bDoRshell=FALSE then bInShell=TRUE always */
1041 rvec_sub(x[ad[i]], xshell, dshell);
1044 gmx_bool bDone = FALSE;
1048 for (m = DIM - 1; m >= 0 && bInShell; m--)
1050 if (dshell[m] < -hbox[m])
1053 rvec_inc(dshell, box[m]);
1055 if (dshell[m] >= hbox[m])
1058 dshell[m] -= 2 * hbox[m];
1062 for (m = DIM - 1; m >= 0 && bInShell; m--)
1064 /* if we're outside the cube, we're outside the sphere also! */
1065 if ((dshell[m] > rshell) || (-dshell[m] > rshell))
1071 /* if we're inside the cube, check if we're inside the sphere */
1074 bInShell = norm2(dshell) < rshell2;
1082 pbc_in_gridbox(x[ad[i]], box);
1084 for (m = DIM - 1; m >= 0; m--)
1085 { /* determine grid index of atom */
1086 grididx[m] = static_cast<int>(x[ad[i]][m] * invdelta[m]);
1087 grididx[m] = (grididx[m] + ngrid[m]) % ngrid[m];
1094 range_check(gx, 0, ngrid[XX]);
1095 range_check(gy, 0, ngrid[YY]);
1096 range_check(gz, 0, ngrid[ZZ]);
1100 /* add atom to grid cell */
1103 newgrid = &(grid[gz][gy][gx].a[gr]);
1107 newgrid = &(grid[gz][gy][gx].d[gr]);
1109 if (newgrid->nr >= newgrid->maxnr)
1111 newgrid->maxnr += 10;
1112 DBB(newgrid->maxnr);
1113 srenew(newgrid->atoms, newgrid->maxnr);
1116 newgrid->atoms[newgrid->nr] = ad[i];
1124 static void count_da_grid(const ivec ngrid, t_gridcell*** grid, t_icell danr)
1128 for (gr = 0; (gr < grNR); gr++)
1131 for (zi = 0; zi < ngrid[ZZ]; zi++)
1133 for (yi = 0; yi < ngrid[YY]; yi++)
1135 for (xi = 0; xi < ngrid[XX]; xi++)
1137 danr[gr] += grid[zi][yi][xi].d[gr].nr;
1145 * Without a box, the grid is 1x1x1, so all loops are 1 long.
1146 * With a rectangular box (bTric==FALSE) all loops are 3 long.
1147 * With a triclinic box all loops are 3 long, except when a cell is
1148 * located next to one of the box edges which is not parallel to the
1149 * x/y-plane, in that case all cells in a line or layer are searched.
1150 * This could be implemented slightly more efficient, but the code
1151 * would get much more complicated.
1153 static inline int grid_loop_begin(int n, int x, gmx_bool bTric, gmx_bool bEdge)
1155 return ((n == 1) ? x : bTric && bEdge ? 0 : (x - 1));
1157 static inline int grid_loop_end(int n, int x, gmx_bool bTric, gmx_bool bEdge)
1159 return ((n == 1) ? x : bTric && bEdge ? (n - 1) : (x + 1));
1161 static inline int grid_mod(int j, int n)
1163 return (j + n) % (n);
1166 static void dump_grid(FILE* fp, ivec ngrid, t_gridcell*** grid)
1168 int gr, x, y, z, sum[grNR];
1170 fprintf(fp, "grid %dx%dx%d\n", ngrid[XX], ngrid[YY], ngrid[ZZ]);
1171 for (gr = 0; gr < grNR; gr++)
1174 fprintf(fp, "GROUP %d (%s)\n", gr, grpnames[gr]);
1175 for (z = 0; z < ngrid[ZZ]; z += 2)
1177 fprintf(fp, "Z=%d,%d\n", z, z + 1);
1178 for (y = 0; y < ngrid[YY]; y++)
1180 for (x = 0; x < ngrid[XX]; x++)
1182 fprintf(fp, "%3d", grid[x][y][z].d[gr].nr);
1183 sum[gr] += grid[z][y][x].d[gr].nr;
1184 fprintf(fp, "%3d", grid[x][y][z].a[gr].nr);
1185 sum[gr] += grid[z][y][x].a[gr].nr;
1188 if ((z + 1) < ngrid[ZZ])
1190 for (x = 0; x < ngrid[XX]; x++)
1192 fprintf(fp, "%3d", grid[z + 1][y][x].d[gr].nr);
1193 sum[gr] += grid[z + 1][y][x].d[gr].nr;
1194 fprintf(fp, "%3d", grid[z + 1][y][x].a[gr].nr);
1195 sum[gr] += grid[z + 1][y][x].a[gr].nr;
1202 fprintf(fp, "TOTALS:");
1203 for (gr = 0; gr < grNR; gr++)
1205 fprintf(fp, " %d=%d", gr, sum[gr]);
1210 /* New GMX record! 5 * in a row. Congratulations!
1211 * Sorry, only four left.
1213 static void free_grid(const ivec ngrid, t_gridcell**** grid)
1216 t_gridcell*** g = *grid;
1218 for (z = 0; z < ngrid[ZZ]; z++)
1220 for (y = 0; y < ngrid[YY]; y++)
1230 static void pbc_correct_gem(rvec dx, matrix box, const rvec hbox)
1233 gmx_bool bDone = FALSE;
1237 for (m = DIM - 1; m >= 0; m--)
1239 if (dx[m] < -hbox[m])
1242 rvec_inc(dx, box[m]);
1244 if (dx[m] >= hbox[m])
1247 rvec_dec(dx, box[m]);
1253 static void pbc_in_gridbox(rvec dx, matrix box)
1256 gmx_bool bDone = FALSE;
1260 for (m = DIM - 1; m >= 0; m--)
1265 rvec_inc(dx, box[m]);
1267 if (dx[m] >= box[m][m])
1270 rvec_dec(dx, box[m]);
1276 /* Added argument r2cut, changed contact and implemented
1277 * use of second cut-off.
1278 * - Erik Marklund, June 29, 2006
1280 static int is_hbond(t_hbdata* hb,
1300 rvec r_da, r_ha, r_dh;
1301 real rc2, r2c2, rda2, rha2, ca;
1302 gmx_bool HAinrange = FALSE; /* If !bDA. Needed for returning hbDist in a correct way. */
1303 gmx_bool daSwap = FALSE;
1310 if (((id = donor_index(&hb->d, grpd, d)) == NOTSET) || (acceptor_index(&hb->a, grpa, a) == NOTSET))
1316 r2c2 = r2cut * r2cut;
1318 rvec_sub(x[d], x[a], r_da);
1319 /* Insert projection code here */
1321 if (bMerge && d > a && isInterchangable(hb, d, a, grpd, grpa))
1323 /* Then this hbond/contact will be found again, or it has already been found. */
1329 && isInterchangable(hb, d, a, grpd, grpa)) /* acceptor is also a donor and vice versa? */
1330 { /* return hbNo; */
1331 daSwap = TRUE; /* If so, then their history should be filed with donor and acceptor swapped. */
1333 pbc_correct_gem(r_da, box, hbox);
1335 rda2 = iprod(r_da, r_da);
1339 if (daSwap && grpa == grpd)
1347 else if (rda2 < r2c2)
1358 if (bDA && (rda2 > rc2))
1363 for (h = 0; (h < hb->d.nhydro[id]); h++)
1365 hh = hb->d.hydro[id][h];
1369 rvec_sub(x[hh], x[a], r_ha);
1372 pbc_correct_gem(r_ha, box, hbox);
1374 rha2 = iprod(r_ha, r_ha);
1377 if (bDA || (rha2 <= rc2))
1379 rvec_sub(x[d], x[hh], r_dh);
1382 pbc_correct_gem(r_dh, box, hbox);
1389 ca = cos_angle(r_dh, r_da);
1390 /* if angle is smaller, cos is larger */
1394 *d_ha = std::sqrt(bDA ? rda2 : rha2);
1395 *ang = std::acos(ca);
1400 if (bDA || HAinrange)
1410 /* Merging is now done on the fly, so do_merge is most likely obsolete now.
1411 * Will do some more testing before removing the function entirely.
1412 * - Erik Marklund, MAY 10 2010 */
1413 static void do_merge(t_hbdata* hb, int ntmp, bool htmp[], bool gtmp[], t_hbond* hb0, t_hbond* hb1)
1415 /* Here we need to make sure we're treating periodicity in
1416 * the right way for the geminate recombination kinetics. */
1418 int m, mm, n00, n01, nn0, nnframes;
1420 /* Decide where to start from when merging */
1423 nn0 = std::min(n00, n01);
1424 nnframes = std::max(n00 + hb0->nframes, n01 + hb1->nframes) - nn0;
1425 /* Initiate tmp arrays */
1426 for (m = 0; (m < ntmp); m++)
1431 /* Fill tmp arrays with values due to first HB */
1432 /* Once again '<' had to be replaced with '<='
1433 to catch the last frame in which the hbond
1435 - Erik Marklund, June 1, 2006 */
1436 for (m = 0; (m <= hb0->nframes); m++)
1439 htmp[mm] = is_hb(hb0->h[0], m);
1441 for (m = 0; (m <= hb0->nframes); m++)
1444 gtmp[mm] = is_hb(hb0->g[0], m);
1447 for (m = 0; (m <= hb1->nframes); m++)
1450 htmp[mm] = htmp[mm] || is_hb(hb1->h[0], m);
1451 gtmp[mm] = gtmp[mm] || is_hb(hb1->g[0], m);
1453 /* Reallocate target array */
1454 if (nnframes > hb0->maxframes)
1456 srenew(hb0->h[0], 4 + nnframes / hb->wordlen);
1457 srenew(hb0->g[0], 4 + nnframes / hb->wordlen);
1460 /* Copy temp array to target array */
1461 for (m = 0; (m <= nnframes); m++)
1463 _set_hb(hb0->h[0], m, htmp[m]);
1464 _set_hb(hb0->g[0], m, gtmp[m]);
1467 /* Set scalar variables */
1469 hb0->maxframes = nnframes;
1472 static void merge_hb(t_hbdata* hb, gmx_bool bTwo, gmx_bool bContact)
1474 int i, inrnew, indnew, j, ii, jj, id, ia, ntmp;
1479 indnew = hb->nrdist;
1481 /* Check whether donors are also acceptors */
1482 printf("Merging hbonds with Acceptor and Donor swapped\n");
1484 ntmp = 2 * hb->max_frames;
1487 for (i = 0; (i < hb->d.nrd); i++)
1489 fprintf(stderr, "\r%d/%d", i + 1, hb->d.nrd);
1492 ii = hb->a.aptr[id];
1493 for (j = 0; (j < hb->a.nra); j++)
1496 jj = hb->d.dptr[ia];
1497 if ((id != ia) && (ii != NOTSET) && (jj != NOTSET)
1498 && (!bTwo || (hb->d.grp[i] != hb->a.grp[j])))
1500 hb0 = hb->hbmap[i][j];
1501 hb1 = hb->hbmap[jj][ii];
1502 if (hb0 && hb1 && ISHB(hb0->history[0]) && ISHB(hb1->history[0]))
1504 do_merge(hb, ntmp, htmp, gtmp, hb0, hb1);
1505 if (ISHB(hb1->history[0]))
1509 else if (ISDIST(hb1->history[0]))
1515 gmx_incons("No contact history");
1519 gmx_incons("Neither hydrogen bond nor distance");
1523 hb1->h[0] = nullptr;
1524 hb1->g[0] = nullptr;
1525 hb1->history[0] = hbNo;
1530 fprintf(stderr, "\n");
1531 printf("- Reduced number of hbonds from %d to %d\n", hb->nrhb, inrnew);
1532 printf("- Reduced number of distances from %d to %d\n", hb->nrdist, indnew);
1534 hb->nrdist = indnew;
1539 static void do_nhb_dist(FILE* fp, t_hbdata* hb, real t)
1541 int i, j, k, n_bound[MAXHH], nbtot;
1543 /* Set array to 0 */
1544 for (k = 0; (k < MAXHH); k++)
1548 /* Loop over possible donors */
1549 for (i = 0; (i < hb->d.nrd); i++)
1551 for (j = 0; (j < hb->d.nhydro[i]); j++)
1553 n_bound[hb->d.nhbonds[i][j]]++;
1556 fprintf(fp, "%12.5e", t);
1558 for (k = 0; (k < MAXHH); k++)
1560 fprintf(fp, " %8d", n_bound[k]);
1561 nbtot += n_bound[k] * k;
1563 fprintf(fp, " %8d\n", nbtot);
1566 static void do_hblife(const char* fn, t_hbdata* hb, gmx_bool bMerge, gmx_bool bContact, const gmx_output_env_t* oenv)
1569 const char* leg[] = { "p(t)", "t p(t)" };
1571 int i, j, j0, k, m, nh, ihb, ohb, nhydro, ndump = 0;
1572 int nframes = hb->nframes;
1575 double sum, integral;
1578 snew(h, hb->maxhydro);
1579 snew(histo, nframes + 1);
1580 /* Total number of hbonds analyzed here */
1581 for (i = 0; (i < hb->d.nrd); i++)
1583 for (k = 0; (k < hb->a.nra); k++)
1585 hbh = hb->hbmap[i][k];
1603 for (m = 0; (m < hb->maxhydro); m++)
1607 h[nhydro++] = bContact ? hbh->g[m] : hbh->h[m];
1611 for (nh = 0; (nh < nhydro); nh++)
1616 for (j = 0; (j <= hbh->nframes); j++)
1618 ihb = static_cast<int>(is_hb(h[nh], j));
1619 if (debug && (ndump < 10))
1621 fprintf(debug, "%5d %5d\n", j, ihb);
1641 fprintf(stderr, "\n");
1644 fp = xvgropen(fn, "Uninterrupted contact lifetime", output_env_get_xvgr_tlabel(oenv), "()", oenv);
1649 fn, "Uninterrupted hydrogen bond lifetime", output_env_get_xvgr_tlabel(oenv), "()", oenv);
1652 xvgr_legend(fp, asize(leg), leg, oenv);
1654 while ((j0 > 0) && (histo[j0] == 0))
1659 for (i = 0; (i <= j0); i++)
1663 dt = hb->time[1] - hb->time[0];
1666 for (i = 1; (i <= j0); i++)
1668 t = hb->time[i] - hb->time[0] - 0.5 * dt;
1669 x1 = t * histo[i] / sum;
1670 fprintf(fp, "%8.3f %10.3e %10.3e\n", t, histo[i] / sum, x1);
1675 printf("%s lifetime = %.2f ps\n", bContact ? "Contact" : "HB", integral);
1676 printf("Note that the lifetime obtained in this manner is close to useless\n");
1677 printf("Use the -ac option instead and check the Forward lifetime\n");
1678 please_cite(stdout, "Spoel2006b");
1683 static void dump_ac(t_hbdata* hb, gmx_bool oneHB, int nDump)
1686 int i, j, k, m, nd, ihb, idist;
1687 int nframes = hb->nframes;
1695 fp = gmx_ffopen("debug-ac.xvg", "w");
1696 for (j = 0; (j < nframes); j++)
1698 fprintf(fp, "%10.3f", hb->time[j]);
1699 for (i = nd = 0; (i < hb->d.nrd) && (nd < nDump); i++)
1701 for (k = 0; (k < hb->a.nra) && (nd < nDump); k++)
1705 hbh = hb->hbmap[i][k];
1710 ihb = static_cast<int>(is_hb(hbh->h[0], j));
1711 idist = static_cast<int>(is_hb(hbh->g[0], j));
1717 for (m = 0; (m < hb->maxhydro) && !ihb; m++)
1719 ihb = static_cast<int>((ihb != 0)
1720 || (((hbh->h[m]) != nullptr) && is_hb(hbh->h[m], j)));
1721 idist = static_cast<int>((idist != 0)
1722 || (((hbh->g[m]) != nullptr) && is_hb(hbh->g[m], j)));
1724 /* This is not correct! */
1725 /* What isn't correct? -Erik M */
1730 fprintf(fp, " %1d-%1d", ihb, idist);
1740 static real calc_dg(real tau, real temp)
1744 kbt = gmx::c_boltz * temp;
1751 return kbt * std::log(kbt * tau / gmx::c_planck);
1757 int n0, n1, nparams, ndelta;
1759 real *t, *ct, *nt, *kt, *sigma_ct, *sigma_nt, *sigma_kt;
1762 static real compute_weighted_rates(int n,
1779 real kkk = 0, kkp = 0, kk2 = 0, kp2 = 0, chi2;
1784 for (i = 0; (i < n); i++)
1786 if (t[i] >= fit_start)
1799 tl.sigma_ct = sigma_ct;
1800 tl.sigma_nt = sigma_nt;
1801 tl.sigma_kt = sigma_kt;
1805 chi2 = 0; /*optimize_luzar_parameters(debug, &tl, 1000, 1e-3); */
1807 *kp = tl.kkk[1] = *kp;
1809 for (j = 0; (j < NK); j++)
1813 kk2 += gmx::square(tl.kkk[0]);
1814 kp2 += gmx::square(tl.kkk[1]);
1817 *sigma_k = std::sqrt(kk2 / NK - gmx::square(kkk / NK));
1818 *sigma_kp = std::sqrt(kp2 / NK - gmx::square(kkp / NK));
1823 void analyse_corr(int n,
1835 real k = 1, kp = 1, kow = 1;
1836 real Q = 0, chi2, tau_hb, dtau, tau_rlx, e_1, sigma_k, sigma_kp, ddg;
1837 double tmp, sn2 = 0, sc2 = 0, sk2 = 0, scn = 0, sck = 0, snk = 0;
1838 gmx_bool bError = (sigma_ct != nullptr) && (sigma_nt != nullptr) && (sigma_kt != nullptr);
1840 for (i0 = 0; (i0 < n - 2) && ((t[i0] - t[0]) < fit_start); i0++) {}
1843 for (i = i0; (i < n); i++)
1845 sc2 += gmx::square(ct[i]);
1846 sn2 += gmx::square(nt[i]);
1847 sk2 += gmx::square(kt[i]);
1848 sck += ct[i] * kt[i];
1849 snk += nt[i] * kt[i];
1850 scn += ct[i] * nt[i];
1852 printf("Hydrogen bond thermodynamics at T = %g K\n", temp);
1853 tmp = (sn2 * sc2 - gmx::square(scn));
1854 if ((tmp > 0) && (sn2 > 0))
1856 k = (sn2 * sck - scn * snk) / tmp;
1857 kp = (k * scn - snk) / sn2;
1861 for (i = i0; (i < n); i++)
1863 chi2 += gmx::square(k * ct[i] - kp * nt[i] - kt[i]);
1865 compute_weighted_rates(
1866 n, t, ct, nt, kt, sigma_ct, sigma_nt, sigma_kt, &k, &kp, &sigma_k, &sigma_kp, fit_start);
1867 Q = 0; /* quality_of_fit(chi2, 2);*/
1868 ddg = gmx::c_boltz * temp * sigma_k / k;
1869 printf("Fitting paramaters chi^2 = %10g, Quality of fit = %10g\n", chi2, Q);
1870 printf("The Rate and Delta G are followed by an error estimate\n");
1871 printf("----------------------------------------------------------\n"
1872 "Type Rate (1/ps) Sigma Time (ps) DG (kJ/mol) Sigma\n");
1873 printf("Forward %10.3f %6.2f %8.3f %10.3f %6.2f\n",
1877 calc_dg(1 / k, temp),
1879 ddg = gmx::c_boltz * temp * sigma_kp / kp;
1880 printf("Backward %10.3f %6.2f %8.3f %10.3f %6.2f\n",
1884 calc_dg(1 / kp, temp),
1890 for (i = i0; (i < n); i++)
1892 chi2 += gmx::square(k * ct[i] - kp * nt[i] - kt[i]);
1894 printf("Fitting parameters chi^2 = %10g\nQ = %10g\n", chi2, Q);
1895 printf("--------------------------------------------------\n"
1896 "Type Rate (1/ps) Time (ps) DG (kJ/mol) Chi^2\n");
1897 printf("Forward %10.3f %8.3f %10.3f %10g\n", k, 1 / k, calc_dg(1 / k, temp), chi2);
1898 printf("Backward %10.3f %8.3f %10.3f\n", kp, 1 / kp, calc_dg(1 / kp, temp));
1903 kow = 2 * sck / sc2;
1904 printf("One-way %10.3f %s%8.3f %10.3f\n",
1908 calc_dg(1 / kow, temp));
1912 printf(" - Numerical problems computing HB thermodynamics:\n"
1913 "sc2 = %g sn2 = %g sk2 = %g sck = %g snk = %g scn = %g\n",
1921 /* Determine integral of the correlation function */
1922 tau_hb = evaluate_integral(n, t, ct, nullptr, (t[n - 1] - t[0]) / 2, &dtau);
1923 printf("Integral %10.3f %s%8.3f %10.3f\n",
1927 calc_dg(tau_hb, temp));
1928 e_1 = std::exp(-1.0);
1929 for (i = 0; (i < n - 2); i++)
1931 if ((ct[i] > e_1) && (ct[i + 1] <= e_1))
1938 /* Determine tau_relax from linear interpolation */
1939 tau_rlx = t[i] - t[0] + (e_1 - ct[i]) * (t[i + 1] - t[i]) / (ct[i + 1] - ct[i]);
1940 printf("Relaxation %10.3f %8.3f %s%10.3f\n",
1944 calc_dg(tau_rlx, temp));
1949 printf("Correlation functions too short to compute thermodynamics\n");
1953 void compute_derivative(int nn, const real x[], const real y[], real dydx[])
1957 /* Compute k(t) = dc(t)/dt */
1958 for (j = 1; (j < nn - 1); j++)
1960 dydx[j] = (y[j + 1] - y[j - 1]) / (x[j + 1] - x[j - 1]);
1962 /* Extrapolate endpoints */
1963 dydx[0] = 2 * dydx[1] - dydx[2];
1964 dydx[nn - 1] = 2 * dydx[nn - 2] - dydx[nn - 3];
1967 static void normalizeACF(real* ct, real* gt, int nhb, int len)
1969 real ct_fac, gt_fac = 0;
1972 /* Xu and Berne use the same normalization constant */
1974 ct_fac = 1.0 / ct[0];
1980 printf("Normalization for c(t) = %g for gh(t) = %g\n", ct_fac, gt_fac);
1981 for (i = 0; i < len; i++)
1991 static void do_hbac(const char* fn,
1999 const gmx_output_env_t* oenv,
2003 int i, j, k, m, ihb, idist, n2, nn;
2005 const char* legLuzar[] = { "Ac\\sfin sys\\v{}\\z{}(t)",
2007 "Cc\\scontact,hb\\v{}\\z{}(t)",
2008 "-dAc\\sfs\\v{}\\z{}/dt" };
2009 gmx_bool bNorm = FALSE;
2011 real * rhbex = nullptr, *ht, *gt, *ght, *dght, *kt;
2012 real * ct, tail, tail2, dtail, *cct;
2013 const real tol = 1e-3;
2014 int nframes = hb->nframes;
2015 unsigned int **h = nullptr, **g = nullptr;
2016 int nh, nhbonds, nhydro;
2019 int* dondata = nullptr;
2029 const bool bOMP = GMX_OPENMP;
2031 printf("Doing autocorrelation ");
2034 printf("according to the theory of Luzar and Chandler.\n");
2037 /* build hbexist matrix in reals for autocorr */
2038 /* Allocate memory for computing ACF (rhbex) and aggregating the ACF (ct) */
2040 while (n2 < nframes)
2047 if (acType != AC_NN || bOMP)
2049 snew(h, hb->maxhydro);
2050 snew(g, hb->maxhydro);
2053 /* Dump hbonds for debugging */
2054 dump_ac(hb, bMerge || bContact, nDump);
2056 /* Total number of hbonds analyzed here */
2059 if (acType != AC_LUZAR && bOMP)
2061 nThreads = std::min((nThreads <= 0) ? INT_MAX : nThreads, gmx_omp_get_max_threads());
2063 gmx_omp_set_num_threads(nThreads);
2064 snew(dondata, nThreads);
2065 for (i = 0; i < nThreads; i++)
2069 printf("ACF calculations parallelized with OpenMP using %i threads.\n"
2070 "Expect close to linear scaling over this donor-loop.\n",
2073 fprintf(stderr, "Donors: [thread no]\n");
2076 for (i = 0; i < nThreads; i++)
2078 snprintf(tmpstr, 7, "[%i]", i);
2079 fprintf(stderr, "%-7s", tmpstr);
2082 fprintf(stderr, "\n");
2087 snew(rhbex, 2 * n2);
2097 for (i = 0; (i < hb->d.nrd); i++)
2099 for (k = 0; (k < hb->a.nra); k++)
2102 hbh = hb->hbmap[i][k];
2106 if (bMerge || bContact)
2108 if (ISHB(hbh->history[0]))
2117 for (m = 0; (m < hb->maxhydro); m++)
2119 if (bContact ? ISDIST(hbh->history[m]) : ISHB(hbh->history[m]))
2121 g[nhydro] = hbh->g[m];
2122 h[nhydro] = hbh->h[m];
2128 int nf = hbh->nframes;
2129 for (nh = 0; (nh < nhydro); nh++)
2131 int nrint = bContact ? hb->nrdist : hb->nrhb;
2132 if ((((nhbonds + 1) % 10) == 0) || (nhbonds + 1 == nrint))
2134 fprintf(stderr, "\rACF %d/%d", nhbonds + 1, nrint);
2138 for (j = 0; (j < nframes); j++)
2142 ihb = static_cast<int>(is_hb(h[nh], j));
2143 idist = static_cast<int>(is_hb(g[nh], j));
2150 /* For contacts: if a second cut-off is provided, use it,
2151 * otherwise use g(t) = 1-h(t) */
2152 if (!R2 && bContact)
2158 gt[j] = idist * (1 - ihb);
2164 /* The autocorrelation function is normalized after summation only */
2165 low_do_autocorr(nullptr,
2172 hb->time[1] - hb->time[0],
2182 /* Cross correlation analysis for thermodynamics */
2183 for (j = nframes; (j < n2); j++)
2189 cross_corr(n2, ht, gt, dght);
2191 for (j = 0; (j < nn); j++)
2200 fprintf(stderr, "\n");
2203 normalizeACF(ct, ght, static_cast<int>(nhb), nn);
2205 /* Determine tail value for statistics */
2208 for (j = nn / 2; (j < nn); j++)
2211 tail2 += ct[j] * ct[j];
2213 tail /= (nn - int{ nn / 2 });
2214 tail2 /= (nn - int{ nn / 2 });
2215 dtail = std::sqrt(tail2 - tail * tail);
2217 /* Check whether the ACF is long enough */
2220 printf("\nWARNING: Correlation function is probably not long enough\n"
2221 "because the standard deviation in the tail of C(t) > %g\n"
2222 "Tail value (average C(t) over second half of acf): %g +/- %g\n",
2227 for (j = 0; (j < nn); j++)
2230 ct[j] = (cct[j] - tail) / (1 - tail);
2232 /* Compute negative derivative k(t) = -dc(t)/dt */
2233 compute_derivative(nn, hb->time, ct, kt);
2234 for (j = 0; (j < nn); j++)
2242 fp = xvgropen(fn, "Contact Autocorrelation", output_env_get_xvgr_tlabel(oenv), "C(t)", oenv);
2246 fp = xvgropen(fn, "Hydrogen Bond Autocorrelation", output_env_get_xvgr_tlabel(oenv), "C(t)", oenv);
2248 xvgr_legend(fp, asize(legLuzar), legLuzar, oenv);
2251 for (j = 0; (j < nn); j++)
2253 fprintf(fp, "%10g %10g %10g %10g %10g\n", hb->time[j] - hb->time[0], ct[j], cct[j], ght[j], kt[j]);
2257 analyse_corr(nn, hb->time, ct, ght, kt, nullptr, nullptr, nullptr, fit_start, temp);
2259 do_view(oenv, fn, nullptr);
2270 static void init_hbframe(t_hbdata* hb, int nframes, real t)
2274 hb->time[nframes] = t;
2275 hb->nhb[nframes] = 0;
2276 hb->ndist[nframes] = 0;
2277 for (i = 0; (i < max_hx); i++)
2279 hb->nhx[nframes][i] = 0;
2283 static FILE* open_donor_properties_file(const char* fn, t_hbdata* hb, const gmx_output_env_t* oenv)
2286 const char* leg[] = { "Nbound", "Nfree" };
2293 fp = xvgropen(fn, "Donor properties", output_env_get_xvgr_tlabel(oenv), "Number", oenv);
2294 xvgr_legend(fp, asize(leg), leg, oenv);
2299 static void analyse_donor_properties(FILE* fp, t_hbdata* hb, int nframes, real t)
2301 int i, j, k, nbound, nb, nhtot;
2309 for (i = 0; (i < hb->d.nrd); i++)
2311 for (k = 0; (k < hb->d.nhydro[i]); k++)
2315 for (j = 0; (j < hb->a.nra) && (nb == 0); j++)
2317 if (hb->hbmap[i][j] && hb->hbmap[i][j]->h[k] && is_hb(hb->hbmap[i][j]->h[k], nframes))
2325 fprintf(fp, "%10.3e %6d %6d\n", t, nbound, nhtot - nbound);
2328 static void dump_hbmap(t_hbdata* hb,
2336 const t_atoms* atoms)
2339 int ddd, hhh, aaa, i, j, k, m, grp;
2340 char ds[32], hs[32], as[32];
2343 fp = opt2FILE("-hbn", nfile, fnm, "w");
2344 if (opt2bSet("-g", nfile, fnm))
2346 fplog = gmx_ffopen(opt2fn("-g", nfile, fnm), "w");
2347 fprintf(fplog, "# %10s %12s %12s\n", "Donor", "Hydrogen", "Acceptor");
2353 for (grp = gr0; grp <= (bTwo ? gr1 : gr0); grp++)
2355 fprintf(fp, "[ %s ]", grpnames[grp]);
2356 for (i = 0; i < isize[grp]; i++)
2358 fprintf(fp, (i % 15) ? " " : "\n");
2359 fprintf(fp, " %4d", index[grp][i] + 1);
2365 fprintf(fp, "[ donors_hydrogens_%s ]\n", grpnames[grp]);
2366 for (i = 0; (i < hb->d.nrd); i++)
2368 if (hb->d.grp[i] == grp)
2370 for (j = 0; (j < hb->d.nhydro[i]); j++)
2372 fprintf(fp, " %4d %4d", hb->d.don[i] + 1, hb->d.hydro[i][j] + 1);
2378 fprintf(fp, "[ acceptors_%s ]", grpnames[grp]);
2379 for (i = 0; (i < hb->a.nra); i++)
2381 if (hb->a.grp[i] == grp)
2383 fprintf(fp, (i % 15 && !first) ? " " : "\n");
2384 fprintf(fp, " %4d", hb->a.acc[i] + 1);
2393 fprintf(fp, bContact ? "[ contacts_%s-%s ]\n" : "[ hbonds_%s-%s ]\n", grpnames[0], grpnames[1]);
2397 fprintf(fp, bContact ? "[ contacts_%s ]" : "[ hbonds_%s ]\n", grpnames[0]);
2400 for (i = 0; (i < hb->d.nrd); i++)
2403 for (k = 0; (k < hb->a.nra); k++)
2406 for (m = 0; (m < hb->d.nhydro[i]); m++)
2408 if (hb->hbmap[i][k] && ISHB(hb->hbmap[i][k]->history[m]))
2410 sprintf(ds, "%s", mkatomname(atoms, ddd));
2411 sprintf(as, "%s", mkatomname(atoms, aaa));
2414 fprintf(fp, " %6d %6d\n", ddd + 1, aaa + 1);
2417 fprintf(fplog, "%12s %12s\n", ds, as);
2422 hhh = hb->d.hydro[i][m];
2423 sprintf(hs, "%s", mkatomname(atoms, hhh));
2424 fprintf(fp, " %6d %6d %6d\n", ddd + 1, hhh + 1, aaa + 1);
2427 fprintf(fplog, "%12s %12s %12s\n", ds, hs, as);
2441 /* sync_hbdata() updates the parallel t_hbdata p_hb using hb as template.
2442 * It mimics add_frames() and init_frame() to some extent. */
2443 static void sync_hbdata(t_hbdata* p_hb, int nframes)
2445 if (nframes >= p_hb->max_frames)
2447 p_hb->max_frames += 4096;
2448 srenew(p_hb->nhb, p_hb->max_frames);
2449 srenew(p_hb->ndist, p_hb->max_frames);
2450 srenew(p_hb->n_bound, p_hb->max_frames);
2451 srenew(p_hb->nhx, p_hb->max_frames);
2454 srenew(p_hb->danr, p_hb->max_frames);
2456 std::memset(&(p_hb->nhb[nframes]), 0, sizeof(int) * (p_hb->max_frames - nframes));
2457 std::memset(&(p_hb->ndist[nframes]), 0, sizeof(int) * (p_hb->max_frames - nframes));
2458 p_hb->nhb[nframes] = 0;
2459 p_hb->ndist[nframes] = 0;
2461 p_hb->nframes = nframes;
2463 std::memset(&(p_hb->nhx[nframes]), 0, sizeof(int) * max_hx); /* zero the helix count for this frame */
2466 int gmx_hbond(int argc, char* argv[])
2468 const char* desc[] = {
2469 "[THISMODULE] computes and analyzes hydrogen bonds. Hydrogen bonds are",
2470 "determined based on cutoffs for the angle Hydrogen - Donor - Acceptor",
2471 "(zero is extended) and the distance Donor - Acceptor",
2472 "(or Hydrogen - Acceptor using [TT]-noda[tt]).",
2473 "OH and NH groups are regarded as donors, O is an acceptor always,",
2474 "N is an acceptor by default, but this can be switched using",
2475 "[TT]-nitacc[tt]. Dummy hydrogen atoms are assumed to be connected",
2476 "to the first preceding non-hydrogen atom.[PAR]",
2478 "You need to specify two groups for analysis, which must be either",
2479 "identical or non-overlapping. All hydrogen bonds between the two",
2480 "groups are analyzed.[PAR]",
2482 "If you set [TT]-shell[tt], you will be asked for an additional index group",
2483 "which should contain exactly one atom. In this case, only hydrogen",
2484 "bonds between atoms within the shell distance from the one atom are",
2487 "With option -ac, rate constants for hydrogen bonding can be derived with the",
2488 "model of Luzar and Chandler (Nature 379:55, 1996; J. Chem. Phys. 113:23, 2000).",
2489 "If contact kinetics are analyzed by using the -contact option, then",
2490 "n(t) can be defined as either all pairs that are not within contact distance r at time t",
2491 "(corresponding to leaving the -r2 option at the default value 0) or all pairs that",
2492 "are within distance r2 (corresponding to setting a second cut-off value with option -r2).",
2493 "See mentioned literature for more details and definitions.",
2496 /* "It is also possible to analyse specific hydrogen bonds with",
2497 "[TT]-sel[tt]. This index file must contain a group of atom triplets",
2498 "Donor Hydrogen Acceptor, in the following way::",
2505 "Note that the triplets need not be on separate lines.",
2506 "Each atom triplet specifies a hydrogen bond to be analyzed,",
2507 "note also that no check is made for the types of atoms.[PAR]",
2512 " * [TT]-num[tt]: number of hydrogen bonds as a function of time.",
2513 " * [TT]-ac[tt]: average over all autocorrelations of the existence",
2514 " functions (either 0 or 1) of all hydrogen bonds.",
2515 " * [TT]-dist[tt]: distance distribution of all hydrogen bonds.",
2516 " * [TT]-ang[tt]: angle distribution of all hydrogen bonds.",
2517 " * [TT]-hx[tt]: the number of n-n+i hydrogen bonds as a function of time",
2518 " where n and n+i stand for residue numbers and i ranges from 0 to 6.",
2519 " This includes the n-n+3, n-n+4 and n-n+5 hydrogen bonds associated",
2520 " with helices in proteins.",
2521 " * [TT]-hbn[tt]: all selected groups, donors, hydrogens and acceptors",
2522 " for selected groups, all hydrogen bonded atoms from all groups and",
2523 " all solvent atoms involved in insertion.",
2524 " * [TT]-hbm[tt]: existence matrix for all hydrogen bonds over all",
2525 " frames, this also contains information on solvent insertion",
2526 " into hydrogen bonds. Ordering is identical to that in [TT]-hbn[tt]",
2528 " * [TT]-dan[tt]: write out the number of donors and acceptors analyzed for",
2529 " each timeframe. This is especially useful when using [TT]-shell[tt].",
2530 " * [TT]-nhbdist[tt]: compute the number of HBonds per hydrogen in order to",
2531 " compare results to Raman Spectroscopy.",
2533 "Note: options [TT]-ac[tt], [TT]-life[tt], [TT]-hbn[tt] and [TT]-hbm[tt]",
2534 "require an amount of memory proportional to the total numbers of donors",
2535 "times the total number of acceptors in the selected group(s)."
2538 static real acut = 30, abin = 1, rcut = 0.35, r2cut = 0, rbin = 0.005, rshell = -1;
2539 static real maxnhb = 0, fit_start = 1, fit_end = 60, temp = 298.15;
2540 static gmx_bool bNitAcc = TRUE, bDA = TRUE, bMerge = TRUE;
2541 static int nDump = 0;
2542 static int nThreads = 0;
2544 static gmx_bool bContact = FALSE;
2548 { "-a", FALSE, etREAL, { &acut }, "Cutoff angle (degrees, Hydrogen - Donor - Acceptor)" },
2549 { "-r", FALSE, etREAL, { &rcut }, "Cutoff radius (nm, X - Acceptor, see next option)" },
2554 "Use distance Donor-Acceptor (if TRUE) or Hydrogen-Acceptor (FALSE)" },
2559 "Second cutoff radius. Mainly useful with [TT]-contact[tt] and [TT]-ac[tt]" },
2560 { "-abin", FALSE, etREAL, { &abin }, "Binwidth angle distribution (degrees)" },
2561 { "-rbin", FALSE, etREAL, { &rbin }, "Binwidth distance distribution (nm)" },
2562 { "-nitacc", FALSE, etBOOL, { &bNitAcc }, "Regard nitrogen atoms as acceptors" },
2567 "Do not look for hydrogen bonds, but merely for contacts within the cut-off distance" },
2572 "when > 0, only calculate hydrogen bonds within # nm shell around "
2578 "Time (ps) from which to start fitting the correlation functions in order to obtain the "
2579 "forward and backward rate constants for HB breaking and formation. With [TT]-gemfit[tt] "
2580 "we suggest [TT]-fitstart 0[tt]" },
2585 "Time (ps) to which to stop fitting the correlation functions in order to obtain the "
2586 "forward and backward rate constants for HB breaking and formation (only with "
2587 "[TT]-gemfit[tt])" },
2592 "Temperature (K) for computing the Gibbs energy corresponding to HB breaking and "
2598 "Dump the first N hydrogen bond ACFs in a single [REF].xvg[ref] file for debugging" },
2603 "Theoretical maximum number of hydrogen bonds used for normalizing HB autocorrelation "
2604 "function. Can be useful in case the program estimates it wrongly" },
2609 "H-bonds between the same donor and acceptor, but with different hydrogen are treated as "
2610 "a single H-bond. Mainly important for the ACF." },
2616 "Number of threads used for the parallel loop over autocorrelations. nThreads <= 0 means "
2617 "maximum number of threads. Requires linking with OpenMP. The number of threads is "
2618 "limited by the number of cores (before OpenMP v.3 ) or environment variable "
2619 "OMP_THREAD_LIMIT (OpenMP v.3)" },
2622 const char* bugs[] = {
2623 "The option [TT]-sel[tt] that used to work on selected hbonds is out of order, and "
2624 "therefore not available for the time being."
2626 t_filenm fnm[] = { { efTRX, "-f", nullptr, ffREAD },
2627 { efTPR, nullptr, nullptr, ffREAD },
2628 { efNDX, nullptr, nullptr, ffOPTRD },
2629 /* { efNDX, "-sel", "select", ffOPTRD },*/
2630 { efXVG, "-num", "hbnum", ffWRITE },
2631 { efLOG, "-g", "hbond", ffOPTWR },
2632 { efXVG, "-ac", "hbac", ffOPTWR },
2633 { efXVG, "-dist", "hbdist", ffOPTWR },
2634 { efXVG, "-ang", "hbang", ffOPTWR },
2635 { efXVG, "-hx", "hbhelix", ffOPTWR },
2636 { efNDX, "-hbn", "hbond", ffOPTWR },
2637 { efXPM, "-hbm", "hbmap", ffOPTWR },
2638 { efXVG, "-don", "donor", ffOPTWR },
2639 { efXVG, "-dan", "danum", ffOPTWR },
2640 { efXVG, "-life", "hblife", ffOPTWR },
2641 { efXVG, "-nhbdist", "nhbdist", ffOPTWR }
2644 #define NFILE asize(fnm)
2646 char hbmap[HB_NR] = { ' ', 'o', '-', '*' };
2647 const char* hbdesc[HB_NR] = { "None", "Present", "Inserted", "Present & Inserted" };
2648 t_rgb hbrgb[HB_NR] = { { 1, 1, 1 }, { 1, 0, 0 }, { 0, 0, 1 }, { 1, 0, 1 } };
2650 t_trxstatus* status;
2651 bool trrStatus = true;
2654 int npargs, natoms, nframes = 0, shatom;
2660 real t, ccut, dist = 0.0, ang = 0.0;
2661 double max_nhb, aver_nhb, aver_dist;
2662 int h = 0, i = 0, j, k = 0, ogrp, nsel;
2663 int xi = 0, yi, zi, ai;
2664 int xj, yj, zj, aj, xjj, yjj, zjj;
2665 gmx_bool bSelected, bHBmap, bStop, bTwo, bBox, bTric;
2666 int * adist, *rdist;
2667 int grp, nabin, nrbin, resdist, ihb;
2670 FILE * fp, *fpnhb = nullptr, *donor_properties = nullptr;
2672 t_ncell * icell, *jcell;
2674 unsigned char* datable;
2675 gmx_output_env_t* oenv;
2676 int ii, hh, actual_nThreads;
2679 gmx_bool bEdge_yjj, bEdge_xjj;
2681 t_hbdata** p_hb = nullptr; /* one per thread, then merge after the frame loop */
2682 int ** p_adist = nullptr, **p_rdist = nullptr; /* a histogram for each thread. */
2684 const bool bOMP = GMX_OPENMP;
2687 ppa = add_acf_pargs(&npargs, pa);
2689 if (!parse_common_args(
2690 &argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT, NFILE, fnm, npargs, ppa, asize(desc), desc, asize(bugs), bugs, &oenv))
2698 ccut = std::cos(acut * gmx::c_deg2Rad);
2704 gmx_fatal(FARGS, "Can not analyze selected contacts.");
2708 gmx_fatal(FARGS, "Can not analyze contact between H and A: turn off -noda");
2712 /* Initiate main data structure! */
2713 bHBmap = (opt2bSet("-ac", NFILE, fnm) || opt2bSet("-life", NFILE, fnm)
2714 || opt2bSet("-hbn", NFILE, fnm) || opt2bSet("-hbm", NFILE, fnm));
2716 if (opt2bSet("-nhbdist", NFILE, fnm))
2718 const char* leg[MAXHH + 1] = { "0 HBs", "1 HB", "2 HBs", "3 HBs", "Total" };
2719 fpnhb = xvgropen(opt2fn("-nhbdist", NFILE, fnm),
2720 "Number of donor-H with N HBs",
2721 output_env_get_xvgr_tlabel(oenv),
2724 xvgr_legend(fpnhb, asize(leg), leg, oenv);
2727 hb = mk_hbdata(bHBmap, opt2bSet("-dan", NFILE, fnm), bMerge || bContact);
2730 t_inputrec irInstance;
2731 t_inputrec* ir = &irInstance;
2732 read_tpx_top(ftp2fn(efTPR, NFILE, fnm), ir, box, &natoms, nullptr, nullptr, &top);
2734 snew(grpnames, grNR);
2737 /* Make Donor-Acceptor table */
2738 snew(datable, top.atoms.nr);
2742 /* analyze selected hydrogen bonds */
2743 printf("Select group with selected atoms:\n");
2744 get_index(&(top.atoms), opt2fn("-sel", NFILE, fnm), 1, &nsel, index, grpnames);
2748 "Number of atoms in group '%s' not a multiple of 3\n"
2749 "and therefore cannot contain triplets of "
2750 "Donor-Hydrogen-Acceptor",
2755 for (i = 0; (i < nsel); i += 3)
2757 int dd = index[0][i];
2758 int aa = index[0][i + 2];
2759 /* int */ hh = index[0][i + 1];
2760 add_dh(&hb->d, dd, hh, i, datable);
2761 add_acc(&hb->a, aa, i);
2762 /* Should this be here ? */
2763 snew(hb->d.dptr, top.atoms.nr);
2764 snew(hb->a.aptr, top.atoms.nr);
2765 add_hbond(hb, dd, aa, hh, gr0, gr0, 0, bMerge, 0, bContact);
2767 printf("Analyzing %d selected hydrogen bonds from '%s'\n", isize[0], grpnames[0]);
2771 /* analyze all hydrogen bonds: get group(s) */
2772 printf("Specify 2 groups to analyze:\n");
2773 get_index(&(top.atoms), ftp2fn_null(efNDX, NFILE, fnm), 2, isize, index, grpnames);
2775 /* check if we have two identical or two non-overlapping groups */
2776 bTwo = isize[0] != isize[1];
2777 for (i = 0; (i < isize[0]) && !bTwo; i++)
2779 bTwo = index[0][i] != index[1][i];
2783 printf("Checking for overlap in atoms between %s and %s\n", grpnames[0], grpnames[1]);
2785 gen_datable(index[0], isize[0], datable, top.atoms.nr);
2787 for (i = 0; i < isize[1]; i++)
2789 if (ISINGRP(datable[index[1][i]]))
2791 gmx_fatal(FARGS, "Partial overlap between groups '%s' and '%s'", grpnames[0], grpnames[1]);
2797 printf("Calculating %s "
2798 "between %s (%d atoms) and %s (%d atoms)\n",
2799 bContact ? "contacts" : "hydrogen bonds",
2808 "Calculating %s in %s (%d atoms)\n",
2809 bContact ? "contacts" : "hydrogen bonds",
2816 /* search donors and acceptors in groups */
2817 snew(datable, top.atoms.nr);
2818 for (i = 0; (i < grNR); i++)
2820 if (((i == gr0) && !bSelected) || ((i == gr1) && bTwo))
2822 gen_datable(index[i], isize[i], datable, top.atoms.nr);
2826 &top, isize[i], index[i], &hb->a, i, bNitAcc, TRUE, (bTwo && (i == gr0)) || !bTwo, datable);
2827 search_donors(&top, isize[i], index[i], &hb->d, i, TRUE, (bTwo && (i == gr1)) || !bTwo, datable);
2831 search_acceptors(&top, isize[i], index[i], &hb->a, i, bNitAcc, FALSE, TRUE, datable);
2832 search_donors(&top, isize[i], index[i], &hb->d, i, FALSE, TRUE, datable);
2836 clear_datable_grp(datable, top.atoms.nr);
2841 printf("Found %d donors and %d acceptors\n", hb->d.nrd, hb->a.nra);
2843 snew(donors[gr0D], dons[gr0D].nrd);*/
2845 donor_properties = open_donor_properties_file(opt2fn_null("-don", NFILE, fnm), hb, oenv);
2849 printf("Making hbmap structure...");
2850 /* Generate hbond data structure */
2857 if (hb->d.nrd + hb->a.nra == 0)
2859 printf("No Donors or Acceptors found\n");
2866 printf("No Donors found\n");
2871 printf("No Acceptors found\n");
2877 gmx_fatal(FARGS, "Nothing to be done");
2886 /* get index group with atom for shell */
2889 printf("Select atom for shell (1 atom):\n");
2890 get_index(&(top.atoms), ftp2fn_null(efNDX, NFILE, fnm), 1, &shisz, &shidx, &shgrpnm);
2893 printf("group contains %d atoms, should be 1 (one)\n", shisz);
2895 } while (shisz != 1);
2897 printf("Will calculate hydrogen bonds within a shell "
2898 "of %g nm around atom %i\n",
2903 /* Analyze trajectory */
2904 natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box);
2905 if (natoms > top.atoms.nr)
2907 gmx_fatal(FARGS, "Topology (%d atoms) does not match trajectory (%d atoms)", top.atoms.nr, natoms);
2910 bBox = (ir->pbcType != PbcType::No);
2911 grid = init_grid(bBox, box, (rcut > r2cut) ? rcut : r2cut, ngrid);
2912 nabin = static_cast<int>(acut / abin);
2913 nrbin = static_cast<int>(rcut / rbin);
2914 snew(adist, nabin + 1);
2915 snew(rdist, nrbin + 1);
2918 # define __ADIST adist
2919 # define __RDIST rdist
2920 # define __HBDATA hb
2921 #else /* GMX_OPENMP ================================================== \
2922 * Set up the OpenMP stuff, | \
2923 * like the number of threads and such | \
2924 * Also start the parallel loop. | \
2926 # define __ADIST p_adist[threadNr]
2927 # define __RDIST p_rdist[threadNr]
2928 # define __HBDATA p_hb[threadNr]
2932 bParallel = !bSelected;
2936 actual_nThreads = std::min((nThreads <= 0) ? INT_MAX : nThreads, gmx_omp_get_max_threads());
2938 gmx_omp_set_num_threads(actual_nThreads);
2939 printf("Frame loop parallelized with OpenMP using %i threads.\n", actual_nThreads);
2944 actual_nThreads = 1;
2947 snew(p_hb, actual_nThreads);
2948 snew(p_adist, actual_nThreads);
2949 snew(p_rdist, actual_nThreads);
2950 for (i = 0; i < actual_nThreads; i++)
2953 snew(p_adist[i], nabin + 1);
2954 snew(p_rdist[i], nrbin + 1);
2956 p_hb[i]->max_frames = 0;
2957 p_hb[i]->nhb = nullptr;
2958 p_hb[i]->ndist = nullptr;
2959 p_hb[i]->n_bound = nullptr;
2960 p_hb[i]->time = nullptr;
2961 p_hb[i]->nhx = nullptr;
2963 p_hb[i]->bHBmap = hb->bHBmap;
2964 p_hb[i]->bDAnr = hb->bDAnr;
2965 p_hb[i]->wordlen = hb->wordlen;
2966 p_hb[i]->nframes = hb->nframes;
2967 p_hb[i]->maxhydro = hb->maxhydro;
2968 p_hb[i]->danr = hb->danr;
2971 p_hb[i]->hbmap = hb->hbmap;
2972 p_hb[i]->time = hb->time; /* This may need re-syncing at every frame. */
2975 p_hb[i]->nrdist = 0;
2979 /* Make a thread pool here,
2980 * instead of forking anew at every frame. */
2982 #pragma omp parallel firstprivate(i) private(j, \
3009 bEdge_yjj) default(shared)
3010 { /* Start of parallel region */
3013 threadNr = gmx_omp_get_thread_num();
3018 bTric = bBox && TRICLINIC(box);
3024 sync_hbdata(p_hb[threadNr], nframes);
3026 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3032 build_grid(hb, x, x[shatom], bBox, box, hbox, (rcut > r2cut) ? rcut : r2cut, rshell, ngrid, grid);
3033 reset_nhbonds(&(hb->d));
3035 if (debug && bDebug)
3037 dump_grid(debug, ngrid, grid);
3040 add_frames(hb, nframes);
3041 init_hbframe(hb, nframes, output_env_conv_time(oenv, t));
3045 count_da_grid(ngrid, grid, hb->danr[nframes]);
3048 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3053 p_hb[threadNr]->time = hb->time; /* This pointer may have changed. */
3063 /* Do not parallelize this just yet. */
3065 for (ii = 0; (ii < nsel); ii++)
3067 int dd = index[0][i];
3068 int aa = index[0][i + 2];
3069 /* int */ hh = index[0][i + 1];
3071 hb, ii, ii, dd, aa, rcut, r2cut, ccut, x, bBox, box, hbox, &dist, &ang, bDA, &h, bContact, bMerge);
3075 /* add to index if not already there */
3077 add_hbond(hb, dd, aa, hh, ii, ii, nframes, bMerge, ihb, bContact);
3081 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3083 } /* if (bSelected) */
3086 /* The outer grid loop will have to do for now. */
3087 #pragma omp for schedule(dynamic)
3088 for (xi = 0; xi < ngrid[XX]; xi++)
3092 for (yi = 0; (yi < ngrid[YY]); yi++)
3094 for (zi = 0; (zi < ngrid[ZZ]); zi++)
3097 /* loop over donor groups gr0 (always) and gr1 (if necessary) */
3098 for (grp = gr0; (grp <= (bTwo ? gr1 : gr0)); grp++)
3100 icell = &(grid[zi][yi][xi].d[grp]);
3111 /* loop over all hydrogen atoms from group (grp)
3112 * in this gridcell (icell)
3114 for (ai = 0; (ai < icell->nr); ai++)
3116 i = icell->atoms[ai];
3118 /* loop over all adjacent gridcells (xj,yj,zj) */
3119 for (zjj = grid_loop_begin(ngrid[ZZ], zi, bTric, FALSE);
3120 zjj <= grid_loop_end(ngrid[ZZ], zi, bTric, FALSE);
3123 zj = grid_mod(zjj, ngrid[ZZ]);
3124 bEdge_yjj = (zj == 0) || (zj == ngrid[ZZ] - 1);
3125 for (yjj = grid_loop_begin(ngrid[YY], yi, bTric, bEdge_yjj);
3126 yjj <= grid_loop_end(ngrid[YY], yi, bTric, bEdge_yjj);
3129 yj = grid_mod(yjj, ngrid[YY]);
3130 bEdge_xjj = (yj == 0) || (yj == ngrid[YY] - 1)
3131 || (zj == 0) || (zj == ngrid[ZZ] - 1);
3132 for (xjj = grid_loop_begin(ngrid[XX], xi, bTric, bEdge_xjj);
3133 xjj <= grid_loop_end(ngrid[XX], xi, bTric, bEdge_xjj);
3136 xj = grid_mod(xjj, ngrid[XX]);
3137 jcell = &(grid[zj][yj][xj].a[ogrp]);
3138 /* loop over acceptor atoms from other group
3139 * (ogrp) in this adjacent gridcell (jcell)
3141 for (aj = 0; (aj < jcell->nr); aj++)
3143 j = jcell->atoms[aj];
3145 /* check if this once was a h-bond */
3146 ihb = is_hbond(__HBDATA,
3167 /* add to index if not already there */
3169 add_hbond(__HBDATA, i, j, h, grp, ogrp, nframes, bMerge, ihb, bContact);
3171 /* make angle and distance distributions */
3172 if (ihb == hbHB && !bContact)
3178 "distance is higher "
3179 "than what is allowed "
3183 ang *= gmx::c_rad2Deg;
3184 __ADIST[static_cast<int>(ang / abin)]++;
3185 __RDIST[static_cast<int>(dist / rbin)]++;
3188 if (donor_index(&hb->d, grp, i) == NOTSET)
3195 if (acceptor_index(&hb->a, ogrp, j)
3204 top.atoms.atom[i].resind
3205 - top.atoms.atom[j].resind);
3206 if (resdist >= max_hx)
3208 resdist = max_hx - 1;
3210 __HBDATA->nhx[nframes][resdist]++;
3220 } /* for xi,yi,zi */
3223 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3225 } /* if (bSelected) {...} else */
3228 /* Better wait for all threads to finnish using x[] before updating it. */
3231 #pragma omp critical
3235 /* Sum up histograms and counts from p_hb[] into hb */
3238 hb->nhb[k] += p_hb[threadNr]->nhb[k];
3239 hb->ndist[k] += p_hb[threadNr]->ndist[k];
3240 for (j = 0; j < max_hx; j++)
3242 hb->nhx[k][j] += p_hb[threadNr]->nhx[k][j];
3246 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3249 /* Here are a handful of single constructs
3250 * to share the workload a bit. The most
3251 * important one is of course the last one,
3252 * where there's a potential bottleneck in form
3259 analyse_donor_properties(donor_properties, hb, k, t);
3261 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3270 do_nhb_dist(fpnhb, hb, t);
3273 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3280 trrStatus = (read_next_x(oenv, status, &t, x, box));
3283 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3287 } while (trrStatus);
3291 #pragma omp critical
3293 hb->nrhb += p_hb[threadNr]->nrhb;
3294 hb->nrdist += p_hb[threadNr]->nrdist;
3297 /* Free parallel datastructures */
3298 sfree(p_hb[threadNr]->nhb);
3299 sfree(p_hb[threadNr]->ndist);
3300 sfree(p_hb[threadNr]->nhx);
3303 for (i = 0; i < nabin; i++)
3307 for (j = 0; j < actual_nThreads; j++)
3310 adist[i] += p_adist[j][i];
3313 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3316 for (i = 0; i <= nrbin; i++)
3320 for (j = 0; j < actual_nThreads; j++)
3322 rdist[i] += p_rdist[j][i];
3325 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3328 sfree(p_adist[threadNr]);
3329 sfree(p_rdist[threadNr]);
3331 } /* End of parallel region */
3338 if (nframes < 2 && (opt2bSet("-ac", NFILE, fnm) || opt2bSet("-life", NFILE, fnm)))
3340 gmx_fatal(FARGS, "Cannot calculate autocorrelation of life times with less than two frames");
3343 free_grid(ngrid, &grid);
3347 if (donor_properties)
3349 xvgrclose(donor_properties);
3357 /* Compute maximum possible number of different hbonds */
3364 max_nhb = 0.5 * (hb->d.nrd * hb->a.nra);
3371 printf("No %s found!!\n", bContact ? "contacts" : "hydrogen bonds");
3375 printf("Found %d different %s in trajectory\n"
3376 "Found %d different atom-pairs within %s distance\n",
3378 bContact ? "contacts" : "hydrogen bonds",
3380 (r2cut > 0) ? "second cut-off" : "hydrogen bonding");
3384 merge_hb(hb, bTwo, bContact);
3387 if (opt2bSet("-hbn", NFILE, fnm))
3389 dump_hbmap(hb, NFILE, fnm, bTwo, bContact, isize, index, grpnames, &top.atoms);
3392 /* Moved the call to merge_hb() to a line BEFORE dump_hbmap
3393 * to make the -hbn and -hmb output match eachother.
3394 * - Erik Marklund, May 30, 2006 */
3397 /* Print out number of hbonds and distances */
3400 fp = xvgropen(opt2fn("-num", NFILE, fnm),
3401 bContact ? "Contacts" : "Hydrogen Bonds",
3402 output_env_get_xvgr_tlabel(oenv),
3406 snew(leg[0], STRLEN);
3407 snew(leg[1], STRLEN);
3408 sprintf(leg[0], "%s", bContact ? "Contacts" : "Hydrogen bonds");
3409 sprintf(leg[1], "Pairs within %g nm", (r2cut > 0) ? r2cut : rcut);
3410 xvgr_legend(fp, 2, leg, oenv);
3414 for (i = 0; (i < nframes); i++)
3416 fprintf(fp, "%10g %10d %10d\n", hb->time[i], hb->nhb[i], hb->ndist[i]);
3417 aver_nhb += hb->nhb[i];
3418 aver_dist += hb->ndist[i];
3421 aver_nhb /= nframes;
3422 aver_dist /= nframes;
3423 /* Print HB distance distribution */
3424 if (opt2bSet("-dist", NFILE, fnm))
3429 for (i = 0; i < nrbin; i++)
3434 fp = xvgropen(opt2fn("-dist", NFILE, fnm),
3435 "Hydrogen Bond Distribution",
3436 bDA ? "Donor - Acceptor Distance (nm)" : "Hydrogen - Acceptor Distance (nm)",
3439 for (i = 0; i < nrbin; i++)
3441 fprintf(fp, "%10g %10g\n", (i + 0.5) * rbin, rdist[i] / (rbin * sum));
3446 /* Print HB angle distribution */
3447 if (opt2bSet("-ang", NFILE, fnm))
3452 for (i = 0; i < nabin; i++)
3457 fp = xvgropen(opt2fn("-ang", NFILE, fnm),
3458 "Hydrogen Bond Distribution",
3459 "Hydrogen - Donor - Acceptor Angle (\\SO\\N)",
3462 for (i = 0; i < nabin; i++)
3464 fprintf(fp, "%10g %10g\n", (i + 0.5) * abin, adist[i] / (abin * sum));
3469 /* Print HB in alpha-helix */
3470 if (opt2bSet("-hx", NFILE, fnm))
3472 fp = xvgropen(opt2fn("-hx", NFILE, fnm),
3474 output_env_get_xvgr_tlabel(oenv),
3477 xvgr_legend(fp, NRHXTYPES, hxtypenames, oenv);
3478 for (i = 0; i < nframes; i++)
3480 fprintf(fp, "%10g", hb->time[i]);
3481 for (j = 0; j < max_hx; j++)
3483 fprintf(fp, " %6d", hb->nhx[i][j]);
3490 printf("Average number of %s per timeframe %.3f out of %g possible\n",
3491 bContact ? "contacts" : "hbonds",
3492 bContact ? aver_dist : aver_nhb,
3495 /* Do Autocorrelation etc. */
3499 Added support for -contact in ac and hbm calculations below.
3500 - Erik Marklund, May 29, 2006
3502 if (opt2bSet("-ac", NFILE, fnm) || opt2bSet("-life", NFILE, fnm))
3504 please_cite(stdout, "Spoel2006b");
3506 if (opt2bSet("-ac", NFILE, fnm))
3508 do_hbac(opt2fn("-ac", NFILE, fnm), hb, nDump, bMerge, bContact, fit_start, temp, r2cut > 0, oenv, nThreads);
3510 if (opt2bSet("-life", NFILE, fnm))
3512 do_hblife(opt2fn("-life", NFILE, fnm), hb, bMerge, bContact, oenv);
3514 if (opt2bSet("-hbm", NFILE, fnm))
3517 int id, ia, hh, x, y;
3520 if ((nframes > 0) && (hb->nrhb > 0))
3525 mat.matrix.resize(mat.nx, mat.ny);
3526 mat.axis_x.resize(mat.nx);
3527 for (auto& value : mat.matrix.toArrayRef())
3532 for (id = 0; (id < hb->d.nrd); id++)
3534 for (ia = 0; (ia < hb->a.nra); ia++)
3536 for (hh = 0; (hh < hb->maxhydro); hh++)
3538 if (hb->hbmap[id][ia])
3540 if (ISHB(hb->hbmap[id][ia]->history[hh]))
3542 for (x = 0; (x <= hb->hbmap[id][ia]->nframes); x++)
3544 int nn0 = hb->hbmap[id][ia]->n0;
3545 range_check(y, 0, mat.ny);
3546 mat.matrix(x + nn0, y) = static_cast<t_matelmt>(
3547 is_hb(hb->hbmap[id][ia]->h[hh], x));
3555 std::copy(hb->time, hb->time + mat.nx, mat.axis_x.begin());
3556 mat.axis_y.resize(mat.ny);
3557 std::iota(mat.axis_y.begin(), mat.axis_y.end(), 0);
3558 mat.title = (bContact ? "Contact Existence Map" : "Hydrogen Bond Existence Map");
3559 mat.legend = bContact ? "Contacts" : "Hydrogen Bonds";
3560 mat.label_x = output_env_get_xvgr_tlabel(oenv);
3561 mat.label_y = bContact ? "Contact Index" : "Hydrogen Bond Index";
3562 mat.bDiscrete = true;
3566 for (auto& m : mat.map)
3568 m.code.c1 = hbmap[i];
3574 fp = opt2FILE("-hbm", NFILE, fnm, "w");
3575 write_xpm_m(fp, mat);
3581 "No hydrogen bonds/contacts found. No hydrogen bond map will be "
3593 #define USE_THIS_GROUP(j) (((j) == gr0) || (bTwo && ((j) == gr1)))
3595 fp = xvgropen(opt2fn("-dan", NFILE, fnm),
3596 "Donors and Acceptors",
3597 output_env_get_xvgr_tlabel(oenv),
3600 nleg = (bTwo ? 2 : 1) * 2;
3601 snew(legnames, nleg);
3603 for (j = 0; j < grNR; j++)
3605 if (USE_THIS_GROUP(j))
3607 sprintf(buf, "Donors %s", grpnames[j]);
3608 legnames[i++] = gmx_strdup(buf);
3609 sprintf(buf, "Acceptors %s", grpnames[j]);
3610 legnames[i++] = gmx_strdup(buf);
3615 gmx_incons("number of legend entries");
3617 xvgr_legend(fp, nleg, legnames, oenv);
3618 for (i = 0; i < nframes; i++)
3620 fprintf(fp, "%10g", hb->time[i]);
3621 for (j = 0; (j < grNR); j++)
3623 if (USE_THIS_GROUP(j))
3625 fprintf(fp, " %6d", hb->danr[i][j]);