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/utilities.h"
64 #include "gromacs/math/vec.h"
65 #include "gromacs/mdtypes/inputrec.h"
66 #include "gromacs/pbcutil/pbc.h"
67 #include "gromacs/topology/ifunc.h"
68 #include "gromacs/topology/index.h"
69 #include "gromacs/topology/topology.h"
70 #include "gromacs/utility/arraysize.h"
71 #include "gromacs/utility/cstringutil.h"
72 #include "gromacs/utility/exceptions.h"
73 #include "gromacs/utility/fatalerror.h"
74 #include "gromacs/utility/futil.h"
75 #include "gromacs/utility/gmxomp.h"
76 #include "gromacs/utility/pleasecite.h"
77 #include "gromacs/utility/programcontext.h"
78 #include "gromacs/utility/smalloc.h"
79 #include "gromacs/utility/snprintf.h"
82 typedef int t_hx[max_hx];
83 #define NRHXTYPES max_hx
84 // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
85 static const char* hxtypenames[NRHXTYPES] = { "n-n", "n-n+1", "n-n+2", "n-n+3",
86 "n-n+4", "n-n+5", "n-n>6" };
89 static const int NOTSET = -49297;
91 /* -----------------------------------------*/
108 static const unsigned char c_acceptorMask = (1 << 0);
109 static const unsigned char c_donorMask = (1 << 1);
110 static const unsigned char c_inGroupMask = (1 << 2);
112 // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
113 static const char* grpnames[grNR] = { "0", "1", "I" };
114 // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
115 static gmx_bool bDebug = FALSE;
118 #define HB_YES 1 << 0
119 #define HB_INS 1 << 1
120 #define HB_YESINS (HB_YES | HB_INS)
121 #define HB_NR (1 << 2)
124 #define ISHB(h) ((h)&2)
125 #define ISDIST(h) ((h)&1)
126 #define ISDIST2(h) ((h)&4)
127 #define ISACC(h) ((h)&c_acceptorMask)
128 #define ISDON(h) ((h)&c_donorMask)
129 #define ISINGRP(h) ((h)&c_inGroupMask)
144 typedef int t_icell[grNR];
145 typedef int h_id[MAXHYDRO];
149 int history[MAXHYDRO];
150 /* Has this hbond existed ever? If so as hbDist or hbHB or both.
151 * Result is stored as a bitmap (1 = hbDist) || (2 = hbHB)
153 /* Bitmask array which tells whether a hbond is present
154 * at a given time. Either of these may be NULL
156 int n0; /* First frame a HB was found */
157 int nframes, maxframes; /* Amount of frames in this hbond */
160 /* See Xu and Berne, JPCB 105 (2001), p. 11929. We define the
161 * function g(t) = [1-h(t)] H(t) where H(t) is one when the donor-
162 * acceptor distance is less than the user-specified distance (typically
170 int* acc; /* Atom numbers of the acceptors */
171 int* grp; /* Group index */
172 int* aptr; /* Map atom number to acceptor index */
178 int* don; /* Atom numbers of the donors */
179 int* grp; /* Group index */
180 int* dptr; /* Map atom number to donor index */
181 int* nhydro; /* Number of hydrogens for each donor */
182 h_id* hydro; /* The atom numbers of the hydrogens */
183 h_id* nhbonds; /* The number of HBs per H at current */
188 gmx_bool bHBmap, bDAnr;
190 /* The following arrays are nframes long */
191 int nframes, max_frames, maxhydro;
197 /* These structures are initialized from the topology at start up */
200 /* This holds a matrix with all possible hydrogen bonds */
205 /* Changed argument 'bMerge' into 'oneHB' below,
206 * since -contact should cause maxhydro to be 1,
208 * - Erik Marklund May 29, 2006
211 static t_hbdata* mk_hbdata(gmx_bool bHBmap, gmx_bool bDAnr, gmx_bool oneHB)
216 hb->wordlen = 8 * sizeof(unsigned int);
225 hb->maxhydro = MAXHYDRO;
230 static void mk_hbmap(t_hbdata* hb)
234 snew(hb->hbmap, hb->d.nrd);
235 for (i = 0; (i < hb->d.nrd); i++)
237 snew(hb->hbmap[i], hb->a.nra);
238 if (hb->hbmap[i] == nullptr)
240 gmx_fatal(FARGS, "Could not allocate enough memory for hbmap");
242 for (j = 0; j < hb->a.nra; j++)
244 hb->hbmap[i][j] = nullptr;
249 static void add_frames(t_hbdata* hb, int nframes)
251 if (nframes >= hb->max_frames)
253 hb->max_frames += 4096;
254 srenew(hb->time, hb->max_frames);
255 srenew(hb->nhb, hb->max_frames);
256 srenew(hb->ndist, hb->max_frames);
257 srenew(hb->n_bound, hb->max_frames);
258 srenew(hb->nhx, hb->max_frames);
261 srenew(hb->danr, hb->max_frames);
264 hb->nframes = nframes;
267 #define OFFSET(frame) ((frame) / 32)
268 #define MASK(frame) (1 << ((frame) % 32))
270 static void set_hb_function(unsigned int hbexist[], unsigned int frame, gmx_bool bValue)
274 hbexist[OFFSET(frame)] |= MASK(frame);
278 hbexist[OFFSET(frame)] &= ~MASK(frame);
282 static gmx_bool is_hb(const unsigned int hbexist[], int frame)
284 return (hbexist[OFFSET(frame)] & MASK(frame)) != 0;
287 static void set_hb(t_hbdata* hb, int id, int ih, int ia, int frame, int ihb)
289 unsigned int* ghptr = nullptr;
293 ghptr = hb->hbmap[id][ia]->h[ih];
295 else if (ihb == hbDist)
297 ghptr = hb->hbmap[id][ia]->g[ih];
301 gmx_fatal(FARGS, "Incomprehensible iValue %d in set_hb", ihb);
304 set_hb_function(ghptr, frame - hb->hbmap[id][ia]->n0, TRUE);
307 static void add_ff(t_hbdata* hbd, int id, int h, int ia, int frame, int ihb)
310 t_hbond* hb = hbd->hbmap[id][ia];
311 int maxhydro = std::min(hbd->maxhydro, hbd->d.nhydro[id]);
312 int wlen = hbd->wordlen;
313 int delta = 32 * wlen;
318 hb->maxframes = delta;
319 for (i = 0; (i < maxhydro); i++)
321 snew(hb->h[i], hb->maxframes / wlen);
322 snew(hb->g[i], hb->maxframes / wlen);
327 hb->nframes = frame - hb->n0;
328 /* We need a while loop here because hbonds may be returning
331 while (hb->nframes >= hb->maxframes)
333 n = hb->maxframes + delta;
334 for (i = 0; (i < maxhydro); i++)
336 srenew(hb->h[i], n / wlen);
337 srenew(hb->g[i], n / wlen);
338 for (j = hb->maxframes / wlen; (j < n / wlen); j++)
350 set_hb(hbd, id, h, ia, frame, ihb);
354 static void inc_nhbonds(t_donors* ddd, int d, int h)
357 int dptr = ddd->dptr[d];
359 for (j = 0; (j < ddd->nhydro[dptr]); j++)
361 if (ddd->hydro[dptr][j] == h)
363 ddd->nhbonds[dptr][j]++;
367 if (j == ddd->nhydro[dptr])
369 gmx_fatal(FARGS, "No such hydrogen %d on donor %d\n", h + 1, d + 1);
373 static int acceptor_index_function(t_acceptors* a, int grp, int i, const char* file, int line)
377 if (a->grp[ai] != grp)
381 fprintf(debug, "Acc. group inconsist.. grp[%d] = %d, grp = %d (%s, %d)\n", ai, a->grp[ai], grp, file, line);
390 #define acceptor_index(a, grp, i) acceptor_index_function(a, grp, i, __FILE__, __LINE__)
392 static int donor_index_function(t_donors* d, int grp, int i, const char* file, int line)
401 if (d->grp[di] != grp)
405 fprintf(debug, "Don. group inconsist.. grp[%d] = %d, grp = %d (%s, %d)\n", di, d->grp[di], grp, file, line);
414 #define donor_index(d, grp, i) donor_index_function(d, grp, i, __FILE__, __LINE__)
416 static gmx_bool isInterchangable(t_hbdata* hb, int d, int a, int grpa, int grpd)
418 /* g_hbond doesn't allow overlapping groups */
423 return donor_index(&hb->d, grpd, a) != NOTSET && acceptor_index(&hb->a, grpa, d) != NOTSET;
428 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)
431 gmx_bool daSwap = FALSE;
433 if ((id = hb->d.dptr[d]) == NOTSET)
435 gmx_fatal(FARGS, "No donor atom %d", d + 1);
437 else if (grpd != hb->d.grp[id])
439 gmx_fatal(FARGS, "Inconsistent donor groups, %d instead of %d, atom %d", grpd, 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, hb->a.grp[ia], a + 1);
453 if (isInterchangable(hb, d, a, grpd, grpa) && d > a)
454 /* Then swap identity so that the id of d is lower then that of a.
456 * This should really be redundant by now, as is_hbond() now ought to return
457 * hbNo in the cases where this conditional is TRUE. */
464 /* Now repeat donor/acc check. */
465 if ((id = hb->d.dptr[d]) == NOTSET)
467 gmx_fatal(FARGS, "No donor atom %d", d + 1);
469 else if (grpd != hb->d.grp[id])
472 "Inconsistent donor groups, %d instead of %d, atom %d",
477 if ((ia = hb->a.aptr[a]) == NOTSET)
479 gmx_fatal(FARGS, "No acceptor atom %d", a + 1);
481 else if (grpa != hb->a.grp[ia])
484 "Inconsistent acceptor groups, %d instead of %d, atom %d",
494 /* Loop over hydrogens to find which hydrogen is in this particular HB */
495 if ((ihb == hbHB) && !bMerge && !bContact)
497 for (k = 0; (k < hb->d.nhydro[id]); k++)
499 if (hb->d.hydro[id][k] == h)
504 if (k == hb->d.nhydro[id])
506 gmx_fatal(FARGS, "Donor %d does not have hydrogen %d (a = %d)", d + 1, h + 1, a + 1);
521 if (hb->hbmap[id][ia] == nullptr)
523 snew(hb->hbmap[id][ia], 1);
524 snew(hb->hbmap[id][ia]->h, hb->maxhydro);
525 snew(hb->hbmap[id][ia]->g, hb->maxhydro);
527 add_ff(hb, id, k, ia, frame, ihb);
529 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
533 /* Strange construction with frame >=0 is a relic from old code
534 * for selected hbond analysis. It may be necessary again if that
535 * is made to work again.
539 hh = hb->hbmap[id][ia]->history[k];
545 hb->hbmap[id][ia]->history[k] = hh | 2;
556 hb->hbmap[id][ia]->history[k] = hh | 1;
580 if (bMerge && daSwap)
582 h = hb->d.hydro[id][0];
584 /* Increment number if HBonds per H */
585 if (ihb == hbHB && !bContact)
587 inc_nhbonds(&(hb->d), d, h);
591 static char* mkatomname(const t_atoms* atoms, int i)
596 rnr = atoms->atom[i].resind;
597 sprintf(buf, "%4s%d%-4s", *atoms->resinfo[rnr].name, atoms->resinfo[rnr].nr, *atoms->atomname[i]);
602 static void gen_datable(int* index, int isize, unsigned char* datable, int natoms)
604 /* Generates table of all atoms and sets the ingroup bit for atoms in index[] */
607 for (i = 0; i < isize; i++)
609 if (index[i] >= natoms)
611 gmx_fatal(FARGS, "Atom has index %d larger than number of atoms %d.", index[i], natoms);
613 datable[index[i]] |= c_inGroupMask;
617 static void clear_datable_grp(unsigned char* datable, int size)
619 /* Clears group information from the table */
623 for (i = 0; i < size; i++)
625 datable[i] &= ~c_inGroupMask;
630 static void add_acc(t_acceptors* a, int ia, int grp)
632 if (a->nra >= a->max_nra)
635 srenew(a->acc, a->max_nra);
636 srenew(a->grp, a->max_nra);
638 a->grp[a->nra] = grp;
639 a->acc[a->nra++] = ia;
642 static void search_acceptors(const t_topology* top,
650 unsigned char* datable)
656 for (i = 0; (i < isize); i++)
660 || (((*top->atoms.atomname[n])[0] == 'O')
661 || (bNitAcc && ((*top->atoms.atomname[n])[0] == 'N'))))
662 && ISINGRP(datable[n]))
664 datable[n] |= c_acceptorMask;
669 snew(a->aptr, top->atoms.nr);
670 for (i = 0; (i < top->atoms.nr); i++)
674 for (i = 0; (i < a->nra); i++)
676 a->aptr[a->acc[i]] = i;
680 static void add_h2d(int id, int ih, t_donors* ddd)
684 for (i = 0; (i < ddd->nhydro[id]); i++)
686 if (ddd->hydro[id][i] == ih)
688 printf("Hm. This isn't the first time I found this donor (%d,%d)\n", ddd->don[id], ih);
692 if (i == ddd->nhydro[id])
694 if (ddd->nhydro[id] >= MAXHYDRO)
696 gmx_fatal(FARGS, "Donor %d has more than %d hydrogens!", ddd->don[id], MAXHYDRO);
698 ddd->hydro[id][i] = ih;
703 static void add_dh(t_donors* ddd, int id, int ih, int grp, const unsigned char* datable)
707 if (!datable || ISDON(datable[id]))
709 if (ddd->dptr[id] == NOTSET) /* New donor */
721 if (ddd->nrd >= ddd->max_nrd)
724 srenew(ddd->don, ddd->max_nrd);
725 srenew(ddd->nhydro, ddd->max_nrd);
726 srenew(ddd->hydro, ddd->max_nrd);
727 srenew(ddd->nhbonds, ddd->max_nrd);
728 srenew(ddd->grp, ddd->max_nrd);
730 ddd->don[ddd->nrd] = id;
731 ddd->nhydro[ddd->nrd] = 0;
732 ddd->grp[ddd->nrd] = grp;
743 printf("Warning: Atom %d is not in the d/a-table!\n", id);
747 static void search_donors(const t_topology* top,
754 unsigned char* datable)
757 t_functype func_type;
762 snew(ddd->dptr, top->atoms.nr);
763 for (i = 0; (i < top->atoms.nr); i++)
765 ddd->dptr[i] = NOTSET;
773 for (i = 0; (i < isize); i++)
775 datable[index[i]] |= c_donorMask;
776 add_dh(ddd, index[i], -1, grp, datable);
782 for (func_type = 0; (func_type < F_NRE); func_type++)
784 const t_ilist* interaction = &(top->idef.il[func_type]);
785 if (func_type == F_POSRES || func_type == F_FBPOSRES)
787 /* The ilist looks strange for posre. Bug in grompp?
788 * We don't need posre interactions for hbonds anyway.*/
791 for (i = 0; i < interaction->nr;
792 i += interaction_function[top->idef.functype[interaction->iatoms[i]]].nratoms + 1)
795 if (func_type != top->idef.functype[interaction->iatoms[i]])
797 fprintf(stderr, "Error in func_type %s", interaction_function[func_type].longname);
801 /* check out this functype */
802 if (func_type == F_SETTLE)
804 nr1 = interaction->iatoms[i + 1];
805 nr2 = interaction->iatoms[i + 2];
806 nr3 = interaction->iatoms[i + 3];
808 if (ISINGRP(datable[nr1]))
810 if (ISINGRP(datable[nr2]))
812 datable[nr1] |= c_donorMask;
813 add_dh(ddd, nr1, nr1 + 1, grp, datable);
815 if (ISINGRP(datable[nr3]))
817 datable[nr1] |= c_donorMask;
818 add_dh(ddd, nr1, nr1 + 2, grp, datable);
822 else if (IS_CHEMBOND(func_type))
824 for (j = 0; j < 2; j++)
826 nr1 = interaction->iatoms[i + 1 + j];
827 nr2 = interaction->iatoms[i + 2 - j];
828 if ((*top->atoms.atomname[nr1][0] == 'H')
829 && ((*top->atoms.atomname[nr2][0] == 'O') || (*top->atoms.atomname[nr2][0] == 'N'))
830 && ISINGRP(datable[nr1]) && ISINGRP(datable[nr2]))
832 datable[nr2] |= c_donorMask;
833 add_dh(ddd, nr2, nr1, grp, datable);
840 for (func_type = 0; func_type < F_NRE; func_type++)
842 interaction = &top->idef.il[func_type];
843 for (i = 0; i < interaction->nr;
844 i += interaction_function[top->idef.functype[interaction->iatoms[i]]].nratoms + 1)
847 if (func_type != top->idef.functype[interaction->iatoms[i]])
849 gmx_incons("function type in search_donors");
852 if (interaction_function[func_type].flags & IF_VSITE)
854 nr1 = interaction->iatoms[i + 1];
855 if (*top->atoms.atomname[nr1][0] == 'H')
859 while (!stop && (*top->atoms.atomname[nr2][0] == 'H'))
871 && ((*top->atoms.atomname[nr2][0] == 'O') || (*top->atoms.atomname[nr2][0] == 'N'))
872 && ISINGRP(datable[nr1]) && ISINGRP(datable[nr2]))
874 datable[nr2] |= c_donorMask;
875 add_dh(ddd, nr2, nr1, grp, datable);
885 static t_gridcell*** init_grid(gmx_bool bBox, rvec box[], real rcut, ivec ngrid)
892 for (i = 0; i < DIM; i++)
894 ngrid[i] = static_cast<int>(box[i][i] / (1.2 * rcut));
898 if (!bBox || (ngrid[XX] < 3) || (ngrid[YY] < 3) || (ngrid[ZZ] < 3))
900 for (i = 0; i < DIM; i++)
907 printf("\nWill do grid-search on %dx%dx%d grid, rcut=%3.8f\n", ngrid[XX], ngrid[YY], ngrid[ZZ], rcut);
909 if (((ngrid[XX] * ngrid[YY] * ngrid[ZZ]) * sizeof(grid)) > INT_MAX)
912 "Failed to allocate memory for %d x %d x %d grid points, which is larger than "
913 "the maximum of %zu. "
914 "You are likely either using a box that is too large (box dimensions are %3.8f "
915 "nm x%3.8f nm x%3.8f nm) or a cutoff (%3.8f nm) that is too small.",
919 INT_MAX / sizeof(grid),
925 snew(grid, ngrid[ZZ]);
926 for (z = 0; z < ngrid[ZZ]; z++)
928 snew((grid)[z], ngrid[YY]);
929 for (y = 0; y < ngrid[YY]; y++)
931 snew((grid)[z][y], ngrid[XX]);
937 static void reset_nhbonds(t_donors* ddd)
941 for (i = 0; (i < ddd->nrd); i++)
943 for (j = 0; (j < MAXHH); j++)
945 ddd->nhbonds[i][j] = 0;
950 static void pbc_correct_gem(rvec dx, matrix box, const rvec hbox);
951 static void pbc_in_gridbox(rvec dx, matrix box);
953 static void build_grid(t_hbdata* hb,
964 int i, m, gr, xi, yi, zi, nr;
967 rvec invdelta, dshell;
969 gmx_bool bDoRshell, bInShell;
974 bDoRshell = (rshell > 0);
975 rshell2 = gmx::square(rshell);
979 if (debug && bDebug) \
980 fprintf(debug, "build_grid, line %d, %s = %d\n", __LINE__, #x, x)
982 for (m = 0; m < DIM; m++)
984 hbox[m] = box[m][m] * 0.5;
987 invdelta[m] = ngrid[m] / box[m][m];
988 if (1 / invdelta[m] < rcut)
991 "Your computational box has shrunk too much.\n"
992 "%s can not handle this situation, sorry.\n",
993 gmx::getProgramContext().displayName());
1005 /* resetting atom counts */
1006 for (gr = 0; (gr < grNR); gr++)
1008 for (zi = 0; zi < ngrid[ZZ]; zi++)
1010 for (yi = 0; yi < ngrid[YY]; yi++)
1012 for (xi = 0; xi < ngrid[XX]; xi++)
1014 grid[zi][yi][xi].d[gr].nr = 0;
1015 grid[zi][yi][xi].a[gr].nr = 0;
1021 /* put atoms in grid cells */
1022 for (int acc = 0; acc < 2; acc++)
1035 for (i = 0; (i < nr); i++)
1037 /* check if we are inside the shell */
1038 /* if bDoRshell=FALSE then bInShell=TRUE always */
1043 rvec_sub(x[ad[i]], xshell, dshell);
1046 gmx_bool bDone = FALSE;
1050 for (m = DIM - 1; m >= 0 && bInShell; m--)
1052 if (dshell[m] < -hbox[m])
1055 rvec_inc(dshell, box[m]);
1057 if (dshell[m] >= hbox[m])
1060 dshell[m] -= 2 * hbox[m];
1064 for (m = DIM - 1; m >= 0 && bInShell; m--)
1066 /* if we're outside the cube, we're outside the sphere also! */
1067 if ((dshell[m] > rshell) || (-dshell[m] > rshell))
1073 /* if we're inside the cube, check if we're inside the sphere */
1076 bInShell = norm2(dshell) < rshell2;
1084 pbc_in_gridbox(x[ad[i]], box);
1086 for (m = DIM - 1; m >= 0; m--)
1087 { /* determine grid index of atom */
1088 grididx[m] = static_cast<int>(x[ad[i]][m] * invdelta[m]);
1089 grididx[m] = (grididx[m] + ngrid[m]) % ngrid[m];
1096 range_check(gx, 0, ngrid[XX]);
1097 range_check(gy, 0, ngrid[YY]);
1098 range_check(gz, 0, ngrid[ZZ]);
1102 /* add atom to grid cell */
1105 newgrid = &(grid[gz][gy][gx].a[gr]);
1109 newgrid = &(grid[gz][gy][gx].d[gr]);
1111 if (newgrid->nr >= newgrid->maxnr)
1113 newgrid->maxnr += 10;
1114 DBB(newgrid->maxnr);
1115 srenew(newgrid->atoms, newgrid->maxnr);
1118 newgrid->atoms[newgrid->nr] = ad[i];
1126 static void count_da_grid(const ivec ngrid, t_gridcell*** grid, t_icell danr)
1130 for (gr = 0; (gr < grNR); gr++)
1133 for (zi = 0; zi < ngrid[ZZ]; zi++)
1135 for (yi = 0; yi < ngrid[YY]; yi++)
1137 for (xi = 0; xi < ngrid[XX]; xi++)
1139 danr[gr] += grid[zi][yi][xi].d[gr].nr;
1147 * Without a box, the grid is 1x1x1, so all loops are 1 long.
1148 * With a rectangular box (bTric==FALSE) all loops are 3 long.
1149 * With a triclinic box all loops are 3 long, except when a cell is
1150 * located next to one of the box edges which is not parallel to the
1151 * x/y-plane, in that case all cells in a line or layer are searched.
1152 * This could be implemented slightly more efficient, but the code
1153 * would get much more complicated.
1155 static inline int grid_loop_begin(int n, int x, gmx_bool bTric, gmx_bool bEdge)
1157 return ((n == 1) ? x : bTric && bEdge ? 0 : (x - 1));
1159 static inline int grid_loop_end(int n, int x, gmx_bool bTric, gmx_bool bEdge)
1161 return ((n == 1) ? x : bTric && bEdge ? (n - 1) : (x + 1));
1163 static inline int grid_mod(int j, int n)
1165 return (j + n) % (n);
1168 static void dump_grid(FILE* fp, ivec ngrid, t_gridcell*** grid)
1170 int gr, x, y, z, sum[grNR];
1172 fprintf(fp, "grid %dx%dx%d\n", ngrid[XX], ngrid[YY], ngrid[ZZ]);
1173 for (gr = 0; gr < grNR; gr++)
1176 fprintf(fp, "GROUP %d (%s)\n", gr, grpnames[gr]);
1177 for (z = 0; z < ngrid[ZZ]; z += 2)
1179 fprintf(fp, "Z=%d,%d\n", z, z + 1);
1180 for (y = 0; y < ngrid[YY]; y++)
1182 for (x = 0; x < ngrid[XX]; x++)
1184 fprintf(fp, "%3d", grid[x][y][z].d[gr].nr);
1185 sum[gr] += grid[z][y][x].d[gr].nr;
1186 fprintf(fp, "%3d", grid[x][y][z].a[gr].nr);
1187 sum[gr] += grid[z][y][x].a[gr].nr;
1190 if ((z + 1) < ngrid[ZZ])
1192 for (x = 0; x < ngrid[XX]; x++)
1194 fprintf(fp, "%3d", grid[z + 1][y][x].d[gr].nr);
1195 sum[gr] += grid[z + 1][y][x].d[gr].nr;
1196 fprintf(fp, "%3d", grid[z + 1][y][x].a[gr].nr);
1197 sum[gr] += grid[z + 1][y][x].a[gr].nr;
1204 fprintf(fp, "TOTALS:");
1205 for (gr = 0; gr < grNR; gr++)
1207 fprintf(fp, " %d=%d", gr, sum[gr]);
1212 /* New GMX record! 5 * in a row. Congratulations!
1213 * Sorry, only four left.
1215 static void free_grid(const ivec ngrid, t_gridcell**** grid)
1218 t_gridcell*** g = *grid;
1220 for (z = 0; z < ngrid[ZZ]; z++)
1222 for (y = 0; y < ngrid[YY]; y++)
1232 static void pbc_correct_gem(rvec dx, matrix box, const rvec hbox)
1235 gmx_bool bDone = FALSE;
1239 for (m = DIM - 1; m >= 0; m--)
1241 if (dx[m] < -hbox[m])
1244 rvec_inc(dx, box[m]);
1246 if (dx[m] >= hbox[m])
1249 rvec_dec(dx, box[m]);
1255 static void pbc_in_gridbox(rvec dx, matrix box)
1258 gmx_bool bDone = FALSE;
1262 for (m = DIM - 1; m >= 0; m--)
1267 rvec_inc(dx, box[m]);
1269 if (dx[m] >= box[m][m])
1272 rvec_dec(dx, box[m]);
1278 /* Added argument r2cut, changed contact and implemented
1279 * use of second cut-off.
1280 * - Erik Marklund, June 29, 2006
1282 static int is_hbond(t_hbdata* hb,
1302 rvec r_da, r_ha, r_dh;
1303 real rc2, r2c2, rda2, rha2, ca;
1304 gmx_bool HAinrange = FALSE; /* If !bDA. Needed for returning hbDist in a correct way. */
1305 gmx_bool daSwap = FALSE;
1312 if (((id = donor_index(&hb->d, grpd, d)) == NOTSET) || (acceptor_index(&hb->a, grpa, a) == NOTSET))
1318 r2c2 = r2cut * r2cut;
1320 rvec_sub(x[d], x[a], r_da);
1321 /* Insert projection code here */
1323 if (bMerge && d > a && isInterchangable(hb, d, a, grpd, grpa))
1325 /* Then this hbond/contact will be found again, or it has already been found. */
1331 && isInterchangable(hb, d, a, grpd, grpa)) /* acceptor is also a donor and vice versa? */
1332 { /* return hbNo; */
1333 daSwap = TRUE; /* If so, then their history should be filed with donor and acceptor swapped. */
1335 pbc_correct_gem(r_da, box, hbox);
1337 rda2 = iprod(r_da, r_da);
1341 if (daSwap && grpa == grpd)
1349 else if (rda2 < r2c2)
1360 if (bDA && (rda2 > rc2))
1365 for (h = 0; (h < hb->d.nhydro[id]); h++)
1367 hh = hb->d.hydro[id][h];
1371 rvec_sub(x[hh], x[a], r_ha);
1374 pbc_correct_gem(r_ha, box, hbox);
1376 rha2 = iprod(r_ha, r_ha);
1379 if (bDA || (rha2 <= rc2))
1381 rvec_sub(x[d], x[hh], r_dh);
1384 pbc_correct_gem(r_dh, box, hbox);
1391 ca = cos_angle(r_dh, r_da);
1392 /* if angle is smaller, cos is larger */
1396 *d_ha = std::sqrt(bDA ? rda2 : rha2);
1397 *ang = std::acos(ca);
1402 if (bDA || HAinrange)
1412 /* Merging is now done on the fly, so do_merge is most likely obsolete now.
1413 * Will do some more testing before removing the function entirely.
1414 * - Erik Marklund, MAY 10 2010 */
1415 static void do_merge(t_hbdata* hb, int ntmp, bool htmp[], bool gtmp[], t_hbond* hb0, t_hbond* hb1)
1417 /* Here we need to make sure we're treating periodicity in
1418 * the right way for the geminate recombination kinetics. */
1420 int m, mm, n00, n01, nn0, nnframes;
1422 /* Decide where to start from when merging */
1425 nn0 = std::min(n00, n01);
1426 nnframes = std::max(n00 + hb0->nframes, n01 + hb1->nframes) - nn0;
1427 /* Initiate tmp arrays */
1428 for (m = 0; (m < ntmp); m++)
1433 /* Fill tmp arrays with values due to first HB */
1434 /* Once again '<' had to be replaced with '<='
1435 to catch the last frame in which the hbond
1437 - Erik Marklund, June 1, 2006 */
1438 for (m = 0; (m <= hb0->nframes); m++)
1441 htmp[mm] = is_hb(hb0->h[0], m);
1443 for (m = 0; (m <= hb0->nframes); m++)
1446 gtmp[mm] = is_hb(hb0->g[0], m);
1449 for (m = 0; (m <= hb1->nframes); m++)
1452 htmp[mm] = htmp[mm] || is_hb(hb1->h[0], m);
1453 gtmp[mm] = gtmp[mm] || is_hb(hb1->g[0], m);
1455 /* Reallocate target array */
1456 if (nnframes > hb0->maxframes)
1458 srenew(hb0->h[0], 4 + nnframes / hb->wordlen);
1459 srenew(hb0->g[0], 4 + nnframes / hb->wordlen);
1462 /* Copy temp array to target array */
1463 for (m = 0; (m <= nnframes); m++)
1465 set_hb_function(hb0->h[0], m, htmp[m]);
1466 set_hb_function(hb0->g[0], m, gtmp[m]);
1469 /* Set scalar variables */
1471 hb0->maxframes = nnframes;
1474 static void merge_hb(t_hbdata* hb, gmx_bool bTwo, gmx_bool bContact)
1476 int i, inrnew, indnew, j, ii, jj, id, ia, ntmp;
1481 indnew = hb->nrdist;
1483 /* Check whether donors are also acceptors */
1484 printf("Merging hbonds with Acceptor and Donor swapped\n");
1486 ntmp = 2 * hb->max_frames;
1489 for (i = 0; (i < hb->d.nrd); i++)
1491 fprintf(stderr, "\r%d/%d", i + 1, hb->d.nrd);
1494 ii = hb->a.aptr[id];
1495 for (j = 0; (j < hb->a.nra); j++)
1498 jj = hb->d.dptr[ia];
1499 if ((id != ia) && (ii != NOTSET) && (jj != NOTSET)
1500 && (!bTwo || (hb->d.grp[i] != hb->a.grp[j])))
1502 hb0 = hb->hbmap[i][j];
1503 hb1 = hb->hbmap[jj][ii];
1504 if (hb0 && hb1 && ISHB(hb0->history[0]) && ISHB(hb1->history[0]))
1506 do_merge(hb, ntmp, htmp, gtmp, hb0, hb1);
1507 if (ISHB(hb1->history[0]))
1511 else if (ISDIST(hb1->history[0]))
1517 gmx_incons("No contact history");
1521 gmx_incons("Neither hydrogen bond nor distance");
1525 hb1->h[0] = nullptr;
1526 hb1->g[0] = nullptr;
1527 hb1->history[0] = hbNo;
1532 fprintf(stderr, "\n");
1533 printf("- Reduced number of hbonds from %d to %d\n", hb->nrhb, inrnew);
1534 printf("- Reduced number of distances from %d to %d\n", hb->nrdist, indnew);
1536 hb->nrdist = indnew;
1541 static void do_nhb_dist(FILE* fp, t_hbdata* hb, real t)
1543 int i, j, k, n_bound[MAXHH], nbtot;
1545 /* Set array to 0 */
1546 for (k = 0; (k < MAXHH); k++)
1550 /* Loop over possible donors */
1551 for (i = 0; (i < hb->d.nrd); i++)
1553 for (j = 0; (j < hb->d.nhydro[i]); j++)
1555 n_bound[hb->d.nhbonds[i][j]]++;
1558 fprintf(fp, "%12.5e", t);
1560 for (k = 0; (k < MAXHH); k++)
1562 fprintf(fp, " %8d", n_bound[k]);
1563 nbtot += n_bound[k] * k;
1565 fprintf(fp, " %8d\n", nbtot);
1568 static void do_hblife(const char* fn, t_hbdata* hb, gmx_bool bMerge, gmx_bool bContact, const gmx_output_env_t* oenv)
1571 const char* leg[] = { "p(t)", "t p(t)" };
1573 int i, j, j0, k, m, nh, ihb, ohb, nhydro, ndump = 0;
1574 int nframes = hb->nframes;
1577 double sum, integral;
1580 snew(h, hb->maxhydro);
1581 snew(histo, nframes + 1);
1582 /* Total number of hbonds analyzed here */
1583 for (i = 0; (i < hb->d.nrd); i++)
1585 for (k = 0; (k < hb->a.nra); k++)
1587 hbh = hb->hbmap[i][k];
1605 for (m = 0; (m < hb->maxhydro); m++)
1609 h[nhydro++] = bContact ? hbh->g[m] : hbh->h[m];
1613 for (nh = 0; (nh < nhydro); nh++)
1618 for (j = 0; (j <= hbh->nframes); j++)
1620 ihb = static_cast<int>(is_hb(h[nh], j));
1621 if (debug && (ndump < 10))
1623 fprintf(debug, "%5d %5d\n", j, ihb);
1643 fprintf(stderr, "\n");
1646 fp = xvgropen(fn, "Uninterrupted contact lifetime", output_env_get_xvgr_tlabel(oenv), "()", oenv);
1651 fn, "Uninterrupted hydrogen bond lifetime", output_env_get_xvgr_tlabel(oenv), "()", oenv);
1654 xvgr_legend(fp, asize(leg), leg, oenv);
1656 while ((j0 > 0) && (histo[j0] == 0))
1661 for (i = 0; (i <= j0); i++)
1665 dt = hb->time[1] - hb->time[0];
1668 for (i = 1; (i <= j0); i++)
1670 t = hb->time[i] - hb->time[0] - 0.5 * dt;
1671 x1 = t * histo[i] / sum;
1672 fprintf(fp, "%8.3f %10.3e %10.3e\n", t, histo[i] / sum, x1);
1677 printf("%s lifetime = %.2f ps\n", bContact ? "Contact" : "HB", integral);
1678 printf("Note that the lifetime obtained in this manner is close to useless\n");
1679 printf("Use the -ac option instead and check the Forward lifetime\n");
1680 please_cite(stdout, "Spoel2006b");
1685 static void dump_ac(t_hbdata* hb, gmx_bool oneHB, int nDump)
1688 int i, j, k, m, nd, ihb, idist;
1689 int nframes = hb->nframes;
1697 fp = gmx_ffopen("debug-ac.xvg", "w");
1698 for (j = 0; (j < nframes); j++)
1700 fprintf(fp, "%10.3f", hb->time[j]);
1701 for (i = nd = 0; (i < hb->d.nrd) && (nd < nDump); i++)
1703 for (k = 0; (k < hb->a.nra) && (nd < nDump); k++)
1707 hbh = hb->hbmap[i][k];
1712 ihb = static_cast<int>(is_hb(hbh->h[0], j));
1713 idist = static_cast<int>(is_hb(hbh->g[0], j));
1719 for (m = 0; (m < hb->maxhydro) && !ihb; m++)
1721 ihb = static_cast<int>((ihb != 0)
1722 || (((hbh->h[m]) != nullptr) && is_hb(hbh->h[m], j)));
1723 idist = static_cast<int>((idist != 0)
1724 || (((hbh->g[m]) != nullptr) && is_hb(hbh->g[m], j)));
1726 /* This is not correct! */
1727 /* What isn't correct? -Erik M */
1732 fprintf(fp, " %1d-%1d", ihb, idist);
1742 static real calc_dg(real tau, real temp)
1746 kbt = gmx::c_boltz * temp;
1753 return kbt * std::log(kbt * tau / gmx::c_planck);
1759 int n0, n1, nparams, ndelta;
1761 real *t, *ct, *nt, *kt, *sigma_ct, *sigma_nt, *sigma_kt;
1764 static real compute_weighted_rates(int n,
1781 real kkk = 0, kkp = 0, kk2 = 0, kp2 = 0, chi2;
1786 for (i = 0; (i < n); i++)
1788 if (t[i] >= fit_start)
1801 tl.sigma_ct = sigma_ct;
1802 tl.sigma_nt = sigma_nt;
1803 tl.sigma_kt = sigma_kt;
1807 chi2 = 0; /*optimize_luzar_parameters(debug, &tl, 1000, 1e-3); */
1809 *kp = tl.kkk[1] = *kp;
1811 for (j = 0; (j < NK); j++)
1815 kk2 += gmx::square(tl.kkk[0]);
1816 kp2 += gmx::square(tl.kkk[1]);
1819 *sigma_k = std::sqrt(kk2 / NK - gmx::square(kkk / NK));
1820 *sigma_kp = std::sqrt(kp2 / NK - gmx::square(kkp / NK));
1825 void analyse_corr(int n,
1837 real k = 1, kp = 1, kow = 1;
1838 real Q = 0, chi2, tau_hb, dtau, tau_rlx, e_1, sigma_k, sigma_kp, ddg;
1839 double tmp, sn2 = 0, sc2 = 0, sk2 = 0, scn = 0, sck = 0, snk = 0;
1840 gmx_bool bError = (sigma_ct != nullptr) && (sigma_nt != nullptr) && (sigma_kt != nullptr);
1842 for (i0 = 0; (i0 < n - 2) && ((t[i0] - t[0]) < fit_start); i0++) {}
1845 for (i = i0; (i < n); i++)
1847 sc2 += gmx::square(ct[i]);
1848 sn2 += gmx::square(nt[i]);
1849 sk2 += gmx::square(kt[i]);
1850 sck += ct[i] * kt[i];
1851 snk += nt[i] * kt[i];
1852 scn += ct[i] * nt[i];
1854 printf("Hydrogen bond thermodynamics at T = %g K\n", temp);
1855 tmp = (sn2 * sc2 - gmx::square(scn));
1856 if ((tmp > 0) && (sn2 > 0))
1858 k = (sn2 * sck - scn * snk) / tmp;
1859 kp = (k * scn - snk) / sn2;
1863 for (i = i0; (i < n); i++)
1865 chi2 += gmx::square(k * ct[i] - kp * nt[i] - kt[i]);
1867 compute_weighted_rates(
1868 n, t, ct, nt, kt, sigma_ct, sigma_nt, sigma_kt, &k, &kp, &sigma_k, &sigma_kp, fit_start);
1869 Q = 0; /* quality_of_fit(chi2, 2);*/
1870 ddg = gmx::c_boltz * temp * sigma_k / k;
1871 printf("Fitting paramaters chi^2 = %10g, Quality of fit = %10g\n", chi2, Q);
1872 printf("The Rate and Delta G are followed by an error estimate\n");
1873 printf("----------------------------------------------------------\n"
1874 "Type Rate (1/ps) Sigma Time (ps) DG (kJ/mol) Sigma\n");
1875 printf("Forward %10.3f %6.2f %8.3f %10.3f %6.2f\n",
1879 calc_dg(1 / k, temp),
1881 ddg = gmx::c_boltz * temp * sigma_kp / kp;
1882 printf("Backward %10.3f %6.2f %8.3f %10.3f %6.2f\n",
1886 calc_dg(1 / kp, temp),
1892 for (i = i0; (i < n); i++)
1894 chi2 += gmx::square(k * ct[i] - kp * nt[i] - kt[i]);
1896 printf("Fitting parameters chi^2 = %10g\nQ = %10g\n", chi2, Q);
1897 printf("--------------------------------------------------\n"
1898 "Type Rate (1/ps) Time (ps) DG (kJ/mol) Chi^2\n");
1899 printf("Forward %10.3f %8.3f %10.3f %10g\n", k, 1 / k, calc_dg(1 / k, temp), chi2);
1900 printf("Backward %10.3f %8.3f %10.3f\n", kp, 1 / kp, calc_dg(1 / kp, temp));
1905 kow = 2 * sck / sc2;
1906 printf("One-way %10.3f %s%8.3f %10.3f\n",
1910 calc_dg(1 / kow, temp));
1914 printf(" - Numerical problems computing HB thermodynamics:\n"
1915 "sc2 = %g sn2 = %g sk2 = %g sck = %g snk = %g scn = %g\n",
1923 /* Determine integral of the correlation function */
1924 tau_hb = evaluate_integral(n, t, ct, nullptr, (t[n - 1] - t[0]) / 2, &dtau);
1925 printf("Integral %10.3f %s%8.3f %10.3f\n",
1929 calc_dg(tau_hb, temp));
1930 e_1 = std::exp(-1.0);
1931 for (i = 0; (i < n - 2); i++)
1933 if ((ct[i] > e_1) && (ct[i + 1] <= e_1))
1940 /* Determine tau_relax from linear interpolation */
1941 tau_rlx = t[i] - t[0] + (e_1 - ct[i]) * (t[i + 1] - t[i]) / (ct[i + 1] - ct[i]);
1942 printf("Relaxation %10.3f %8.3f %s%10.3f\n",
1946 calc_dg(tau_rlx, temp));
1951 printf("Correlation functions too short to compute thermodynamics\n");
1955 void compute_derivative(int nn, const real x[], const real y[], real dydx[])
1959 /* Compute k(t) = dc(t)/dt */
1960 for (j = 1; (j < nn - 1); j++)
1962 dydx[j] = (y[j + 1] - y[j - 1]) / (x[j + 1] - x[j - 1]);
1964 /* Extrapolate endpoints */
1965 dydx[0] = 2 * dydx[1] - dydx[2];
1966 dydx[nn - 1] = 2 * dydx[nn - 2] - dydx[nn - 3];
1969 static void normalizeACF(real* ct, real* gt, int nhb, int len)
1971 real ct_fac, gt_fac = 0;
1974 /* Xu and Berne use the same normalization constant */
1976 ct_fac = 1.0 / ct[0];
1982 printf("Normalization for c(t) = %g for gh(t) = %g\n", ct_fac, gt_fac);
1983 for (i = 0; i < len; i++)
1993 static void do_hbac(const char* fn,
2001 const gmx_output_env_t* oenv,
2005 int i, j, k, m, ihb, idist, n2, nn;
2007 const char* legLuzar[] = { "Ac\\sfin sys\\v{}\\z{}(t)",
2009 "Cc\\scontact,hb\\v{}\\z{}(t)",
2010 "-dAc\\sfs\\v{}\\z{}/dt" };
2011 gmx_bool bNorm = FALSE;
2013 real * rhbex = nullptr, *ht, *gt, *ght, *dght, *kt;
2014 real * ct, tail, tail2, dtail, *cct;
2015 const real tol = 1e-3;
2016 int nframes = hb->nframes;
2017 unsigned int **h = nullptr, **g = nullptr;
2018 int nh, nhbonds, nhydro;
2021 int* dondata = nullptr;
2031 const bool bOMP = GMX_OPENMP;
2033 printf("Doing autocorrelation ");
2036 printf("according to the theory of Luzar and Chandler.\n");
2039 /* build hbexist matrix in reals for autocorr */
2040 /* Allocate memory for computing ACF (rhbex) and aggregating the ACF (ct) */
2042 while (n2 < nframes)
2049 if (acType != AC_NN || bOMP)
2051 snew(h, hb->maxhydro);
2052 snew(g, hb->maxhydro);
2055 /* Dump hbonds for debugging */
2056 dump_ac(hb, bMerge || bContact, nDump);
2058 /* Total number of hbonds analyzed here */
2061 if (acType != AC_LUZAR && bOMP)
2063 nThreads = std::min((nThreads <= 0) ? INT_MAX : nThreads, gmx_omp_get_max_threads());
2065 gmx_omp_set_num_threads(nThreads);
2066 snew(dondata, nThreads);
2067 for (i = 0; i < nThreads; i++)
2071 printf("ACF calculations parallelized with OpenMP using %i threads.\n"
2072 "Expect close to linear scaling over this donor-loop.\n",
2075 fprintf(stderr, "Donors: [thread no]\n");
2078 for (i = 0; i < nThreads; i++)
2080 snprintf(tmpstr, 7, "[%i]", i);
2081 fprintf(stderr, "%-7s", tmpstr);
2084 fprintf(stderr, "\n");
2089 snew(rhbex, 2 * n2);
2099 for (i = 0; (i < hb->d.nrd); i++)
2101 for (k = 0; (k < hb->a.nra); k++)
2104 hbh = hb->hbmap[i][k];
2108 if (bMerge || bContact)
2110 if (ISHB(hbh->history[0]))
2119 for (m = 0; (m < hb->maxhydro); m++)
2121 if (bContact ? ISDIST(hbh->history[m]) : ISHB(hbh->history[m]))
2123 g[nhydro] = hbh->g[m];
2124 h[nhydro] = hbh->h[m];
2130 int nf = hbh->nframes;
2131 for (nh = 0; (nh < nhydro); nh++)
2133 int nrint = bContact ? hb->nrdist : hb->nrhb;
2134 if ((((nhbonds + 1) % 10) == 0) || (nhbonds + 1 == nrint))
2136 fprintf(stderr, "\rACF %d/%d", nhbonds + 1, nrint);
2140 for (j = 0; (j < nframes); j++)
2144 ihb = static_cast<int>(is_hb(h[nh], j));
2145 idist = static_cast<int>(is_hb(g[nh], j));
2152 /* For contacts: if a second cut-off is provided, use it,
2153 * otherwise use g(t) = 1-h(t) */
2154 if (!R2 && bContact)
2160 gt[j] = idist * (1 - ihb);
2166 /* The autocorrelation function is normalized after summation only */
2167 low_do_autocorr(nullptr,
2174 hb->time[1] - hb->time[0],
2184 /* Cross correlation analysis for thermodynamics */
2185 for (j = nframes; (j < n2); j++)
2191 cross_corr(n2, ht, gt, dght);
2193 for (j = 0; (j < nn); j++)
2202 fprintf(stderr, "\n");
2205 normalizeACF(ct, ght, static_cast<int>(nhb), nn);
2207 /* Determine tail value for statistics */
2210 for (j = nn / 2; (j < nn); j++)
2213 tail2 += ct[j] * ct[j];
2215 tail /= (nn - int{ nn / 2 });
2216 tail2 /= (nn - int{ nn / 2 });
2217 dtail = std::sqrt(tail2 - tail * tail);
2219 /* Check whether the ACF is long enough */
2222 printf("\nWARNING: Correlation function is probably not long enough\n"
2223 "because the standard deviation in the tail of C(t) > %g\n"
2224 "Tail value (average C(t) over second half of acf): %g +/- %g\n",
2229 for (j = 0; (j < nn); j++)
2232 ct[j] = (cct[j] - tail) / (1 - tail);
2234 /* Compute negative derivative k(t) = -dc(t)/dt */
2235 compute_derivative(nn, hb->time, ct, kt);
2236 for (j = 0; (j < nn); j++)
2244 fp = xvgropen(fn, "Contact Autocorrelation", output_env_get_xvgr_tlabel(oenv), "C(t)", oenv);
2248 fp = xvgropen(fn, "Hydrogen Bond Autocorrelation", output_env_get_xvgr_tlabel(oenv), "C(t)", oenv);
2250 xvgr_legend(fp, asize(legLuzar), legLuzar, oenv);
2253 for (j = 0; (j < nn); j++)
2255 fprintf(fp, "%10g %10g %10g %10g %10g\n", hb->time[j] - hb->time[0], ct[j], cct[j], ght[j], kt[j]);
2259 analyse_corr(nn, hb->time, ct, ght, kt, nullptr, nullptr, nullptr, fit_start, temp);
2261 do_view(oenv, fn, nullptr);
2272 static void init_hbframe(t_hbdata* hb, int nframes, real t)
2276 hb->time[nframes] = t;
2277 hb->nhb[nframes] = 0;
2278 hb->ndist[nframes] = 0;
2279 for (i = 0; (i < max_hx); i++)
2281 hb->nhx[nframes][i] = 0;
2285 static FILE* open_donor_properties_file(const char* fn, t_hbdata* hb, const gmx_output_env_t* oenv)
2288 const char* leg[] = { "Nbound", "Nfree" };
2295 fp = xvgropen(fn, "Donor properties", output_env_get_xvgr_tlabel(oenv), "Number", oenv);
2296 xvgr_legend(fp, asize(leg), leg, oenv);
2301 static void analyse_donor_properties(FILE* fp, t_hbdata* hb, int nframes, real t)
2303 int i, j, k, nbound, nb, nhtot;
2311 for (i = 0; (i < hb->d.nrd); i++)
2313 for (k = 0; (k < hb->d.nhydro[i]); k++)
2317 for (j = 0; (j < hb->a.nra) && (nb == 0); j++)
2319 if (hb->hbmap[i][j] && hb->hbmap[i][j]->h[k] && is_hb(hb->hbmap[i][j]->h[k], nframes))
2327 fprintf(fp, "%10.3e %6d %6d\n", t, nbound, nhtot - nbound);
2330 static void dump_hbmap(t_hbdata* hb,
2338 const t_atoms* atoms)
2341 int ddd, hhh, aaa, i, j, k, m, grp;
2342 char ds[32], hs[32], as[32];
2345 fp = opt2FILE("-hbn", nfile, fnm, "w");
2346 if (opt2bSet("-g", nfile, fnm))
2348 fplog = gmx_ffopen(opt2fn("-g", nfile, fnm), "w");
2349 fprintf(fplog, "# %10s %12s %12s\n", "Donor", "Hydrogen", "Acceptor");
2355 for (grp = gr0; grp <= (bTwo ? gr1 : gr0); grp++)
2357 fprintf(fp, "[ %s ]", grpnames[grp]);
2358 for (i = 0; i < isize[grp]; i++)
2360 fprintf(fp, (i % 15) ? " " : "\n");
2361 fprintf(fp, " %4d", index[grp][i] + 1);
2367 fprintf(fp, "[ donors_hydrogens_%s ]\n", grpnames[grp]);
2368 for (i = 0; (i < hb->d.nrd); i++)
2370 if (hb->d.grp[i] == grp)
2372 for (j = 0; (j < hb->d.nhydro[i]); j++)
2374 fprintf(fp, " %4d %4d", hb->d.don[i] + 1, hb->d.hydro[i][j] + 1);
2380 fprintf(fp, "[ acceptors_%s ]", grpnames[grp]);
2381 for (i = 0; (i < hb->a.nra); i++)
2383 if (hb->a.grp[i] == grp)
2385 fprintf(fp, (i % 15 && !first) ? " " : "\n");
2386 fprintf(fp, " %4d", hb->a.acc[i] + 1);
2395 fprintf(fp, bContact ? "[ contacts_%s-%s ]\n" : "[ hbonds_%s-%s ]\n", grpnames[0], grpnames[1]);
2399 fprintf(fp, bContact ? "[ contacts_%s ]" : "[ hbonds_%s ]\n", grpnames[0]);
2402 for (i = 0; (i < hb->d.nrd); i++)
2405 for (k = 0; (k < hb->a.nra); k++)
2408 for (m = 0; (m < hb->d.nhydro[i]); m++)
2410 if (hb->hbmap[i][k] && ISHB(hb->hbmap[i][k]->history[m]))
2412 sprintf(ds, "%s", mkatomname(atoms, ddd));
2413 sprintf(as, "%s", mkatomname(atoms, aaa));
2416 fprintf(fp, " %6d %6d\n", ddd + 1, aaa + 1);
2419 fprintf(fplog, "%12s %12s\n", ds, as);
2424 hhh = hb->d.hydro[i][m];
2425 sprintf(hs, "%s", mkatomname(atoms, hhh));
2426 fprintf(fp, " %6d %6d %6d\n", ddd + 1, hhh + 1, aaa + 1);
2429 fprintf(fplog, "%12s %12s %12s\n", ds, hs, as);
2443 /* sync_hbdata() updates the parallel t_hbdata p_hb using hb as template.
2444 * It mimics add_frames() and init_frame() to some extent. */
2445 static void sync_hbdata(t_hbdata* p_hb, int nframes)
2447 if (nframes >= p_hb->max_frames)
2449 p_hb->max_frames += 4096;
2450 srenew(p_hb->nhb, p_hb->max_frames);
2451 srenew(p_hb->ndist, p_hb->max_frames);
2452 srenew(p_hb->n_bound, p_hb->max_frames);
2453 srenew(p_hb->nhx, p_hb->max_frames);
2456 srenew(p_hb->danr, p_hb->max_frames);
2458 std::memset(&(p_hb->nhb[nframes]), 0, sizeof(int) * (p_hb->max_frames - nframes));
2459 std::memset(&(p_hb->ndist[nframes]), 0, sizeof(int) * (p_hb->max_frames - nframes));
2460 p_hb->nhb[nframes] = 0;
2461 p_hb->ndist[nframes] = 0;
2463 p_hb->nframes = nframes;
2465 std::memset(&(p_hb->nhx[nframes]), 0, sizeof(int) * max_hx); /* zero the helix count for this frame */
2468 int gmx_hbond(int argc, char* argv[])
2470 const char* desc[] = {
2471 "[THISMODULE] computes and analyzes hydrogen bonds. Hydrogen bonds are",
2472 "determined based on cutoffs for the angle Hydrogen - Donor - Acceptor",
2473 "(zero is extended) and the distance Donor - Acceptor",
2474 "(or Hydrogen - Acceptor using [TT]-noda[tt]).",
2475 "OH and NH groups are regarded as donors, O is an acceptor always,",
2476 "N is an acceptor by default, but this can be switched using",
2477 "[TT]-nitacc[tt]. Dummy hydrogen atoms are assumed to be connected",
2478 "to the first preceding non-hydrogen atom.[PAR]",
2480 "You need to specify two groups for analysis, which must be either",
2481 "identical or non-overlapping. All hydrogen bonds between the two",
2482 "groups are analyzed.[PAR]",
2484 "If you set [TT]-shell[tt], you will be asked for an additional index group",
2485 "which should contain exactly one atom. In this case, only hydrogen",
2486 "bonds between atoms within the shell distance from the one atom are",
2489 "With option -ac, rate constants for hydrogen bonding can be derived with the",
2490 "model of Luzar and Chandler (Nature 379:55, 1996; J. Chem. Phys. 113:23, 2000).",
2491 "If contact kinetics are analyzed by using the -contact option, then",
2492 "n(t) can be defined as either all pairs that are not within contact distance r at time t",
2493 "(corresponding to leaving the -r2 option at the default value 0) or all pairs that",
2494 "are within distance r2 (corresponding to setting a second cut-off value with option -r2).",
2495 "See mentioned literature for more details and definitions.",
2498 /* "It is also possible to analyse specific hydrogen bonds with",
2499 "[TT]-sel[tt]. This index file must contain a group of atom triplets",
2500 "Donor Hydrogen Acceptor, in the following way::",
2507 "Note that the triplets need not be on separate lines.",
2508 "Each atom triplet specifies a hydrogen bond to be analyzed,",
2509 "note also that no check is made for the types of atoms.[PAR]",
2514 " * [TT]-num[tt]: number of hydrogen bonds as a function of time.",
2515 " * [TT]-ac[tt]: average over all autocorrelations of the existence",
2516 " functions (either 0 or 1) of all hydrogen bonds.",
2517 " * [TT]-dist[tt]: distance distribution of all hydrogen bonds.",
2518 " * [TT]-ang[tt]: angle distribution of all hydrogen bonds.",
2519 " * [TT]-hx[tt]: the number of n-n+i hydrogen bonds as a function of time",
2520 " where n and n+i stand for residue numbers and i ranges from 0 to 6.",
2521 " This includes the n-n+3, n-n+4 and n-n+5 hydrogen bonds associated",
2522 " with helices in proteins.",
2523 " * [TT]-hbn[tt]: all selected groups, donors, hydrogens and acceptors",
2524 " for selected groups, all hydrogen bonded atoms from all groups and",
2525 " all solvent atoms involved in insertion.",
2526 " * [TT]-hbm[tt]: existence matrix for all hydrogen bonds over all",
2527 " frames, this also contains information on solvent insertion",
2528 " into hydrogen bonds. Ordering is identical to that in [TT]-hbn[tt]",
2530 " * [TT]-dan[tt]: write out the number of donors and acceptors analyzed for",
2531 " each timeframe. This is especially useful when using [TT]-shell[tt].",
2532 " * [TT]-nhbdist[tt]: compute the number of HBonds per hydrogen in order to",
2533 " compare results to Raman Spectroscopy.",
2535 "Note: options [TT]-ac[tt], [TT]-life[tt], [TT]-hbn[tt] and [TT]-hbm[tt]",
2536 "require an amount of memory proportional to the total numbers of donors",
2537 "times the total number of acceptors in the selected group(s)."
2540 static real acut = 30, abin = 1, rcut = 0.35, r2cut = 0, rbin = 0.005, rshell = -1;
2541 static real maxnhb = 0, fit_start = 1, fit_end = 60, temp = 298.15;
2542 static gmx_bool bNitAcc = TRUE, bDA = TRUE, bMerge = TRUE;
2543 static int nDump = 0;
2544 static int nThreads = 0;
2546 static gmx_bool bContact = FALSE;
2550 { "-a", FALSE, etREAL, { &acut }, "Cutoff angle (degrees, Hydrogen - Donor - Acceptor)" },
2551 { "-r", FALSE, etREAL, { &rcut }, "Cutoff radius (nm, X - Acceptor, see next option)" },
2556 "Use distance Donor-Acceptor (if TRUE) or Hydrogen-Acceptor (FALSE)" },
2561 "Second cutoff radius. Mainly useful with [TT]-contact[tt] and [TT]-ac[tt]" },
2562 { "-abin", FALSE, etREAL, { &abin }, "Binwidth angle distribution (degrees)" },
2563 { "-rbin", FALSE, etREAL, { &rbin }, "Binwidth distance distribution (nm)" },
2564 { "-nitacc", FALSE, etBOOL, { &bNitAcc }, "Regard nitrogen atoms as acceptors" },
2569 "Do not look for hydrogen bonds, but merely for contacts within the cut-off distance" },
2574 "when > 0, only calculate hydrogen bonds within # nm shell around "
2580 "Time (ps) from which to start fitting the correlation functions in order to obtain the "
2581 "forward and backward rate constants for HB breaking and formation. With [TT]-gemfit[tt] "
2582 "we suggest [TT]-fitstart 0[tt]" },
2587 "Time (ps) to which to stop fitting the correlation functions in order to obtain the "
2588 "forward and backward rate constants for HB breaking and formation (only with "
2589 "[TT]-gemfit[tt])" },
2594 "Temperature (K) for computing the Gibbs energy corresponding to HB breaking and "
2600 "Dump the first N hydrogen bond ACFs in a single [REF].xvg[ref] file for debugging" },
2605 "Theoretical maximum number of hydrogen bonds used for normalizing HB autocorrelation "
2606 "function. Can be useful in case the program estimates it wrongly" },
2611 "H-bonds between the same donor and acceptor, but with different hydrogen are treated as "
2612 "a single H-bond. Mainly important for the ACF." },
2618 "Number of threads used for the parallel loop over autocorrelations. nThreads <= 0 means "
2619 "maximum number of threads. Requires linking with OpenMP. The number of threads is "
2620 "limited by the number of cores (before OpenMP v.3 ) or environment variable "
2621 "OMP_THREAD_LIMIT (OpenMP v.3)" },
2624 const char* bugs[] = {
2625 "The option [TT]-sel[tt] that used to work on selected hbonds is out of order, and "
2626 "therefore not available for the time being."
2628 t_filenm fnm[] = { { efTRX, "-f", nullptr, ffREAD },
2629 { efTPR, nullptr, nullptr, ffREAD },
2630 { efNDX, nullptr, nullptr, ffOPTRD },
2631 /* { efNDX, "-sel", "select", ffOPTRD },*/
2632 { efXVG, "-num", "hbnum", ffWRITE },
2633 { efLOG, "-g", "hbond", ffOPTWR },
2634 { efXVG, "-ac", "hbac", ffOPTWR },
2635 { efXVG, "-dist", "hbdist", ffOPTWR },
2636 { efXVG, "-ang", "hbang", ffOPTWR },
2637 { efXVG, "-hx", "hbhelix", ffOPTWR },
2638 { efNDX, "-hbn", "hbond", ffOPTWR },
2639 { efXPM, "-hbm", "hbmap", ffOPTWR },
2640 { efXVG, "-don", "donor", ffOPTWR },
2641 { efXVG, "-dan", "danum", ffOPTWR },
2642 { efXVG, "-life", "hblife", ffOPTWR },
2643 { efXVG, "-nhbdist", "nhbdist", ffOPTWR }
2646 #define NFILE asize(fnm)
2648 char hbmap[HB_NR] = { ' ', 'o', '-', '*' };
2649 const char* hbdesc[HB_NR] = { "None", "Present", "Inserted", "Present & Inserted" };
2650 t_rgb hbrgb[HB_NR] = { { 1, 1, 1 }, { 1, 0, 0 }, { 0, 0, 1 }, { 1, 0, 1 } };
2652 t_trxstatus* status;
2653 bool trrStatus = true;
2656 int npargs, natoms, nframes = 0, shatom;
2662 real t, ccut, dist = 0.0, ang = 0.0;
2663 double max_nhb, aver_nhb, aver_dist;
2664 int h = 0, i = 0, j, k = 0, ogrp, nsel;
2665 int xi = 0, yi, zi, ai;
2666 int xj, yj, zj, aj, xjj, yjj, zjj;
2667 gmx_bool bSelected, bHBmap, bStop, bTwo, bBox, bTric;
2668 int * adist, *rdist;
2669 int grp, nabin, nrbin, resdist, ihb;
2672 FILE * fp, *fpnhb = nullptr, *donor_properties = nullptr;
2674 t_ncell * icell, *jcell;
2676 unsigned char* datable;
2677 gmx_output_env_t* oenv;
2678 int ii, hh, actual_nThreads;
2681 gmx_bool bEdge_yjj, bEdge_xjj;
2683 t_hbdata** p_hb = nullptr; /* one per thread, then merge after the frame loop */
2684 int ** p_adist = nullptr, **p_rdist = nullptr; /* a histogram for each thread. */
2686 const bool bOMP = GMX_OPENMP;
2689 ppa = add_acf_pargs(&npargs, pa);
2691 if (!parse_common_args(
2692 &argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT, NFILE, fnm, npargs, ppa, asize(desc), desc, asize(bugs), bugs, &oenv))
2700 ccut = std::cos(acut * gmx::c_deg2Rad);
2706 gmx_fatal(FARGS, "Can not analyze selected contacts.");
2710 gmx_fatal(FARGS, "Can not analyze contact between H and A: turn off -noda");
2714 /* Initiate main data structure! */
2715 bHBmap = (opt2bSet("-ac", NFILE, fnm) || opt2bSet("-life", NFILE, fnm)
2716 || opt2bSet("-hbn", NFILE, fnm) || opt2bSet("-hbm", NFILE, fnm));
2718 if (opt2bSet("-nhbdist", NFILE, fnm))
2720 const char* leg[MAXHH + 1] = { "0 HBs", "1 HB", "2 HBs", "3 HBs", "Total" };
2721 fpnhb = xvgropen(opt2fn("-nhbdist", NFILE, fnm),
2722 "Number of donor-H with N HBs",
2723 output_env_get_xvgr_tlabel(oenv),
2726 xvgr_legend(fpnhb, asize(leg), leg, oenv);
2729 hb = mk_hbdata(bHBmap, opt2bSet("-dan", NFILE, fnm), bMerge || bContact);
2732 t_inputrec irInstance;
2733 t_inputrec* ir = &irInstance;
2734 read_tpx_top(ftp2fn(efTPR, NFILE, fnm), ir, box, &natoms, nullptr, nullptr, &top);
2736 snew(grpnames, grNR);
2739 /* Make Donor-Acceptor table */
2740 snew(datable, top.atoms.nr);
2744 /* analyze selected hydrogen bonds */
2745 printf("Select group with selected atoms:\n");
2746 get_index(&(top.atoms), opt2fn("-sel", NFILE, fnm), 1, &nsel, index, grpnames);
2750 "Number of atoms in group '%s' not a multiple of 3\n"
2751 "and therefore cannot contain triplets of "
2752 "Donor-Hydrogen-Acceptor",
2757 for (i = 0; (i < nsel); i += 3)
2759 int dd = index[0][i];
2760 int aa = index[0][i + 2];
2761 /* int */ hh = index[0][i + 1];
2762 add_dh(&hb->d, dd, hh, i, datable);
2763 add_acc(&hb->a, aa, i);
2764 /* Should this be here ? */
2765 snew(hb->d.dptr, top.atoms.nr);
2766 snew(hb->a.aptr, top.atoms.nr);
2767 add_hbond(hb, dd, aa, hh, gr0, gr0, 0, bMerge, 0, bContact);
2769 printf("Analyzing %d selected hydrogen bonds from '%s'\n", isize[0], grpnames[0]);
2773 /* analyze all hydrogen bonds: get group(s) */
2774 printf("Specify 2 groups to analyze:\n");
2775 get_index(&(top.atoms), ftp2fn_null(efNDX, NFILE, fnm), 2, isize, index, grpnames);
2777 /* check if we have two identical or two non-overlapping groups */
2778 bTwo = isize[0] != isize[1];
2779 for (i = 0; (i < isize[0]) && !bTwo; i++)
2781 bTwo = index[0][i] != index[1][i];
2785 printf("Checking for overlap in atoms between %s and %s\n", grpnames[0], grpnames[1]);
2787 gen_datable(index[0], isize[0], datable, top.atoms.nr);
2789 for (i = 0; i < isize[1]; i++)
2791 if (ISINGRP(datable[index[1][i]]))
2793 gmx_fatal(FARGS, "Partial overlap between groups '%s' and '%s'", grpnames[0], grpnames[1]);
2799 printf("Calculating %s "
2800 "between %s (%d atoms) and %s (%d atoms)\n",
2801 bContact ? "contacts" : "hydrogen bonds",
2810 "Calculating %s in %s (%d atoms)\n",
2811 bContact ? "contacts" : "hydrogen bonds",
2818 /* search donors and acceptors in groups */
2819 snew(datable, top.atoms.nr);
2820 for (i = 0; (i < grNR); i++)
2822 if (((i == gr0) && !bSelected) || ((i == gr1) && bTwo))
2824 gen_datable(index[i], isize[i], datable, top.atoms.nr);
2828 &top, isize[i], index[i], &hb->a, i, bNitAcc, TRUE, (bTwo && (i == gr0)) || !bTwo, datable);
2829 search_donors(&top, isize[i], index[i], &hb->d, i, TRUE, (bTwo && (i == gr1)) || !bTwo, datable);
2833 search_acceptors(&top, isize[i], index[i], &hb->a, i, bNitAcc, FALSE, TRUE, datable);
2834 search_donors(&top, isize[i], index[i], &hb->d, i, FALSE, TRUE, datable);
2838 clear_datable_grp(datable, top.atoms.nr);
2843 printf("Found %d donors and %d acceptors\n", hb->d.nrd, hb->a.nra);
2845 snew(donors[gr0D], dons[gr0D].nrd);*/
2847 donor_properties = open_donor_properties_file(opt2fn_null("-don", NFILE, fnm), hb, oenv);
2851 printf("Making hbmap structure...");
2852 /* Generate hbond data structure */
2859 if (hb->d.nrd + hb->a.nra == 0)
2861 printf("No Donors or Acceptors found\n");
2868 printf("No Donors found\n");
2873 printf("No Acceptors found\n");
2879 gmx_fatal(FARGS, "Nothing to be done");
2888 /* get index group with atom for shell */
2891 printf("Select atom for shell (1 atom):\n");
2892 get_index(&(top.atoms), ftp2fn_null(efNDX, NFILE, fnm), 1, &shisz, &shidx, &shgrpnm);
2895 printf("group contains %d atoms, should be 1 (one)\n", shisz);
2897 } while (shisz != 1);
2899 printf("Will calculate hydrogen bonds within a shell "
2900 "of %g nm around atom %i\n",
2905 /* Analyze trajectory */
2906 natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box);
2907 if (natoms > top.atoms.nr)
2909 gmx_fatal(FARGS, "Topology (%d atoms) does not match trajectory (%d atoms)", top.atoms.nr, natoms);
2912 bBox = (ir->pbcType != PbcType::No);
2913 grid = init_grid(bBox, box, (rcut > r2cut) ? rcut : r2cut, ngrid);
2914 nabin = static_cast<int>(acut / abin);
2915 nrbin = static_cast<int>(rcut / rbin);
2916 snew(adist, nabin + 1);
2917 snew(rdist, nrbin + 1);
2920 # define __ADIST adist // NOLINT(bugprone-reserved-identifier)
2921 # define __RDIST rdist // NOLINT(bugprone-reserved-identifier)
2922 # define __HBDATA hb // NOLINT(bugprone-reserved-identifier)
2923 #else /* GMX_OPENMP ================================================== \
2924 * Set up the OpenMP stuff, | \
2925 * like the number of threads and such | \
2926 * Also start the parallel loop. | \
2928 # define __ADIST p_adist[threadNr] // NOLINT(bugprone-reserved-identifier)
2929 # define __RDIST p_rdist[threadNr] // NOLINT(bugprone-reserved-identifier)
2930 # define __HBDATA p_hb[threadNr] // NOLINT(bugprone-reserved-identifier)
2934 bParallel = !bSelected;
2938 actual_nThreads = std::min((nThreads <= 0) ? INT_MAX : nThreads, gmx_omp_get_max_threads());
2940 gmx_omp_set_num_threads(actual_nThreads);
2941 printf("Frame loop parallelized with OpenMP using %i threads.\n", actual_nThreads);
2946 actual_nThreads = 1;
2949 snew(p_hb, actual_nThreads);
2950 snew(p_adist, actual_nThreads);
2951 snew(p_rdist, actual_nThreads);
2952 for (i = 0; i < actual_nThreads; i++)
2955 snew(p_adist[i], nabin + 1);
2956 snew(p_rdist[i], nrbin + 1);
2958 p_hb[i]->max_frames = 0;
2959 p_hb[i]->nhb = nullptr;
2960 p_hb[i]->ndist = nullptr;
2961 p_hb[i]->n_bound = nullptr;
2962 p_hb[i]->time = nullptr;
2963 p_hb[i]->nhx = nullptr;
2965 p_hb[i]->bHBmap = hb->bHBmap;
2966 p_hb[i]->bDAnr = hb->bDAnr;
2967 p_hb[i]->wordlen = hb->wordlen;
2968 p_hb[i]->nframes = hb->nframes;
2969 p_hb[i]->maxhydro = hb->maxhydro;
2970 p_hb[i]->danr = hb->danr;
2973 p_hb[i]->hbmap = hb->hbmap;
2974 p_hb[i]->time = hb->time; /* This may need re-syncing at every frame. */
2977 p_hb[i]->nrdist = 0;
2981 /* Make a thread pool here,
2982 * instead of forking anew at every frame. */
2984 #pragma omp parallel firstprivate(i) private(j, \
3011 bEdge_yjj) default(shared)
3012 { /* Start of parallel region */
3015 threadNr = gmx_omp_get_thread_num();
3020 bTric = bBox && TRICLINIC(box);
3026 sync_hbdata(p_hb[threadNr], nframes);
3028 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3034 build_grid(hb, x, x[shatom], bBox, box, hbox, (rcut > r2cut) ? rcut : r2cut, rshell, ngrid, grid);
3035 reset_nhbonds(&(hb->d));
3037 if (debug && bDebug)
3039 dump_grid(debug, ngrid, grid);
3042 add_frames(hb, nframes);
3043 init_hbframe(hb, nframes, output_env_conv_time(oenv, t));
3047 count_da_grid(ngrid, grid, hb->danr[nframes]);
3050 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3055 p_hb[threadNr]->time = hb->time; /* This pointer may have changed. */
3065 /* Do not parallelize this just yet. */
3067 for (ii = 0; (ii < nsel); ii++)
3069 int dd = index[0][i];
3070 int aa = index[0][i + 2];
3071 /* int */ hh = index[0][i + 1];
3073 hb, ii, ii, dd, aa, rcut, r2cut, ccut, x, bBox, box, hbox, &dist, &ang, bDA, &h, bContact, bMerge);
3077 /* add to index if not already there */
3079 add_hbond(hb, dd, aa, hh, ii, ii, nframes, bMerge, ihb, bContact);
3083 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3085 } /* if (bSelected) */
3088 /* The outer grid loop will have to do for now. */
3089 #pragma omp for schedule(dynamic)
3090 for (xi = 0; xi < ngrid[XX]; xi++)
3094 for (yi = 0; (yi < ngrid[YY]); yi++)
3096 for (zi = 0; (zi < ngrid[ZZ]); zi++)
3099 /* loop over donor groups gr0 (always) and gr1 (if necessary) */
3100 for (grp = gr0; (grp <= (bTwo ? gr1 : gr0)); grp++)
3102 icell = &(grid[zi][yi][xi].d[grp]);
3113 /* loop over all hydrogen atoms from group (grp)
3114 * in this gridcell (icell)
3116 for (ai = 0; (ai < icell->nr); ai++)
3118 i = icell->atoms[ai];
3120 /* loop over all adjacent gridcells (xj,yj,zj) */
3121 for (zjj = grid_loop_begin(ngrid[ZZ], zi, bTric, FALSE);
3122 zjj <= grid_loop_end(ngrid[ZZ], zi, bTric, FALSE);
3125 zj = grid_mod(zjj, ngrid[ZZ]);
3126 bEdge_yjj = (zj == 0) || (zj == ngrid[ZZ] - 1);
3127 for (yjj = grid_loop_begin(ngrid[YY], yi, bTric, bEdge_yjj);
3128 yjj <= grid_loop_end(ngrid[YY], yi, bTric, bEdge_yjj);
3131 yj = grid_mod(yjj, ngrid[YY]);
3132 bEdge_xjj = (yj == 0) || (yj == ngrid[YY] - 1)
3133 || (zj == 0) || (zj == ngrid[ZZ] - 1);
3134 for (xjj = grid_loop_begin(ngrid[XX], xi, bTric, bEdge_xjj);
3135 xjj <= grid_loop_end(ngrid[XX], xi, bTric, bEdge_xjj);
3138 xj = grid_mod(xjj, ngrid[XX]);
3139 jcell = &(grid[zj][yj][xj].a[ogrp]);
3140 /* loop over acceptor atoms from other group
3141 * (ogrp) in this adjacent gridcell (jcell)
3143 for (aj = 0; (aj < jcell->nr); aj++)
3145 j = jcell->atoms[aj];
3147 /* check if this once was a h-bond */
3148 ihb = is_hbond(__HBDATA,
3169 /* add to index if not already there */
3171 add_hbond(__HBDATA, i, j, h, grp, ogrp, nframes, bMerge, ihb, bContact);
3173 /* make angle and distance distributions */
3174 if (ihb == hbHB && !bContact)
3180 "distance is higher "
3181 "than what is allowed "
3185 ang *= gmx::c_rad2Deg;
3186 __ADIST[static_cast<int>(ang / abin)]++;
3187 __RDIST[static_cast<int>(dist / rbin)]++;
3190 if (donor_index(&hb->d, grp, i) == NOTSET)
3197 if (acceptor_index(&hb->a, ogrp, j)
3206 top.atoms.atom[i].resind
3207 - top.atoms.atom[j].resind);
3208 if (resdist >= max_hx)
3210 resdist = max_hx - 1;
3212 __HBDATA->nhx[nframes][resdist]++;
3222 } /* for xi,yi,zi */
3225 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3227 } /* if (bSelected) {...} else */
3230 /* Better wait for all threads to finnish using x[] before updating it. */
3233 #pragma omp critical
3237 /* Sum up histograms and counts from p_hb[] into hb */
3240 hb->nhb[k] += p_hb[threadNr]->nhb[k];
3241 hb->ndist[k] += p_hb[threadNr]->ndist[k];
3242 for (j = 0; j < max_hx; j++)
3244 hb->nhx[k][j] += p_hb[threadNr]->nhx[k][j];
3248 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3251 /* Here are a handful of single constructs
3252 * to share the workload a bit. The most
3253 * important one is of course the last one,
3254 * where there's a potential bottleneck in form
3261 analyse_donor_properties(donor_properties, hb, k, t);
3263 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3272 do_nhb_dist(fpnhb, hb, t);
3275 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3282 trrStatus = (read_next_x(oenv, status, &t, x, box));
3285 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3289 } while (trrStatus);
3293 #pragma omp critical
3295 hb->nrhb += p_hb[threadNr]->nrhb;
3296 hb->nrdist += p_hb[threadNr]->nrdist;
3299 /* Free parallel datastructures */
3300 sfree(p_hb[threadNr]->nhb);
3301 sfree(p_hb[threadNr]->ndist);
3302 sfree(p_hb[threadNr]->nhx);
3305 for (i = 0; i < nabin; i++)
3309 for (j = 0; j < actual_nThreads; j++)
3312 adist[i] += p_adist[j][i];
3315 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3318 for (i = 0; i <= nrbin; i++)
3322 for (j = 0; j < actual_nThreads; j++)
3324 rdist[i] += p_rdist[j][i];
3327 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
3330 sfree(p_adist[threadNr]);
3331 sfree(p_rdist[threadNr]);
3333 } /* End of parallel region */
3340 if (nframes < 2 && (opt2bSet("-ac", NFILE, fnm) || opt2bSet("-life", NFILE, fnm)))
3342 gmx_fatal(FARGS, "Cannot calculate autocorrelation of life times with less than two frames");
3345 free_grid(ngrid, &grid);
3349 if (donor_properties)
3351 xvgrclose(donor_properties);
3359 /* Compute maximum possible number of different hbonds */
3366 max_nhb = 0.5 * (hb->d.nrd * hb->a.nra);
3373 printf("No %s found!!\n", bContact ? "contacts" : "hydrogen bonds");
3377 printf("Found %d different %s in trajectory\n"
3378 "Found %d different atom-pairs within %s distance\n",
3380 bContact ? "contacts" : "hydrogen bonds",
3382 (r2cut > 0) ? "second cut-off" : "hydrogen bonding");
3386 merge_hb(hb, bTwo, bContact);
3389 if (opt2bSet("-hbn", NFILE, fnm))
3391 dump_hbmap(hb, NFILE, fnm, bTwo, bContact, isize, index, grpnames, &top.atoms);
3394 /* Moved the call to merge_hb() to a line BEFORE dump_hbmap
3395 * to make the -hbn and -hmb output match eachother.
3396 * - Erik Marklund, May 30, 2006 */
3399 /* Print out number of hbonds and distances */
3402 fp = xvgropen(opt2fn("-num", NFILE, fnm),
3403 bContact ? "Contacts" : "Hydrogen Bonds",
3404 output_env_get_xvgr_tlabel(oenv),
3408 snew(leg[0], STRLEN);
3409 snew(leg[1], STRLEN);
3410 sprintf(leg[0], "%s", bContact ? "Contacts" : "Hydrogen bonds");
3411 sprintf(leg[1], "Pairs within %g nm", (r2cut > 0) ? r2cut : rcut);
3412 xvgr_legend(fp, 2, leg, oenv);
3416 for (i = 0; (i < nframes); i++)
3418 fprintf(fp, "%10g %10d %10d\n", hb->time[i], hb->nhb[i], hb->ndist[i]);
3419 aver_nhb += hb->nhb[i];
3420 aver_dist += hb->ndist[i];
3423 aver_nhb /= nframes;
3424 aver_dist /= nframes;
3425 /* Print HB distance distribution */
3426 if (opt2bSet("-dist", NFILE, fnm))
3431 for (i = 0; i < nrbin; i++)
3436 fp = xvgropen(opt2fn("-dist", NFILE, fnm),
3437 "Hydrogen Bond Distribution",
3438 bDA ? "Donor - Acceptor Distance (nm)" : "Hydrogen - Acceptor Distance (nm)",
3441 for (i = 0; i < nrbin; i++)
3443 fprintf(fp, "%10g %10g\n", (i + 0.5) * rbin, rdist[i] / (rbin * sum));
3448 /* Print HB angle distribution */
3449 if (opt2bSet("-ang", NFILE, fnm))
3454 for (i = 0; i < nabin; i++)
3459 fp = xvgropen(opt2fn("-ang", NFILE, fnm),
3460 "Hydrogen Bond Distribution",
3461 "Hydrogen - Donor - Acceptor Angle (\\SO\\N)",
3464 for (i = 0; i < nabin; i++)
3466 fprintf(fp, "%10g %10g\n", (i + 0.5) * abin, adist[i] / (abin * sum));
3471 /* Print HB in alpha-helix */
3472 if (opt2bSet("-hx", NFILE, fnm))
3474 fp = xvgropen(opt2fn("-hx", NFILE, fnm),
3476 output_env_get_xvgr_tlabel(oenv),
3479 xvgr_legend(fp, NRHXTYPES, hxtypenames, oenv);
3480 for (i = 0; i < nframes; i++)
3482 fprintf(fp, "%10g", hb->time[i]);
3483 for (j = 0; j < max_hx; j++)
3485 fprintf(fp, " %6d", hb->nhx[i][j]);
3492 printf("Average number of %s per timeframe %.3f out of %g possible\n",
3493 bContact ? "contacts" : "hbonds",
3494 bContact ? aver_dist : aver_nhb,
3497 /* Do Autocorrelation etc. */
3501 Added support for -contact in ac and hbm calculations below.
3502 - Erik Marklund, May 29, 2006
3504 if (opt2bSet("-ac", NFILE, fnm) || opt2bSet("-life", NFILE, fnm))
3506 please_cite(stdout, "Spoel2006b");
3508 if (opt2bSet("-ac", NFILE, fnm))
3510 do_hbac(opt2fn("-ac", NFILE, fnm), hb, nDump, bMerge, bContact, fit_start, temp, r2cut > 0, oenv, nThreads);
3512 if (opt2bSet("-life", NFILE, fnm))
3514 do_hblife(opt2fn("-life", NFILE, fnm), hb, bMerge, bContact, oenv);
3516 if (opt2bSet("-hbm", NFILE, fnm))
3519 int id, ia, hh, x, y;
3522 if ((nframes > 0) && (hb->nrhb > 0))
3527 mat.matrix.resize(mat.nx, mat.ny);
3528 mat.axis_x.resize(mat.nx);
3529 for (auto& value : mat.matrix.toArrayRef())
3534 for (id = 0; (id < hb->d.nrd); id++)
3536 for (ia = 0; (ia < hb->a.nra); ia++)
3538 for (hh = 0; (hh < hb->maxhydro); hh++)
3540 if (hb->hbmap[id][ia])
3542 if (ISHB(hb->hbmap[id][ia]->history[hh]))
3544 for (x = 0; (x <= hb->hbmap[id][ia]->nframes); x++)
3546 int nn0 = hb->hbmap[id][ia]->n0;
3547 range_check(y, 0, mat.ny);
3548 mat.matrix(x + nn0, y) = static_cast<t_matelmt>(
3549 is_hb(hb->hbmap[id][ia]->h[hh], x));
3557 std::copy(hb->time, hb->time + mat.nx, mat.axis_x.begin());
3558 mat.axis_y.resize(mat.ny);
3559 std::iota(mat.axis_y.begin(), mat.axis_y.end(), 0);
3560 mat.title = (bContact ? "Contact Existence Map" : "Hydrogen Bond Existence Map");
3561 mat.legend = bContact ? "Contacts" : "Hydrogen Bonds";
3562 mat.label_x = output_env_get_xvgr_tlabel(oenv);
3563 mat.label_y = bContact ? "Contact Index" : "Hydrogen Bond Index";
3564 mat.bDiscrete = true;
3568 for (auto& m : mat.map)
3570 m.code.c1 = hbmap[i];
3576 fp = opt2FILE("-hbm", NFILE, fnm, "w");
3577 write_xpm_m(fp, mat);
3583 "No hydrogen bonds/contacts found. No hydrogen bond map will be "
3595 #define USE_THIS_GROUP(j) (((j) == gr0) || (bTwo && ((j) == gr1)))
3597 fp = xvgropen(opt2fn("-dan", NFILE, fnm),
3598 "Donors and Acceptors",
3599 output_env_get_xvgr_tlabel(oenv),
3602 nleg = (bTwo ? 2 : 1) * 2;
3603 snew(legnames, nleg);
3605 for (j = 0; j < grNR; j++)
3607 if (USE_THIS_GROUP(j))
3609 sprintf(buf, "Donors %s", grpnames[j]);
3610 legnames[i++] = gmx_strdup(buf);
3611 sprintf(buf, "Acceptors %s", grpnames[j]);
3612 legnames[i++] = gmx_strdup(buf);
3617 gmx_incons("number of legend entries");
3619 xvgr_legend(fp, nleg, legnames, oenv);
3620 for (i = 0; i < nframes; i++)
3622 fprintf(fp, "%10g", hb->time[i]);
3623 for (j = 0; (j < grNR); j++)
3625 if (USE_THIS_GROUP(j))
3627 fprintf(fp, " %6d", hb->danr[i][j]);