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, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
43 #include "gromacs/commandline/pargs.h"
44 #include "gromacs/correlationfunctions/autocorr.h"
45 #include "gromacs/correlationfunctions/crosscorr.h"
46 #include "gromacs/correlationfunctions/expfit.h"
47 #include "gromacs/correlationfunctions/integrate.h"
48 #include "gromacs/fileio/matio.h"
49 #include "gromacs/fileio/tpxio.h"
50 #include "gromacs/fileio/trxio.h"
51 #include "gromacs/fileio/xvgr.h"
52 #include "gromacs/gmxana/gmx_ana.h"
53 #include "gromacs/legacyheaders/copyrite.h"
54 #include "gromacs/legacyheaders/macros.h"
55 #include "gromacs/legacyheaders/txtdump.h"
56 #include "gromacs/legacyheaders/viewit.h"
57 #include "gromacs/math/units.h"
58 #include "gromacs/math/vec.h"
59 #include "gromacs/pbcutil/pbc.h"
60 #include "gromacs/topology/index.h"
61 #include "gromacs/utility/cstringutil.h"
62 #include "gromacs/utility/fatalerror.h"
63 #include "gromacs/utility/futil.h"
64 #include "gromacs/utility/gmxomp.h"
65 #include "gromacs/utility/smalloc.h"
66 #include "gromacs/utility/snprintf.h"
69 typedef int t_hx[max_hx];
70 #define NRHXTYPES max_hx
71 const char *hxtypenames[NRHXTYPES] =
72 {"n-n", "n-n+1", "n-n+2", "n-n+3", "n-n+4", "n-n+5", "n-n>6"};
76 #define MASTER_THREAD_ONLY(threadNr) ((threadNr) == 0)
78 #define MASTER_THREAD_ONLY(threadNr) ((threadNr) == (threadNr))
81 /* -----------------------------------------*/
87 hbNo, hbDist, hbHB, hbNR, hbR2
90 noDA, ACC, DON, DA, INGROUP
93 static const char *grpnames[grNR] = {"0", "1", "I" };
95 static gmx_bool bDebug = FALSE;
100 #define HB_YESINS HB_YES|HB_INS
104 #define ISHB(h) (((h) & 2) == 2)
105 #define ISDIST(h) (((h) & 1) == 1)
106 #define ISDIST2(h) (((h) & 4) == 4)
107 #define ISACC(h) (((h) & 1) == 1)
108 #define ISDON(h) (((h) & 2) == 2)
109 #define ISINGRP(h) (((h) & 4) == 4)
122 typedef int t_icell[grNR];
123 typedef atom_id h_id[MAXHYDRO];
126 int history[MAXHYDRO];
127 /* Has this hbond existed ever? If so as hbDist or hbHB or both.
128 * Result is stored as a bitmap (1 = hbDist) || (2 = hbHB)
130 /* Bitmask array which tells whether a hbond is present
131 * at a given time. Either of these may be NULL
133 int n0; /* First frame a HB was found */
134 int nframes, maxframes; /* Amount of frames in this hbond */
137 /* See Xu and Berne, JPCB 105 (2001), p. 11929. We define the
138 * function g(t) = [1-h(t)] H(t) where H(t) is one when the donor-
139 * acceptor distance is less than the user-specified distance (typically
146 atom_id *acc; /* Atom numbers of the acceptors */
147 int *grp; /* Group index */
148 int *aptr; /* Map atom number to acceptor index */
153 int *don; /* Atom numbers of the donors */
154 int *grp; /* Group index */
155 int *dptr; /* Map atom number to donor index */
156 int *nhydro; /* Number of hydrogens for each donor */
157 h_id *hydro; /* The atom numbers of the hydrogens */
158 h_id *nhbonds; /* The number of HBs per H at current */
162 gmx_bool bHBmap, bDAnr;
164 /* The following arrays are nframes long */
165 int nframes, max_frames, maxhydro;
171 /* These structures are initialized from the topology at start up */
174 /* This holds a matrix with all possible hydrogen bonds */
179 /* Changed argument 'bMerge' into 'oneHB' below,
180 * since -contact should cause maxhydro to be 1,
182 * - Erik Marklund May 29, 2006
185 static t_hbdata *mk_hbdata(gmx_bool bHBmap, gmx_bool bDAnr, gmx_bool oneHB)
190 hb->wordlen = 8*sizeof(unsigned int);
199 hb->maxhydro = MAXHYDRO;
204 static void mk_hbmap(t_hbdata *hb)
208 snew(hb->hbmap, hb->d.nrd);
209 for (i = 0; (i < hb->d.nrd); i++)
211 snew(hb->hbmap[i], hb->a.nra);
212 if (hb->hbmap[i] == NULL)
214 gmx_fatal(FARGS, "Could not allocate enough memory for hbmap");
216 for (j = 0; (j > hb->a.nra); j++)
218 hb->hbmap[i][j] = NULL;
223 static void add_frames(t_hbdata *hb, int nframes)
227 if (nframes >= hb->max_frames)
229 hb->max_frames += 4096;
230 srenew(hb->time, hb->max_frames);
231 srenew(hb->nhb, hb->max_frames);
232 srenew(hb->ndist, hb->max_frames);
233 srenew(hb->n_bound, hb->max_frames);
234 srenew(hb->nhx, hb->max_frames);
237 srenew(hb->danr, hb->max_frames);
240 hb->nframes = nframes;
243 #define OFFSET(frame) (frame / 32)
244 #define MASK(frame) (1 << (frame % 32))
246 static void _set_hb(unsigned int hbexist[], unsigned int frame, gmx_bool bValue)
250 hbexist[OFFSET(frame)] |= MASK(frame);
254 hbexist[OFFSET(frame)] &= ~MASK(frame);
258 static gmx_bool is_hb(unsigned int hbexist[], int frame)
260 return ((hbexist[OFFSET(frame)] & MASK(frame)) != 0) ? 1 : 0;
263 static void set_hb(t_hbdata *hb, int id, int ih, int ia, int frame, int ihb)
265 unsigned int *ghptr = NULL;
269 ghptr = hb->hbmap[id][ia]->h[ih];
271 else if (ihb == hbDist)
273 ghptr = hb->hbmap[id][ia]->g[ih];
277 gmx_fatal(FARGS, "Incomprehensible iValue %d in set_hb", ihb);
280 _set_hb(ghptr, frame-hb->hbmap[id][ia]->n0, TRUE);
283 static void add_ff(t_hbdata *hbd, int id, int h, int ia, int frame, int ihb)
286 t_hbond *hb = hbd->hbmap[id][ia];
287 int maxhydro = min(hbd->maxhydro, hbd->d.nhydro[id]);
288 int wlen = hbd->wordlen;
294 hb->maxframes = delta;
295 for (i = 0; (i < maxhydro); i++)
297 snew(hb->h[i], hb->maxframes/wlen);
298 snew(hb->g[i], hb->maxframes/wlen);
303 hb->nframes = frame-hb->n0;
304 /* We need a while loop here because hbonds may be returning
307 while (hb->nframes >= hb->maxframes)
309 n = hb->maxframes + delta;
310 for (i = 0; (i < maxhydro); i++)
312 srenew(hb->h[i], n/wlen);
313 srenew(hb->g[i], n/wlen);
314 for (j = hb->maxframes/wlen; (j < n/wlen); j++)
326 set_hb(hbd, id, h, ia, frame, ihb);
331 static void inc_nhbonds(t_donors *ddd, int d, int h)
334 int dptr = ddd->dptr[d];
336 for (j = 0; (j < ddd->nhydro[dptr]); j++)
338 if (ddd->hydro[dptr][j] == h)
340 ddd->nhbonds[dptr][j]++;
344 if (j == ddd->nhydro[dptr])
346 gmx_fatal(FARGS, "No such hydrogen %d on donor %d\n", h+1, d+1);
350 static int _acceptor_index(t_acceptors *a, int grp, atom_id i,
351 const char *file, int line)
355 if (a->grp[ai] != grp)
359 fprintf(debug, "Acc. group inconsist.. grp[%d] = %d, grp = %d (%s, %d)\n",
360 ai, a->grp[ai], grp, file, line);
369 #define acceptor_index(a, grp, i) _acceptor_index(a, grp, i, __FILE__, __LINE__)
371 static int _donor_index(t_donors *d, int grp, atom_id i, const char *file, int line)
380 if (d->grp[di] != grp)
384 fprintf(debug, "Don. group inconsist.. grp[%d] = %d, grp = %d (%s, %d)\n",
385 di, d->grp[di], grp, file, line);
394 #define donor_index(d, grp, i) _donor_index(d, grp, i, __FILE__, __LINE__)
396 static gmx_bool isInterchangable(t_hbdata *hb, int d, int a, int grpa, int grpd)
398 /* g_hbond doesn't allow overlapping groups */
404 donor_index(&hb->d, grpd, a) != NOTSET
405 && acceptor_index(&hb->a, grpa, d) != NOTSET;
409 static void add_hbond(t_hbdata *hb, int d, int a, int h, int grpd, int grpa,
410 int frame, gmx_bool bMerge, int ihb, gmx_bool bContact)
413 gmx_bool daSwap = FALSE;
415 if ((id = hb->d.dptr[d]) == NOTSET)
417 gmx_fatal(FARGS, "No donor atom %d", d+1);
419 else if (grpd != hb->d.grp[id])
421 gmx_fatal(FARGS, "Inconsistent donor groups, %d iso %d, atom %d",
422 grpd, hb->d.grp[id], d+1);
424 if ((ia = hb->a.aptr[a]) == NOTSET)
426 gmx_fatal(FARGS, "No acceptor atom %d", a+1);
428 else if (grpa != hb->a.grp[ia])
430 gmx_fatal(FARGS, "Inconsistent acceptor groups, %d iso %d, atom %d",
431 grpa, hb->a.grp[ia], a+1);
437 if (isInterchangable(hb, d, a, grpd, grpa) && d > a)
438 /* Then swap identity so that the id of d is lower then that of a.
440 * This should really be redundant by now, as is_hbond() now ought to return
441 * hbNo in the cases where this conditional is TRUE. */
448 /* Now repeat donor/acc check. */
449 if ((id = hb->d.dptr[d]) == NOTSET)
451 gmx_fatal(FARGS, "No donor atom %d", d+1);
453 else if (grpd != hb->d.grp[id])
455 gmx_fatal(FARGS, "Inconsistent donor groups, %d iso %d, atom %d",
456 grpd, hb->d.grp[id], d+1);
458 if ((ia = hb->a.aptr[a]) == NOTSET)
460 gmx_fatal(FARGS, "No acceptor atom %d", a+1);
462 else if (grpa != hb->a.grp[ia])
464 gmx_fatal(FARGS, "Inconsistent acceptor groups, %d iso %d, atom %d",
465 grpa, hb->a.grp[ia], a+1);
472 /* Loop over hydrogens to find which hydrogen is in this particular HB */
473 if ((ihb == hbHB) && !bMerge && !bContact)
475 for (k = 0; (k < hb->d.nhydro[id]); k++)
477 if (hb->d.hydro[id][k] == h)
482 if (k == hb->d.nhydro[id])
484 gmx_fatal(FARGS, "Donor %d does not have hydrogen %d (a = %d)",
498 if (hb->hbmap[id][ia] == NULL)
500 snew(hb->hbmap[id][ia], 1);
501 snew(hb->hbmap[id][ia]->h, hb->maxhydro);
502 snew(hb->hbmap[id][ia]->g, hb->maxhydro);
504 add_ff(hb, id, k, ia, frame, ihb);
508 /* Strange construction with frame >=0 is a relic from old code
509 * for selected hbond analysis. It may be necessary again if that
510 * is made to work again.
514 hh = hb->hbmap[id][ia]->history[k];
520 hb->hbmap[id][ia]->history[k] = hh | 2;
531 hb->hbmap[id][ia]->history[k] = hh | 1;
555 if (bMerge && daSwap)
557 h = hb->d.hydro[id][0];
559 /* Increment number if HBonds per H */
560 if (ihb == hbHB && !bContact)
562 inc_nhbonds(&(hb->d), d, h);
566 static char *mkatomname(t_atoms *atoms, int i)
571 rnr = atoms->atom[i].resind;
572 sprintf(buf, "%4s%d%-4s",
573 *atoms->resinfo[rnr].name, atoms->resinfo[rnr].nr, *atoms->atomname[i]);
578 static void gen_datable(atom_id *index, int isize, unsigned char *datable, int natoms)
580 /* Generates table of all atoms and sets the ingroup bit for atoms in index[] */
583 for (i = 0; i < isize; i++)
585 if (index[i] >= natoms)
587 gmx_fatal(FARGS, "Atom has index %d larger than number of atoms %d.", index[i], natoms);
589 datable[index[i]] |= INGROUP;
593 static void clear_datable_grp(unsigned char *datable, int size)
595 /* Clears group information from the table */
597 const char mask = !(char)INGROUP;
600 for (i = 0; i < size; i++)
607 static void add_acc(t_acceptors *a, int ia, int grp)
609 if (a->nra >= a->max_nra)
612 srenew(a->acc, a->max_nra);
613 srenew(a->grp, a->max_nra);
615 a->grp[a->nra] = grp;
616 a->acc[a->nra++] = ia;
619 static void search_acceptors(t_topology *top, int isize,
620 atom_id *index, t_acceptors *a, int grp,
622 gmx_bool bContact, gmx_bool bDoIt, unsigned char *datable)
628 for (i = 0; (i < isize); i++)
632 (((*top->atoms.atomname[n])[0] == 'O') ||
633 (bNitAcc && ((*top->atoms.atomname[n])[0] == 'N')))) &&
636 datable[n] |= ACC; /* set the atom's acceptor flag in datable. */
641 snew(a->aptr, top->atoms.nr);
642 for (i = 0; (i < top->atoms.nr); i++)
646 for (i = 0; (i < a->nra); i++)
648 a->aptr[a->acc[i]] = i;
652 static void add_h2d(int id, int ih, t_donors *ddd)
656 for (i = 0; (i < ddd->nhydro[id]); i++)
658 if (ddd->hydro[id][i] == ih)
660 printf("Hm. This isn't the first time I found this donor (%d,%d)\n",
665 if (i == ddd->nhydro[id])
667 if (ddd->nhydro[id] >= MAXHYDRO)
669 gmx_fatal(FARGS, "Donor %d has more than %d hydrogens!",
670 ddd->don[id], MAXHYDRO);
672 ddd->hydro[id][i] = ih;
677 static void add_dh(t_donors *ddd, int id, int ih, int grp, unsigned char *datable)
681 if (!datable || ISDON(datable[id]))
683 if (ddd->dptr[id] == NOTSET) /* New donor */
695 if (ddd->nrd >= ddd->max_nrd)
698 srenew(ddd->don, ddd->max_nrd);
699 srenew(ddd->nhydro, ddd->max_nrd);
700 srenew(ddd->hydro, ddd->max_nrd);
701 srenew(ddd->nhbonds, ddd->max_nrd);
702 srenew(ddd->grp, ddd->max_nrd);
704 ddd->don[ddd->nrd] = id;
705 ddd->nhydro[ddd->nrd] = 0;
706 ddd->grp[ddd->nrd] = grp;
718 printf("Warning: Atom %d is not in the d/a-table!\n", id);
722 static void search_donors(t_topology *top, int isize, atom_id *index,
723 t_donors *ddd, int grp, gmx_bool bContact, gmx_bool bDoIt,
724 unsigned char *datable)
727 t_functype func_type;
728 t_ilist *interaction;
729 atom_id nr1, nr2, nr3;
734 snew(ddd->dptr, top->atoms.nr);
735 for (i = 0; (i < top->atoms.nr); i++)
737 ddd->dptr[i] = NOTSET;
745 for (i = 0; (i < isize); i++)
747 datable[index[i]] |= DON;
748 add_dh(ddd, index[i], -1, grp, datable);
754 for (func_type = 0; (func_type < F_NRE); func_type++)
756 interaction = &(top->idef.il[func_type]);
757 if (func_type == F_POSRES || func_type == F_FBPOSRES)
759 /* The ilist looks strange for posre. Bug in grompp?
760 * We don't need posre interactions for hbonds anyway.*/
763 for (i = 0; i < interaction->nr;
764 i += interaction_function[top->idef.functype[interaction->iatoms[i]]].nratoms+1)
767 if (func_type != top->idef.functype[interaction->iatoms[i]])
769 fprintf(stderr, "Error in func_type %s",
770 interaction_function[func_type].longname);
774 /* check out this functype */
775 if (func_type == F_SETTLE)
777 nr1 = interaction->iatoms[i+1];
778 nr2 = interaction->iatoms[i+2];
779 nr3 = interaction->iatoms[i+3];
781 if (ISINGRP(datable[nr1]))
783 if (ISINGRP(datable[nr2]))
786 add_dh(ddd, nr1, nr1+1, grp, datable);
788 if (ISINGRP(datable[nr3]))
791 add_dh(ddd, nr1, nr1+2, grp, datable);
795 else if (IS_CHEMBOND(func_type))
797 for (j = 0; j < 2; j++)
799 nr1 = interaction->iatoms[i+1+j];
800 nr2 = interaction->iatoms[i+2-j];
801 if ((*top->atoms.atomname[nr1][0] == 'H') &&
802 ((*top->atoms.atomname[nr2][0] == 'O') ||
803 (*top->atoms.atomname[nr2][0] == 'N')) &&
804 ISINGRP(datable[nr1]) && ISINGRP(datable[nr2]))
807 add_dh(ddd, nr2, nr1, grp, datable);
814 for (func_type = 0; func_type < F_NRE; func_type++)
816 interaction = &top->idef.il[func_type];
817 for (i = 0; i < interaction->nr;
818 i += interaction_function[top->idef.functype[interaction->iatoms[i]]].nratoms+1)
821 if (func_type != top->idef.functype[interaction->iatoms[i]])
823 gmx_incons("function type in search_donors");
826 if (interaction_function[func_type].flags & IF_VSITE)
828 nr1 = interaction->iatoms[i+1];
829 if (*top->atoms.atomname[nr1][0] == 'H')
833 while (!stop && ( *top->atoms.atomname[nr2][0] == 'H'))
844 if (!stop && ( ( *top->atoms.atomname[nr2][0] == 'O') ||
845 ( *top->atoms.atomname[nr2][0] == 'N') ) &&
846 ISINGRP(datable[nr1]) && ISINGRP(datable[nr2]))
849 add_dh(ddd, nr2, nr1, grp, datable);
859 static t_gridcell ***init_grid(gmx_bool bBox, rvec box[], real rcut, ivec ngrid)
866 for (i = 0; i < DIM; i++)
868 ngrid[i] = (box[i][i]/(1.2*rcut));
872 if (!bBox || (ngrid[XX] < 3) || (ngrid[YY] < 3) || (ngrid[ZZ] < 3) )
874 for (i = 0; i < DIM; i++)
881 printf("\nWill do grid-seach on %dx%dx%d grid, rcut=%g\n",
882 ngrid[XX], ngrid[YY], ngrid[ZZ], rcut);
884 snew(grid, ngrid[ZZ]);
885 for (z = 0; z < ngrid[ZZ]; z++)
887 snew((grid)[z], ngrid[YY]);
888 for (y = 0; y < ngrid[YY]; y++)
890 snew((grid)[z][y], ngrid[XX]);
896 static void reset_nhbonds(t_donors *ddd)
900 for (i = 0; (i < ddd->nrd); i++)
902 for (j = 0; (j < MAXHH); j++)
904 ddd->nhbonds[i][j] = 0;
909 void pbc_correct_gem(rvec dx, matrix box, rvec hbox);
910 void pbc_in_gridbox(rvec dx, matrix box);
912 static void build_grid(t_hbdata *hb, rvec x[], rvec xshell,
913 gmx_bool bBox, matrix box, rvec hbox,
914 real rcut, real rshell,
915 ivec ngrid, t_gridcell ***grid)
917 int i, m, gr, xi, yi, zi, nr;
920 rvec invdelta, dshell, xtemp = {0, 0, 0};
922 gmx_bool bDoRshell, bInShell, bAcc;
927 bDoRshell = (rshell > 0);
928 rshell2 = sqr(rshell);
931 #define DBB(x) if (debug && bDebug) fprintf(debug, "build_grid, line %d, %s = %d\n", __LINE__,#x, x)
933 for (m = 0; m < DIM; m++)
935 hbox[m] = box[m][m]*0.5;
938 invdelta[m] = ngrid[m]/box[m][m];
939 if (1/invdelta[m] < rcut)
941 gmx_fatal(FARGS, "Your computational box has shrunk too much.\n"
942 "%s can not handle this situation, sorry.\n",
955 /* resetting atom counts */
956 for (gr = 0; (gr < grNR); gr++)
958 for (zi = 0; zi < ngrid[ZZ]; zi++)
960 for (yi = 0; yi < ngrid[YY]; yi++)
962 for (xi = 0; xi < ngrid[XX]; xi++)
964 grid[zi][yi][xi].d[gr].nr = 0;
965 grid[zi][yi][xi].a[gr].nr = 0;
971 /* put atoms in grid cells */
972 for (bAcc = FALSE; (bAcc <= TRUE); bAcc++)
985 for (i = 0; (i < nr); i++)
987 /* check if we are inside the shell */
988 /* if bDoRshell=FALSE then bInShell=TRUE always */
993 rvec_sub(x[ad[i]], xshell, dshell);
996 gmx_bool bDone = FALSE;
1000 for (m = DIM-1; m >= 0 && bInShell; m--)
1002 if (dshell[m] < -hbox[m])
1005 rvec_inc(dshell, box[m]);
1007 if (dshell[m] >= hbox[m])
1010 dshell[m] -= 2*hbox[m];
1014 for (m = DIM-1; m >= 0 && bInShell; m--)
1016 /* if we're outside the cube, we're outside the sphere also! */
1017 if ( (dshell[m] > rshell) || (-dshell[m] > rshell) )
1023 /* if we're inside the cube, check if we're inside the sphere */
1026 bInShell = norm2(dshell) < rshell2;
1034 pbc_in_gridbox(x[ad[i]], box);
1036 for (m = DIM-1; m >= 0; m--)
1037 { /* determine grid index of atom */
1038 grididx[m] = x[ad[i]][m]*invdelta[m];
1039 grididx[m] = (grididx[m]+ngrid[m]) % ngrid[m];
1046 range_check(gx, 0, ngrid[XX]);
1047 range_check(gy, 0, ngrid[YY]);
1048 range_check(gz, 0, ngrid[ZZ]);
1052 /* add atom to grid cell */
1055 newgrid = &(grid[gz][gy][gx].a[gr]);
1059 newgrid = &(grid[gz][gy][gx].d[gr]);
1061 if (newgrid->nr >= newgrid->maxnr)
1063 newgrid->maxnr += 10;
1064 DBB(newgrid->maxnr);
1065 srenew(newgrid->atoms, newgrid->maxnr);
1068 newgrid->atoms[newgrid->nr] = ad[i];
1076 static void count_da_grid(ivec ngrid, t_gridcell ***grid, t_icell danr)
1080 for (gr = 0; (gr < grNR); gr++)
1083 for (zi = 0; zi < ngrid[ZZ]; zi++)
1085 for (yi = 0; yi < ngrid[YY]; yi++)
1087 for (xi = 0; xi < ngrid[XX]; xi++)
1089 danr[gr] += grid[zi][yi][xi].d[gr].nr;
1097 * Without a box, the grid is 1x1x1, so all loops are 1 long.
1098 * With a rectangular box (bTric==FALSE) all loops are 3 long.
1099 * With a triclinic box all loops are 3 long, except when a cell is
1100 * located next to one of the box edges which is not parallel to the
1101 * x/y-plane, in that case all cells in a line or layer are searched.
1102 * This could be implemented slightly more efficient, but the code
1103 * would get much more complicated.
1105 static gmx_inline gmx_bool grid_loop_begin(int n, int x, gmx_bool bTric, gmx_bool bEdge)
1107 return ((n == 1) ? x : bTric && bEdge ? 0 : (x-1));
1109 static gmx_inline gmx_bool grid_loop_end(int n, int x, gmx_bool bTric, gmx_bool bEdge)
1111 return ((n == 1) ? x : bTric && bEdge ? (n-1) : (x+1));
1113 static gmx_inline int grid_mod(int j, int n)
1118 static void dump_grid(FILE *fp, ivec ngrid, t_gridcell ***grid)
1120 int gr, x, y, z, sum[grNR];
1122 fprintf(fp, "grid %dx%dx%d\n", ngrid[XX], ngrid[YY], ngrid[ZZ]);
1123 for (gr = 0; gr < grNR; gr++)
1126 fprintf(fp, "GROUP %d (%s)\n", gr, grpnames[gr]);
1127 for (z = 0; z < ngrid[ZZ]; z += 2)
1129 fprintf(fp, "Z=%d,%d\n", z, z+1);
1130 for (y = 0; y < ngrid[YY]; y++)
1132 for (x = 0; x < ngrid[XX]; x++)
1134 fprintf(fp, "%3d", grid[x][y][z].d[gr].nr);
1135 sum[gr] += grid[z][y][x].d[gr].nr;
1136 fprintf(fp, "%3d", grid[x][y][z].a[gr].nr);
1137 sum[gr] += grid[z][y][x].a[gr].nr;
1141 if ( (z+1) < ngrid[ZZ])
1143 for (x = 0; x < ngrid[XX]; x++)
1145 fprintf(fp, "%3d", grid[z+1][y][x].d[gr].nr);
1146 sum[gr] += grid[z+1][y][x].d[gr].nr;
1147 fprintf(fp, "%3d", grid[z+1][y][x].a[gr].nr);
1148 sum[gr] += grid[z+1][y][x].a[gr].nr;
1155 fprintf(fp, "TOTALS:");
1156 for (gr = 0; gr < grNR; gr++)
1158 fprintf(fp, " %d=%d", gr, sum[gr]);
1163 /* New GMX record! 5 * in a row. Congratulations!
1164 * Sorry, only four left.
1166 static void free_grid(ivec ngrid, t_gridcell ****grid)
1169 t_gridcell ***g = *grid;
1171 for (z = 0; z < ngrid[ZZ]; z++)
1173 for (y = 0; y < ngrid[YY]; y++)
1183 void pbc_correct_gem(rvec dx, matrix box, rvec hbox)
1186 gmx_bool bDone = FALSE;
1190 for (m = DIM-1; m >= 0; m--)
1192 if (dx[m] < -hbox[m])
1195 rvec_inc(dx, box[m]);
1197 if (dx[m] >= hbox[m])
1200 rvec_dec(dx, box[m]);
1206 void pbc_in_gridbox(rvec dx, matrix box)
1209 gmx_bool bDone = FALSE;
1213 for (m = DIM-1; m >= 0; m--)
1218 rvec_inc(dx, box[m]);
1220 if (dx[m] >= box[m][m])
1223 rvec_dec(dx, box[m]);
1229 /* Added argument r2cut, changed contact and implemented
1230 * use of second cut-off.
1231 * - Erik Marklund, June 29, 2006
1233 static int is_hbond(t_hbdata *hb, int grpd, int grpa, int d, int a,
1234 real rcut, real r2cut, real ccut,
1235 rvec x[], gmx_bool bBox, matrix box, rvec hbox,
1236 real *d_ha, real *ang, gmx_bool bDA, int *hhh,
1237 gmx_bool bContact, gmx_bool bMerge)
1239 int h, hh, id, ja, ihb;
1240 rvec r_da, r_ha, r_dh, r = {0, 0, 0};
1242 real rc2, r2c2, rda2, rha2, ca;
1243 gmx_bool HAinrange = FALSE; /* If !bDA. Needed for returning hbDist in a correct way. */
1244 gmx_bool daSwap = FALSE;
1251 if (((id = donor_index(&hb->d, grpd, d)) == NOTSET) ||
1252 ((ja = acceptor_index(&hb->a, grpa, a)) == NOTSET))
1260 rvec_sub(x[d], x[a], r_da);
1261 /* Insert projection code here */
1263 if (bMerge && d > a && isInterchangable(hb, d, a, grpd, grpa))
1265 /* Then this hbond/contact will be found again, or it has already been found. */
1270 if (d > a && bMerge && isInterchangable(hb, d, a, grpd, grpa)) /* acceptor is also a donor and vice versa? */
1271 { /* return hbNo; */
1272 daSwap = TRUE; /* If so, then their history should be filed with donor and acceptor swapped. */
1274 pbc_correct_gem(r_da, box, hbox);
1276 rda2 = iprod(r_da, r_da);
1280 if (daSwap && grpa == grpd)
1288 else if (rda2 < r2c2)
1299 if (bDA && (rda2 > rc2))
1304 for (h = 0; (h < hb->d.nhydro[id]); h++)
1306 hh = hb->d.hydro[id][h];
1310 rvec_sub(x[hh], x[a], r_ha);
1313 pbc_correct_gem(r_ha, box, hbox);
1315 rha2 = iprod(r_ha, r_ha);
1318 if (bDA || (!bDA && (rha2 <= rc2)))
1320 rvec_sub(x[d], x[hh], r_dh);
1323 pbc_correct_gem(r_dh, box, hbox);
1330 ca = cos_angle(r_dh, r_da);
1331 /* if angle is smaller, cos is larger */
1335 *d_ha = sqrt(bDA ? rda2 : rha2);
1341 if (bDA || (!bDA && HAinrange))
1351 /* Merging is now done on the fly, so do_merge is most likely obsolete now.
1352 * Will do some more testing before removing the function entirely.
1353 * - Erik Marklund, MAY 10 2010 */
1354 static void do_merge(t_hbdata *hb, int ntmp,
1355 unsigned int htmp[], unsigned int gtmp[],
1356 t_hbond *hb0, t_hbond *hb1)
1358 /* Here we need to make sure we're treating periodicity in
1359 * the right way for the geminate recombination kinetics. */
1361 int m, mm, n00, n01, nn0, nnframes;
1363 /* Decide where to start from when merging */
1366 nn0 = min(n00, n01);
1367 nnframes = max(n00 + hb0->nframes, n01 + hb1->nframes) - nn0;
1368 /* Initiate tmp arrays */
1369 for (m = 0; (m < ntmp); m++)
1374 /* Fill tmp arrays with values due to first HB */
1375 /* Once again '<' had to be replaced with '<='
1376 to catch the last frame in which the hbond
1378 - Erik Marklund, June 1, 2006 */
1379 for (m = 0; (m <= hb0->nframes); m++)
1382 htmp[mm] = is_hb(hb0->h[0], m);
1384 for (m = 0; (m <= hb0->nframes); m++)
1387 gtmp[mm] = is_hb(hb0->g[0], m);
1390 for (m = 0; (m <= hb1->nframes); m++)
1393 htmp[mm] = htmp[mm] || is_hb(hb1->h[0], m);
1394 gtmp[mm] = gtmp[mm] || is_hb(hb1->g[0], m);
1396 /* Reallocate target array */
1397 if (nnframes > hb0->maxframes)
1399 srenew(hb0->h[0], 4+nnframes/hb->wordlen);
1400 srenew(hb0->g[0], 4+nnframes/hb->wordlen);
1403 /* Copy temp array to target array */
1404 for (m = 0; (m <= nnframes); m++)
1406 _set_hb(hb0->h[0], m, htmp[m]);
1407 _set_hb(hb0->g[0], m, gtmp[m]);
1410 /* Set scalar variables */
1412 hb0->maxframes = nnframes;
1415 static void merge_hb(t_hbdata *hb, gmx_bool bTwo, gmx_bool bContact)
1417 int i, inrnew, indnew, j, ii, jj, m, id, ia, grp, ogrp, ntmp;
1418 unsigned int *htmp, *gtmp;
1422 indnew = hb->nrdist;
1424 /* Check whether donors are also acceptors */
1425 printf("Merging hbonds with Acceptor and Donor swapped\n");
1427 ntmp = 2*hb->max_frames;
1430 for (i = 0; (i < hb->d.nrd); i++)
1432 fprintf(stderr, "\r%d/%d", i+1, hb->d.nrd);
1434 ii = hb->a.aptr[id];
1435 for (j = 0; (j < hb->a.nra); j++)
1438 jj = hb->d.dptr[ia];
1439 if ((id != ia) && (ii != NOTSET) && (jj != NOTSET) &&
1440 (!bTwo || (bTwo && (hb->d.grp[i] != hb->a.grp[j]))))
1442 hb0 = hb->hbmap[i][j];
1443 hb1 = hb->hbmap[jj][ii];
1444 if (hb0 && hb1 && ISHB(hb0->history[0]) && ISHB(hb1->history[0]))
1446 do_merge(hb, ntmp, htmp, gtmp, hb0, hb1);
1447 if (ISHB(hb1->history[0]))
1451 else if (ISDIST(hb1->history[0]))
1458 gmx_incons("No contact history");
1462 gmx_incons("Neither hydrogen bond nor distance");
1468 hb1->history[0] = hbNo;
1473 fprintf(stderr, "\n");
1474 printf("- Reduced number of hbonds from %d to %d\n", hb->nrhb, inrnew);
1475 printf("- Reduced number of distances from %d to %d\n", hb->nrdist, indnew);
1477 hb->nrdist = indnew;
1482 static void do_nhb_dist(FILE *fp, t_hbdata *hb, real t)
1484 int i, j, k, n_bound[MAXHH], nbtot;
1488 /* Set array to 0 */
1489 for (k = 0; (k < MAXHH); k++)
1493 /* Loop over possible donors */
1494 for (i = 0; (i < hb->d.nrd); i++)
1496 for (j = 0; (j < hb->d.nhydro[i]); j++)
1498 n_bound[hb->d.nhbonds[i][j]]++;
1501 fprintf(fp, "%12.5e", t);
1503 for (k = 0; (k < MAXHH); k++)
1505 fprintf(fp, " %8d", n_bound[k]);
1506 nbtot += n_bound[k]*k;
1508 fprintf(fp, " %8d\n", nbtot);
1511 static void do_hblife(const char *fn, t_hbdata *hb, gmx_bool bMerge, gmx_bool bContact,
1512 const output_env_t oenv)
1515 const char *leg[] = { "p(t)", "t p(t)" };
1517 int i, j, j0, k, m, nh, ihb, ohb, nhydro, ndump = 0;
1518 int nframes = hb->nframes;
1521 double sum, integral;
1524 snew(h, hb->maxhydro);
1525 snew(histo, nframes+1);
1526 /* Total number of hbonds analyzed here */
1527 for (i = 0; (i < hb->d.nrd); i++)
1529 for (k = 0; (k < hb->a.nra); k++)
1531 hbh = hb->hbmap[i][k];
1549 for (m = 0; (m < hb->maxhydro); m++)
1553 h[nhydro++] = bContact ? hbh->g[m] : hbh->h[m];
1557 for (nh = 0; (nh < nhydro); nh++)
1562 for (j = 0; (j <= hbh->nframes); j++)
1564 ihb = is_hb(h[nh], j);
1565 if (debug && (ndump < 10))
1567 fprintf(debug, "%5d %5d\n", j, ihb);
1587 fprintf(stderr, "\n");
1590 fp = xvgropen(fn, "Uninterrupted contact lifetime", output_env_get_xvgr_tlabel(oenv), "()", oenv);
1594 fp = xvgropen(fn, "Uninterrupted hydrogen bond lifetime", output_env_get_xvgr_tlabel(oenv), "()",
1598 xvgr_legend(fp, asize(leg), leg, oenv);
1600 while ((j0 > 0) && (histo[j0] == 0))
1605 for (i = 0; (i <= j0); i++)
1609 dt = hb->time[1]-hb->time[0];
1612 for (i = 1; (i <= j0); i++)
1614 t = hb->time[i] - hb->time[0] - 0.5*dt;
1615 x1 = t*histo[i]/sum;
1616 fprintf(fp, "%8.3f %10.3e %10.3e\n", t, histo[i]/sum, x1);
1621 printf("%s lifetime = %.2f ps\n", bContact ? "Contact" : "HB", integral);
1622 printf("Note that the lifetime obtained in this manner is close to useless\n");
1623 printf("Use the -ac option instead and check the Forward lifetime\n");
1624 please_cite(stdout, "Spoel2006b");
1629 static void dump_ac(t_hbdata *hb, gmx_bool oneHB, int nDump)
1632 int i, j, k, m, nd, ihb, idist;
1633 int nframes = hb->nframes;
1641 fp = gmx_ffopen("debug-ac.xvg", "w");
1642 for (j = 0; (j < nframes); j++)
1644 fprintf(fp, "%10.3f", hb->time[j]);
1645 for (i = nd = 0; (i < hb->d.nrd) && (nd < nDump); i++)
1647 for (k = 0; (k < hb->a.nra) && (nd < nDump); k++)
1651 hbh = hb->hbmap[i][k];
1656 ihb = is_hb(hbh->h[0], j);
1657 idist = is_hb(hbh->g[0], j);
1663 for (m = 0; (m < hb->maxhydro) && !ihb; m++)
1665 ihb = ihb || ((hbh->h[m]) && is_hb(hbh->h[m], j));
1666 idist = idist || ((hbh->g[m]) && is_hb(hbh->g[m], j));
1668 /* This is not correct! */
1669 /* What isn't correct? -Erik M */
1674 fprintf(fp, " %1d-%1d", ihb, idist);
1684 static real calc_dg(real tau, real temp)
1695 return kbt*log(kbt*tau/PLANCK);
1700 int n0, n1, nparams, ndelta;
1702 real *t, *ct, *nt, *kt, *sigma_ct, *sigma_nt, *sigma_kt;
1705 static real compute_weighted_rates(int n, real t[], real ct[], real nt[],
1706 real kt[], real sigma_ct[], real sigma_nt[],
1707 real sigma_kt[], real *k, real *kp,
1708 real *sigma_k, real *sigma_kp,
1714 real kkk = 0, kkp = 0, kk2 = 0, kp2 = 0, chi2;
1719 for (i = 0; (i < n); i++)
1721 if (t[i] >= fit_start)
1734 tl.sigma_ct = sigma_ct;
1735 tl.sigma_nt = sigma_nt;
1736 tl.sigma_kt = sigma_kt;
1740 chi2 = 0; /*optimize_luzar_parameters(debug, &tl, 1000, 1e-3); */
1742 *kp = tl.kkk[1] = *kp;
1744 for (j = 0; (j < NK); j++)
1746 /* (void) optimize_luzar_parameters(debug, &tl, 1000, 1e-3); */
1749 kk2 += sqr(tl.kkk[0]);
1750 kp2 += sqr(tl.kkk[1]);
1753 *sigma_k = sqrt(kk2/NK - sqr(kkk/NK));
1754 *sigma_kp = sqrt(kp2/NK - sqr(kkp/NK));
1759 void analyse_corr(int n, real t[], real ct[], real nt[], real kt[],
1760 real sigma_ct[], real sigma_nt[], real sigma_kt[],
1761 real fit_start, real temp)
1764 real k = 1, kp = 1, kow = 1;
1765 real Q = 0, chi22, chi2, dg, dgp, tau_hb, dtau, tau_rlx, e_1, dt, sigma_k, sigma_kp, ddg;
1766 double tmp, sn2 = 0, sc2 = 0, sk2 = 0, scn = 0, sck = 0, snk = 0;
1767 gmx_bool bError = (sigma_ct != NULL) && (sigma_nt != NULL) && (sigma_kt != NULL);
1769 for (i0 = 0; (i0 < n-2) && ((t[i0]-t[0]) < fit_start); i0++)
1775 for (i = i0; (i < n); i++)
1784 printf("Hydrogen bond thermodynamics at T = %g K\n", temp);
1785 tmp = (sn2*sc2-sqr(scn));
1786 if ((tmp > 0) && (sn2 > 0))
1788 k = (sn2*sck-scn*snk)/tmp;
1789 kp = (k*scn-snk)/sn2;
1793 for (i = i0; (i < n); i++)
1795 chi2 += sqr(k*ct[i]-kp*nt[i]-kt[i]);
1797 chi22 = compute_weighted_rates(n, t, ct, nt, kt, sigma_ct, sigma_nt,
1799 &sigma_k, &sigma_kp, fit_start);
1800 Q = 0; /* quality_of_fit(chi2, 2);*/
1801 ddg = BOLTZ*temp*sigma_k/k;
1802 printf("Fitting paramaters chi^2 = %10g, Quality of fit = %10g\n",
1804 printf("The Rate and Delta G are followed by an error estimate\n");
1805 printf("----------------------------------------------------------\n"
1806 "Type Rate (1/ps) Sigma Time (ps) DG (kJ/mol) Sigma\n");
1807 printf("Forward %10.3f %6.2f %8.3f %10.3f %6.2f\n",
1808 k, sigma_k, 1/k, calc_dg(1/k, temp), ddg);
1809 ddg = BOLTZ*temp*sigma_kp/kp;
1810 printf("Backward %10.3f %6.2f %8.3f %10.3f %6.2f\n",
1811 kp, sigma_kp, 1/kp, calc_dg(1/kp, temp), ddg);
1816 for (i = i0; (i < n); i++)
1818 chi2 += sqr(k*ct[i]-kp*nt[i]-kt[i]);
1820 printf("Fitting parameters chi^2 = %10g\nQ = %10g\n",
1822 printf("--------------------------------------------------\n"
1823 "Type Rate (1/ps) Time (ps) DG (kJ/mol) Chi^2\n");
1824 printf("Forward %10.3f %8.3f %10.3f %10g\n",
1825 k, 1/k, calc_dg(1/k, temp), chi2);
1826 printf("Backward %10.3f %8.3f %10.3f\n",
1827 kp, 1/kp, calc_dg(1/kp, temp));
1833 printf("One-way %10.3f %s%8.3f %10.3f\n",
1834 kow, bError ? " " : "", 1/kow, calc_dg(1/kow, temp));
1838 printf(" - Numerical problems computing HB thermodynamics:\n"
1839 "sc2 = %g sn2 = %g sk2 = %g sck = %g snk = %g scn = %g\n",
1840 sc2, sn2, sk2, sck, snk, scn);
1842 /* Determine integral of the correlation function */
1843 tau_hb = evaluate_integral(n, t, ct, NULL, (t[n-1]-t[0])/2, &dtau);
1844 printf("Integral %10.3f %s%8.3f %10.3f\n", 1/tau_hb,
1845 bError ? " " : "", tau_hb, calc_dg(tau_hb, temp));
1847 for (i = 0; (i < n-2); i++)
1849 if ((ct[i] > e_1) && (ct[i+1] <= e_1))
1856 /* Determine tau_relax from linear interpolation */
1857 tau_rlx = t[i]-t[0] + (e_1-ct[i])*(t[i+1]-t[i])/(ct[i+1]-ct[i]);
1858 printf("Relaxation %10.3f %8.3f %s%10.3f\n", 1/tau_rlx,
1859 tau_rlx, bError ? " " : "",
1860 calc_dg(tau_rlx, temp));
1865 printf("Correlation functions too short to compute thermodynamics\n");
1869 void compute_derivative(int nn, real x[], real y[], real dydx[])
1873 /* Compute k(t) = dc(t)/dt */
1874 for (j = 1; (j < nn-1); j++)
1876 dydx[j] = (y[j+1]-y[j-1])/(x[j+1]-x[j-1]);
1878 /* Extrapolate endpoints */
1879 dydx[0] = 2*dydx[1] - dydx[2];
1880 dydx[nn-1] = 2*dydx[nn-2] - dydx[nn-3];
1883 static void parallel_print(int *data, int nThreads)
1885 /* This prints the donors on which each tread is currently working. */
1888 fprintf(stderr, "\r");
1889 for (i = 0; i < nThreads; i++)
1891 fprintf(stderr, "%-7i", data[i]);
1895 static void normalizeACF(real *ct, real *gt, int nhb, int len)
1897 real ct_fac, gt_fac = 0;
1900 /* Xu and Berne use the same normalization constant */
1905 gt_fac = 1.0/(real)nhb;
1908 printf("Normalization for c(t) = %g for gh(t) = %g\n", ct_fac, gt_fac);
1909 for (i = 0; i < len; i++)
1919 static void do_hbac(const char *fn, t_hbdata *hb,
1920 int nDump, gmx_bool bMerge, gmx_bool bContact, real fit_start,
1921 real temp, gmx_bool R2, const output_env_t oenv,
1925 int i, j, k, m, n, o, nd, ihb, idist, n2, nn, iter, nSets;
1926 const char *legNN[] = {
1930 static char **legGem;
1932 const char *legLuzar[] = {
1933 "Ac\\sfin sys\\v{}\\z{}(t)",
1935 "Cc\\scontact,hb\\v{}\\z{}(t)",
1936 "-dAc\\sfs\\v{}\\z{}/dt"
1938 gmx_bool bNorm = FALSE, bOMP = FALSE;
1941 real *rhbex = NULL, *ht, *gt, *ght, *dght, *kt;
1942 real *ct, *p_ct, tail, tail2, dtail, ct_fac, ght_fac, *cct;
1943 const real tol = 1e-3;
1944 int nframes = hb->nframes, nf;
1945 unsigned int **h = NULL, **g = NULL;
1946 int nh, nhbonds, nhydro, ngh;
1948 int *ptimes = NULL, *poff = NULL, anhb, n0, mMax = INT_MIN;
1951 double *ctdouble, *timedouble, *fittedct;
1952 double fittolerance = 0.1;
1953 int *dondata = NULL, thisThread;
1956 AC_NONE, AC_NN, AC_GEM, AC_LUZAR
1965 printf("Doing autocorrelation ");
1968 printf("according to the theory of Luzar and Chandler.\n");
1971 /* build hbexist matrix in reals for autocorr */
1972 /* Allocate memory for computing ACF (rhbex) and aggregating the ACF (ct) */
1974 while (n2 < nframes)
1981 if (acType != AC_NN || bOMP)
1983 snew(h, hb->maxhydro);
1984 snew(g, hb->maxhydro);
1987 /* Dump hbonds for debugging */
1988 dump_ac(hb, bMerge || bContact, nDump);
1990 /* Total number of hbonds analyzed here */
1995 if (acType != AC_LUZAR && bOMP)
1997 nThreads = min((nThreads <= 0) ? INT_MAX : nThreads, gmx_omp_get_max_threads());
1999 gmx_omp_set_num_threads(nThreads);
2000 snew(dondata, nThreads);
2001 for (i = 0; i < nThreads; i++)
2005 printf("ACF calculations parallelized with OpenMP using %i threads.\n"
2006 "Expect close to linear scaling over this donor-loop.\n", nThreads);
2008 fprintf(stderr, "Donors: [thread no]\n");
2011 for (i = 0; i < nThreads; i++)
2013 snprintf(tmpstr, 7, "[%i]", i);
2014 fprintf(stderr, "%-7s", tmpstr);
2017 fprintf(stderr, "\n");
2032 for (i = 0; (i < hb->d.nrd); i++)
2034 for (k = 0; (k < hb->a.nra); k++)
2037 hbh = hb->hbmap[i][k];
2041 if (bMerge || bContact)
2043 if (ISHB(hbh->history[0]))
2052 for (m = 0; (m < hb->maxhydro); m++)
2054 if (bContact ? ISDIST(hbh->history[m]) : ISHB(hbh->history[m]))
2056 g[nhydro] = hbh->g[m];
2057 h[nhydro] = hbh->h[m];
2064 for (nh = 0; (nh < nhydro); nh++)
2066 int nrint = bContact ? hb->nrdist : hb->nrhb;
2067 if ((((nhbonds+1) % 10) == 0) || (nhbonds+1 == nrint))
2069 fprintf(stderr, "\rACF %d/%d", nhbonds+1, nrint);
2072 for (j = 0; (j < nframes); j++)
2076 ihb = is_hb(h[nh], j);
2077 idist = is_hb(g[nh], j);
2084 /* For contacts: if a second cut-off is provided, use it,
2085 * otherwise use g(t) = 1-h(t) */
2086 if (!R2 && bContact)
2092 gt[j] = idist*(1-ihb);
2098 /* The autocorrelation function is normalized after summation only */
2099 low_do_autocorr(NULL, oenv, NULL, nframes, 1, -1, &rhbex, hb->time[1]-hb->time[0],
2100 eacNormal, 1, FALSE, bNorm, FALSE, 0, -1, 0);
2102 /* Cross correlation analysis for thermodynamics */
2103 for (j = nframes; (j < n2); j++)
2109 cross_corr(n2, ht, gt, dght);
2111 for (j = 0; (j < nn); j++)
2120 fprintf(stderr, "\n");
2123 normalizeACF(ct, ght, nhb, nn);
2125 /* Determine tail value for statistics */
2128 for (j = nn/2; (j < nn); j++)
2131 tail2 += ct[j]*ct[j];
2133 tail /= (nn - nn/2);
2134 tail2 /= (nn - nn/2);
2135 dtail = sqrt(tail2-tail*tail);
2137 /* Check whether the ACF is long enough */
2140 printf("\nWARNING: Correlation function is probably not long enough\n"
2141 "because the standard deviation in the tail of C(t) > %g\n"
2142 "Tail value (average C(t) over second half of acf): %g +/- %g\n",
2145 for (j = 0; (j < nn); j++)
2148 ct[j] = (cct[j]-tail)/(1-tail);
2150 /* Compute negative derivative k(t) = -dc(t)/dt */
2151 compute_derivative(nn, hb->time, ct, kt);
2152 for (j = 0; (j < nn); j++)
2160 fp = xvgropen(fn, "Contact Autocorrelation", output_env_get_xvgr_tlabel(oenv), "C(t)", oenv);
2164 fp = xvgropen(fn, "Hydrogen Bond Autocorrelation", output_env_get_xvgr_tlabel(oenv), "C(t)", oenv);
2166 xvgr_legend(fp, asize(legLuzar), legLuzar, oenv);
2169 for (j = 0; (j < nn); j++)
2171 fprintf(fp, "%10g %10g %10g %10g %10g\n",
2172 hb->time[j]-hb->time[0], ct[j], cct[j], ght[j], kt[j]);
2176 analyse_corr(nn, hb->time, ct, ght, kt, NULL, NULL, NULL,
2179 do_view(oenv, fn, NULL);
2190 static void init_hbframe(t_hbdata *hb, int nframes, real t)
2194 hb->time[nframes] = t;
2195 hb->nhb[nframes] = 0;
2196 hb->ndist[nframes] = 0;
2197 for (i = 0; (i < max_hx); i++)
2199 hb->nhx[nframes][i] = 0;
2203 static FILE *open_donor_properties_file(const char *fn,
2205 const output_env_t oenv)
2208 const char *leg[] = { "Nbound", "Nfree" };
2215 fp = xvgropen(fn, "Donor properties", output_env_get_xvgr_tlabel(oenv), "Number", oenv);
2216 xvgr_legend(fp, asize(leg), leg, oenv);
2221 static void analyse_donor_properties(FILE *fp, t_hbdata *hb, int nframes, real t)
2223 int i, j, k, nbound, nb, nhtot;
2231 for (i = 0; (i < hb->d.nrd); i++)
2233 for (k = 0; (k < hb->d.nhydro[i]); k++)
2237 for (j = 0; (j < hb->a.nra) && (nb == 0); j++)
2239 if (hb->hbmap[i][j] && hb->hbmap[i][j]->h[k] &&
2240 is_hb(hb->hbmap[i][j]->h[k], nframes))
2248 fprintf(fp, "%10.3e %6d %6d\n", t, nbound, nhtot-nbound);
2251 static void dump_hbmap(t_hbdata *hb,
2252 int nfile, t_filenm fnm[], gmx_bool bTwo,
2253 gmx_bool bContact, int isize[], int *index[], char *grpnames[],
2257 int ddd, hhh, aaa, i, j, k, m, grp;
2258 char ds[32], hs[32], as[32];
2261 fp = opt2FILE("-hbn", nfile, fnm, "w");
2262 if (opt2bSet("-g", nfile, fnm))
2264 fplog = gmx_ffopen(opt2fn("-g", nfile, fnm), "w");
2265 fprintf(fplog, "# %10s %12s %12s\n", "Donor", "Hydrogen", "Acceptor");
2271 for (grp = gr0; grp <= (bTwo ? gr1 : gr0); grp++)
2273 fprintf(fp, "[ %s ]", grpnames[grp]);
2274 for (i = 0; i < isize[grp]; i++)
2276 fprintf(fp, (i%15) ? " " : "\n");
2277 fprintf(fp, " %4d", index[grp][i]+1);
2283 fprintf(fp, "[ donors_hydrogens_%s ]\n", grpnames[grp]);
2284 for (i = 0; (i < hb->d.nrd); i++)
2286 if (hb->d.grp[i] == grp)
2288 for (j = 0; (j < hb->d.nhydro[i]); j++)
2290 fprintf(fp, " %4d %4d", hb->d.don[i]+1,
2291 hb->d.hydro[i][j]+1);
2297 fprintf(fp, "[ acceptors_%s ]", grpnames[grp]);
2298 for (i = 0; (i < hb->a.nra); i++)
2300 if (hb->a.grp[i] == grp)
2302 fprintf(fp, (i%15 && !first) ? " " : "\n");
2303 fprintf(fp, " %4d", hb->a.acc[i]+1);
2312 fprintf(fp, bContact ? "[ contacts_%s-%s ]\n" :
2313 "[ hbonds_%s-%s ]\n", grpnames[0], grpnames[1]);
2317 fprintf(fp, bContact ? "[ contacts_%s ]" : "[ hbonds_%s ]\n", grpnames[0]);
2320 for (i = 0; (i < hb->d.nrd); i++)
2323 for (k = 0; (k < hb->a.nra); k++)
2326 for (m = 0; (m < hb->d.nhydro[i]); m++)
2328 if (hb->hbmap[i][k] && ISHB(hb->hbmap[i][k]->history[m]))
2330 sprintf(ds, "%s", mkatomname(atoms, ddd));
2331 sprintf(as, "%s", mkatomname(atoms, aaa));
2334 fprintf(fp, " %6d %6d\n", ddd+1, aaa+1);
2337 fprintf(fplog, "%12s %12s\n", ds, as);
2342 hhh = hb->d.hydro[i][m];
2343 sprintf(hs, "%s", mkatomname(atoms, hhh));
2344 fprintf(fp, " %6d %6d %6d\n", ddd+1, hhh+1, aaa+1);
2347 fprintf(fplog, "%12s %12s %12s\n", ds, hs, as);
2361 /* sync_hbdata() updates the parallel t_hbdata p_hb using hb as template.
2362 * It mimics add_frames() and init_frame() to some extent. */
2363 static void sync_hbdata(t_hbdata *p_hb, int nframes)
2366 if (nframes >= p_hb->max_frames)
2368 p_hb->max_frames += 4096;
2369 srenew(p_hb->nhb, p_hb->max_frames);
2370 srenew(p_hb->ndist, p_hb->max_frames);
2371 srenew(p_hb->n_bound, p_hb->max_frames);
2372 srenew(p_hb->nhx, p_hb->max_frames);
2375 srenew(p_hb->danr, p_hb->max_frames);
2377 memset(&(p_hb->nhb[nframes]), 0, sizeof(int) * (p_hb->max_frames-nframes));
2378 memset(&(p_hb->ndist[nframes]), 0, sizeof(int) * (p_hb->max_frames-nframes));
2379 p_hb->nhb[nframes] = 0;
2380 p_hb->ndist[nframes] = 0;
2383 p_hb->nframes = nframes;
2386 /* p_hb->nhx[nframes][i] */
2388 memset(&(p_hb->nhx[nframes]), 0, sizeof(int)*max_hx); /* zero the helix count for this frame */
2390 /* hb->per will remain constant througout the frame loop,
2391 * even though the data its members point to will change,
2392 * hence no need for re-syncing. */
2395 int gmx_hbond(int argc, char *argv[])
2397 const char *desc[] = {
2398 "[THISMODULE] computes and analyzes hydrogen bonds. Hydrogen bonds are",
2399 "determined based on cutoffs for the angle Hydrogen - Donor - Acceptor",
2400 "(zero is extended) and the distance Donor - Acceptor",
2401 "(or Hydrogen - Acceptor using [TT]-noda[tt]).",
2402 "OH and NH groups are regarded as donors, O is an acceptor always,",
2403 "N is an acceptor by default, but this can be switched using",
2404 "[TT]-nitacc[tt]. Dummy hydrogen atoms are assumed to be connected",
2405 "to the first preceding non-hydrogen atom.[PAR]",
2407 "You need to specify two groups for analysis, which must be either",
2408 "identical or non-overlapping. All hydrogen bonds between the two",
2409 "groups are analyzed.[PAR]",
2411 "If you set [TT]-shell[tt], you will be asked for an additional index group",
2412 "which should contain exactly one atom. In this case, only hydrogen",
2413 "bonds between atoms within the shell distance from the one atom are",
2416 "With option -ac, rate constants for hydrogen bonding can be derived with the model of Luzar and Chandler",
2417 "(Nature 394, 1996; J. Chem. Phys. 113:23, 2000) or that of Markovitz and Agmon (J. Chem. Phys 129, 2008).",
2418 "If contact kinetics are analyzed by using the -contact option, then",
2419 "n(t) can be defined as either all pairs that are not within contact distance r at time t",
2420 "(corresponding to leaving the -r2 option at the default value 0) or all pairs that",
2421 "are within distance r2 (corresponding to setting a second cut-off value with option -r2).",
2422 "See mentioned literature for more details and definitions."
2425 /* "It is also possible to analyse specific hydrogen bonds with",
2426 "[TT]-sel[tt]. This index file must contain a group of atom triplets",
2427 "Donor Hydrogen Acceptor, in the following way::",
2434 "Note that the triplets need not be on separate lines.",
2435 "Each atom triplet specifies a hydrogen bond to be analyzed,",
2436 "note also that no check is made for the types of atoms.[PAR]",
2441 " * [TT]-num[tt]: number of hydrogen bonds as a function of time.",
2442 " * [TT]-ac[tt]: average over all autocorrelations of the existence",
2443 " functions (either 0 or 1) of all hydrogen bonds.",
2444 " * [TT]-dist[tt]: distance distribution of all hydrogen bonds.",
2445 " * [TT]-ang[tt]: angle distribution of all hydrogen bonds.",
2446 " * [TT]-hx[tt]: the number of n-n+i hydrogen bonds as a function of time",
2447 " where n and n+i stand for residue numbers and i ranges from 0 to 6.",
2448 " This includes the n-n+3, n-n+4 and n-n+5 hydrogen bonds associated",
2449 " with helices in proteins.",
2450 " * [TT]-hbn[tt]: all selected groups, donors, hydrogens and acceptors",
2451 " for selected groups, all hydrogen bonded atoms from all groups and",
2452 " all solvent atoms involved in insertion.",
2453 " * [TT]-hbm[tt]: existence matrix for all hydrogen bonds over all",
2454 " frames, this also contains information on solvent insertion",
2455 " into hydrogen bonds. Ordering is identical to that in [TT]-hbn[tt]",
2457 " * [TT]-dan[tt]: write out the number of donors and acceptors analyzed for",
2458 " each timeframe. This is especially useful when using [TT]-shell[tt].",
2459 " * [TT]-nhbdist[tt]: compute the number of HBonds per hydrogen in order to",
2460 " compare results to Raman Spectroscopy.",
2462 "Note: options [TT]-ac[tt], [TT]-life[tt], [TT]-hbn[tt] and [TT]-hbm[tt]",
2463 "require an amount of memory proportional to the total numbers of donors",
2464 "times the total number of acceptors in the selected group(s)."
2467 static real acut = 30, abin = 1, rcut = 0.35, r2cut = 0, rbin = 0.005, rshell = -1;
2468 static real maxnhb = 0, fit_start = 1, fit_end = 60, temp = 298.15, D = -1;
2469 static gmx_bool bNitAcc = TRUE, bDA = TRUE, bMerge = TRUE;
2470 static int nDump = 0, nFitPoints = 100;
2471 static int nThreads = 0, nBalExp = 4;
2473 static gmx_bool bContact = FALSE;
2474 static real logAfterTime = 10, gemBallistic = 0.2; /* ps */
2475 static const char *NNtype[] = {NULL, "none", "binary", "oneOverR3", "dipole", NULL};
2479 { "-a", FALSE, etREAL, {&acut},
2480 "Cutoff angle (degrees, Hydrogen - Donor - Acceptor)" },
2481 { "-r", FALSE, etREAL, {&rcut},
2482 "Cutoff radius (nm, X - Acceptor, see next option)" },
2483 { "-da", FALSE, etBOOL, {&bDA},
2484 "Use distance Donor-Acceptor (if TRUE) or Hydrogen-Acceptor (FALSE)" },
2485 { "-r2", FALSE, etREAL, {&r2cut},
2486 "Second cutoff radius. Mainly useful with [TT]-contact[tt] and [TT]-ac[tt]"},
2487 { "-abin", FALSE, etREAL, {&abin},
2488 "Binwidth angle distribution (degrees)" },
2489 { "-rbin", FALSE, etREAL, {&rbin},
2490 "Binwidth distance distribution (nm)" },
2491 { "-nitacc", FALSE, etBOOL, {&bNitAcc},
2492 "Regard nitrogen atoms as acceptors" },
2493 { "-contact", FALSE, etBOOL, {&bContact},
2494 "Do not look for hydrogen bonds, but merely for contacts within the cut-off distance" },
2495 { "-shell", FALSE, etREAL, {&rshell},
2496 "when > 0, only calculate hydrogen bonds within # nm shell around "
2498 { "-fitstart", FALSE, etREAL, {&fit_start},
2499 "Time (ps) from which to start fitting the correlation functions in order to obtain the forward and backward rate constants for HB breaking and formation. With [TT]-gemfit[tt] we suggest [TT]-fitstart 0[tt]" },
2500 { "-fitend", FALSE, etREAL, {&fit_end},
2501 "Time (ps) to which to stop fitting the correlation functions in order to obtain the forward and backward rate constants for HB breaking and formation (only with [TT]-gemfit[tt])" },
2502 { "-temp", FALSE, etREAL, {&temp},
2503 "Temperature (K) for computing the Gibbs energy corresponding to HB breaking and reforming" },
2504 { "-dump", FALSE, etINT, {&nDump},
2505 "Dump the first N hydrogen bond ACFs in a single [REF].xvg[ref] file for debugging" },
2506 { "-max_hb", FALSE, etREAL, {&maxnhb},
2507 "Theoretical maximum number of hydrogen bonds used for normalizing HB autocorrelation function. Can be useful in case the program estimates it wrongly" },
2508 { "-merge", FALSE, etBOOL, {&bMerge},
2509 "H-bonds between the same donor and acceptor, but with different hydrogen are treated as a single H-bond. Mainly important for the ACF." },
2511 { "-nthreads", FALSE, etINT, {&nThreads},
2512 "Number of threads used for the parallel loop over autocorrelations. nThreads <= 0 means maximum number of threads. Requires linking with OpenMP. The number of threads is limited by the number of cores (before OpenMP v.3 ) or environment variable OMP_THREAD_LIMIT (OpenMP v.3)"},
2515 const char *bugs[] = {
2516 "The option [TT]-sel[tt] that used to work on selected hbonds is out of order, and therefore not available for the time being."
2519 { efTRX, "-f", NULL, ffREAD },
2520 { efTPR, NULL, NULL, ffREAD },
2521 { efNDX, NULL, NULL, ffOPTRD },
2522 /* { efNDX, "-sel", "select", ffOPTRD },*/
2523 { efXVG, "-num", "hbnum", ffWRITE },
2524 { efLOG, "-g", "hbond", ffOPTWR },
2525 { efXVG, "-ac", "hbac", ffOPTWR },
2526 { efXVG, "-dist", "hbdist", ffOPTWR },
2527 { efXVG, "-ang", "hbang", ffOPTWR },
2528 { efXVG, "-hx", "hbhelix", ffOPTWR },
2529 { efNDX, "-hbn", "hbond", ffOPTWR },
2530 { efXPM, "-hbm", "hbmap", ffOPTWR },
2531 { efXVG, "-don", "donor", ffOPTWR },
2532 { efXVG, "-dan", "danum", ffOPTWR },
2533 { efXVG, "-life", "hblife", ffOPTWR },
2534 { efXVG, "-nhbdist", "nhbdist", ffOPTWR }
2537 #define NFILE asize(fnm)
2539 char hbmap [HB_NR] = { ' ', 'o', '-', '*' };
2540 const char *hbdesc[HB_NR] = { "None", "Present", "Inserted", "Present & Inserted" };
2541 t_rgb hbrgb [HB_NR] = { {1, 1, 1}, {1, 0, 0}, {0, 0, 1}, {1, 0, 1} };
2543 t_trxstatus *status;
2548 int npargs, natoms, nframes = 0, shatom;
2554 real t, ccut, dist = 0.0, ang = 0.0;
2555 double max_nhb, aver_nhb, aver_dist;
2556 int h = 0, i = 0, j, k = 0, l, start, end, id, ja, ogrp, nsel;
2558 int xj, yj, zj, aj, xjj, yjj, zjj;
2559 int xk, yk, zk, ak, xkk, ykk, zkk;
2560 gmx_bool bSelected, bHBmap, bStop, bTwo, was, bBox, bTric;
2561 int *adist, *rdist, *aptr, *rprt;
2562 int grp, nabin, nrbin, bin, resdist, ihb;
2564 t_hbdata *hb, *hbptr;
2565 FILE *fp, *fpins = NULL, *fpnhb = NULL, *donor_properties = NULL;
2567 t_ncell *icell, *jcell, *kcell;
2569 unsigned char *datable;
2572 int ii, jj, hh, actual_nThreads;
2575 gmx_bool bEdge_yjj, bEdge_xjj, bOMP;
2577 t_hbdata **p_hb = NULL; /* one per thread, then merge after the frame loop */
2578 int **p_adist = NULL, **p_rdist = NULL; /* a histogram for each thread. */
2587 ppa = add_acf_pargs(&npargs, pa);
2589 if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT, NFILE, fnm, npargs,
2590 ppa, asize(desc), desc, asize(bugs), bugs, &oenv))
2597 ccut = cos(acut*DEG2RAD);
2603 gmx_fatal(FARGS, "Can not analyze selected contacts.");
2607 gmx_fatal(FARGS, "Can not analyze contact between H and A: turn off -noda");
2611 /* Initiate main data structure! */
2612 bHBmap = (opt2bSet("-ac", NFILE, fnm) ||
2613 opt2bSet("-life", NFILE, fnm) ||
2614 opt2bSet("-hbn", NFILE, fnm) ||
2615 opt2bSet("-hbm", NFILE, fnm));
2617 if (opt2bSet("-nhbdist", NFILE, fnm))
2619 const char *leg[MAXHH+1] = { "0 HBs", "1 HB", "2 HBs", "3 HBs", "Total" };
2620 fpnhb = xvgropen(opt2fn("-nhbdist", NFILE, fnm),
2621 "Number of donor-H with N HBs", output_env_get_xvgr_tlabel(oenv), "N", oenv);
2622 xvgr_legend(fpnhb, asize(leg), leg, oenv);
2625 hb = mk_hbdata(bHBmap, opt2bSet("-dan", NFILE, fnm), bMerge || bContact);
2628 read_tpx_top(ftp2fn(efTPR, NFILE, fnm), &ir, box, &natoms, NULL, NULL, NULL, &top);
2630 snew(grpnames, grNR);
2633 /* Make Donor-Acceptor table */
2634 snew(datable, top.atoms.nr);
2635 gen_datable(index[0], isize[0], datable, top.atoms.nr);
2639 /* analyze selected hydrogen bonds */
2640 printf("Select group with selected atoms:\n");
2641 get_index(&(top.atoms), opt2fn("-sel", NFILE, fnm),
2642 1, &nsel, index, grpnames);
2645 gmx_fatal(FARGS, "Number of atoms in group '%s' not a multiple of 3\n"
2646 "and therefore cannot contain triplets of "
2647 "Donor-Hydrogen-Acceptor", grpnames[0]);
2651 for (i = 0; (i < nsel); i += 3)
2653 int dd = index[0][i];
2654 int aa = index[0][i+2];
2655 /* int */ hh = index[0][i+1];
2656 add_dh (&hb->d, dd, hh, i, datable);
2657 add_acc(&hb->a, aa, i);
2658 /* Should this be here ? */
2659 snew(hb->d.dptr, top.atoms.nr);
2660 snew(hb->a.aptr, top.atoms.nr);
2661 add_hbond(hb, dd, aa, hh, gr0, gr0, 0, bMerge, 0, bContact);
2663 printf("Analyzing %d selected hydrogen bonds from '%s'\n",
2664 isize[0], grpnames[0]);
2668 /* analyze all hydrogen bonds: get group(s) */
2669 printf("Specify 2 groups to analyze:\n");
2670 get_index(&(top.atoms), ftp2fn_null(efNDX, NFILE, fnm),
2671 2, isize, index, grpnames);
2673 /* check if we have two identical or two non-overlapping groups */
2674 bTwo = isize[0] != isize[1];
2675 for (i = 0; (i < isize[0]) && !bTwo; i++)
2677 bTwo = index[0][i] != index[1][i];
2681 printf("Checking for overlap in atoms between %s and %s\n",
2682 grpnames[0], grpnames[1]);
2683 for (i = 0; i < isize[1]; i++)
2685 if (ISINGRP(datable[index[1][i]]))
2687 gmx_fatal(FARGS, "Partial overlap between groups '%s' and '%s'",
2688 grpnames[0], grpnames[1]);
2692 printf("Checking for overlap in atoms between %s and %s\n",
2693 grpnames[0],grpnames[1]);
2694 for (i=0; i<isize[0]; i++)
2695 for (j=0; j<isize[1]; j++)
2696 if (index[0][i] == index[1][j])
2697 gmx_fatal(FARGS,"Partial overlap between groups '%s' and '%s'",
2698 grpnames[0],grpnames[1]);
2703 printf("Calculating %s "
2704 "between %s (%d atoms) and %s (%d atoms)\n",
2705 bContact ? "contacts" : "hydrogen bonds",
2706 grpnames[0], isize[0], grpnames[1], isize[1]);
2710 fprintf(stderr, "Calculating %s in %s (%d atoms)\n",
2711 bContact ? "contacts" : "hydrogen bonds", grpnames[0], isize[0]);
2716 /* search donors and acceptors in groups */
2717 snew(datable, top.atoms.nr);
2718 for (i = 0; (i < grNR); i++)
2720 if ( ((i == gr0) && !bSelected ) ||
2721 ((i == gr1) && bTwo ))
2723 gen_datable(index[i], isize[i], datable, top.atoms.nr);
2726 search_acceptors(&top, isize[i], index[i], &hb->a, i,
2727 bNitAcc, TRUE, (bTwo && (i == gr0)) || !bTwo, datable);
2728 search_donors (&top, isize[i], index[i], &hb->d, i,
2729 TRUE, (bTwo && (i == gr1)) || !bTwo, datable);
2733 search_acceptors(&top, isize[i], index[i], &hb->a, i, bNitAcc, FALSE, TRUE, datable);
2734 search_donors (&top, isize[i], index[i], &hb->d, i, FALSE, TRUE, datable);
2738 clear_datable_grp(datable, top.atoms.nr);
2743 printf("Found %d donors and %d acceptors\n", hb->d.nrd, hb->a.nra);
2745 snew(donors[gr0D], dons[gr0D].nrd);*/
2747 donor_properties = open_donor_properties_file(opt2fn_null("-don", NFILE, fnm), hb, oenv);
2751 printf("Making hbmap structure...");
2752 /* Generate hbond data structure */
2759 if (hb->d.nrd + hb->a.nra == 0)
2761 printf("No Donors or Acceptors found\n");
2768 printf("No Donors found\n");
2773 printf("No Acceptors found\n");
2779 gmx_fatal(FARGS, "Nothing to be done");
2788 /* get index group with atom for shell */
2791 printf("Select atom for shell (1 atom):\n");
2792 get_index(&(top.atoms), ftp2fn_null(efNDX, NFILE, fnm),
2793 1, &shisz, &shidx, &shgrpnm);
2796 printf("group contains %d atoms, should be 1 (one)\n", shisz);
2801 printf("Will calculate hydrogen bonds within a shell "
2802 "of %g nm around atom %i\n", rshell, shatom+1);
2805 /* Analyze trajectory */
2806 natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box);
2807 if (natoms > top.atoms.nr)
2809 gmx_fatal(FARGS, "Topology (%d atoms) does not match trajectory (%d atoms)",
2810 top.atoms.nr, natoms);
2813 bBox = ir.ePBC != epbcNONE;
2814 grid = init_grid(bBox, box, (rcut > r2cut) ? rcut : r2cut, ngrid);
2817 snew(adist, nabin+1);
2818 snew(rdist, nrbin+1);
2823 #define __ADIST adist
2824 #define __RDIST rdist
2826 #else /* GMX_OPENMP ================================================== \
2827 * Set up the OpenMP stuff, |
2828 * like the number of threads and such |
2829 * Also start the parallel loop. |
2831 #define __ADIST p_adist[threadNr]
2832 #define __RDIST p_rdist[threadNr]
2833 #define __HBDATA p_hb[threadNr]
2837 bParallel = !bSelected;
2841 actual_nThreads = min((nThreads <= 0) ? INT_MAX : nThreads, gmx_omp_get_max_threads());
2843 gmx_omp_set_num_threads(actual_nThreads);
2844 printf("Frame loop parallelized with OpenMP using %i threads.\n", actual_nThreads);
2849 actual_nThreads = 1;
2852 snew(p_hb, actual_nThreads);
2853 snew(p_adist, actual_nThreads);
2854 snew(p_rdist, actual_nThreads);
2855 for (i = 0; i < actual_nThreads; i++)
2858 snew(p_adist[i], nabin+1);
2859 snew(p_rdist[i], nrbin+1);
2861 p_hb[i]->max_frames = 0;
2862 p_hb[i]->nhb = NULL;
2863 p_hb[i]->ndist = NULL;
2864 p_hb[i]->n_bound = NULL;
2865 p_hb[i]->time = NULL;
2866 p_hb[i]->nhx = NULL;
2868 p_hb[i]->bHBmap = hb->bHBmap;
2869 p_hb[i]->bDAnr = hb->bDAnr;
2870 p_hb[i]->wordlen = hb->wordlen;
2871 p_hb[i]->nframes = hb->nframes;
2872 p_hb[i]->maxhydro = hb->maxhydro;
2873 p_hb[i]->danr = hb->danr;
2876 p_hb[i]->hbmap = hb->hbmap;
2877 p_hb[i]->time = hb->time; /* This may need re-syncing at every frame. */
2880 p_hb[i]->nrdist = 0;
2884 /* Make a thread pool here,
2885 * instead of forking anew at every frame. */
2887 #pragma omp parallel \
2889 private(j, h, ii, jj, hh, \
2890 xi, yi, zi, xj, yj, zj, threadNr, \
2891 dist, ang, icell, jcell, \
2892 grp, ogrp, ai, aj, xjj, yjj, zjj, \
2893 xk, yk, zk, ihb, id, resdist, \
2894 xkk, ykk, zkk, kcell, ak, k, bTric, \
2895 bEdge_xjj, bEdge_yjj) \
2897 { /* Start of parallel region */
2898 threadNr = gmx_omp_get_thread_num();
2903 bTric = bBox && TRICLINIC(box);
2907 sync_hbdata(p_hb[threadNr], nframes);
2911 build_grid(hb, x, x[shatom], bBox, box, hbox, (rcut > r2cut) ? rcut : r2cut,
2912 rshell, ngrid, grid);
2913 reset_nhbonds(&(hb->d));
2915 if (debug && bDebug)
2917 dump_grid(debug, ngrid, grid);
2920 add_frames(hb, nframes);
2921 init_hbframe(hb, nframes, output_env_conv_time(oenv, t));
2925 count_da_grid(ngrid, grid, hb->danr[nframes]);
2931 p_hb[threadNr]->time = hb->time; /* This pointer may have changed. */
2939 /* Do not parallelize this just yet. */
2941 for (ii = 0; (ii < nsel); ii++)
2943 int dd = index[0][i];
2944 int aa = index[0][i+2];
2945 /* int */ hh = index[0][i+1];
2946 ihb = is_hbond(hb, ii, ii, dd, aa, rcut, r2cut, ccut, x, bBox, box,
2947 hbox, &dist, &ang, bDA, &h, bContact, bMerge);
2951 /* add to index if not already there */
2953 add_hbond(hb, dd, aa, hh, ii, ii, nframes, bMerge, ihb, bContact);
2957 } /* if (bSelected) */
2960 /* The outer grid loop will have to do for now. */
2961 #pragma omp for schedule(dynamic)
2962 for (xi = 0; xi < ngrid[XX]; xi++)
2964 for (yi = 0; (yi < ngrid[YY]); yi++)
2966 for (zi = 0; (zi < ngrid[ZZ]); zi++)
2969 /* loop over donor groups gr0 (always) and gr1 (if necessary) */
2970 for (grp = gr0; (grp <= (bTwo ? gr1 : gr0)); grp++)
2972 icell = &(grid[zi][yi][xi].d[grp]);
2983 /* loop over all hydrogen atoms from group (grp)
2984 * in this gridcell (icell)
2986 for (ai = 0; (ai < icell->nr); ai++)
2988 i = icell->atoms[ai];
2990 /* loop over all adjacent gridcells (xj,yj,zj) */
2991 for (zjj = grid_loop_begin(ngrid[ZZ], zi, bTric, FALSE);
2992 zjj <= grid_loop_end(ngrid[ZZ], zi, bTric, FALSE);
2995 zj = grid_mod(zjj, ngrid[ZZ]);
2996 bEdge_yjj = (zj == 0) || (zj == ngrid[ZZ] - 1);
2997 for (yjj = grid_loop_begin(ngrid[YY], yi, bTric, bEdge_yjj);
2998 yjj <= grid_loop_end(ngrid[YY], yi, bTric, bEdge_yjj);
3001 yj = grid_mod(yjj, ngrid[YY]);
3003 (yj == 0) || (yj == ngrid[YY] - 1) ||
3004 (zj == 0) || (zj == ngrid[ZZ] - 1);
3005 for (xjj = grid_loop_begin(ngrid[XX], xi, bTric, bEdge_xjj);
3006 xjj <= grid_loop_end(ngrid[XX], xi, bTric, bEdge_xjj);
3009 xj = grid_mod(xjj, ngrid[XX]);
3010 jcell = &(grid[zj][yj][xj].a[ogrp]);
3011 /* loop over acceptor atoms from other group (ogrp)
3012 * in this adjacent gridcell (jcell)
3014 for (aj = 0; (aj < jcell->nr); aj++)
3016 j = jcell->atoms[aj];
3018 /* check if this once was a h-bond */
3019 ihb = is_hbond(__HBDATA, grp, ogrp, i, j, rcut, r2cut, ccut, x, bBox, box,
3020 hbox, &dist, &ang, bDA, &h, bContact, bMerge);
3024 /* add to index if not already there */
3026 add_hbond(__HBDATA, i, j, h, grp, ogrp, nframes, bMerge, ihb, bContact);
3028 /* make angle and distance distributions */
3029 if (ihb == hbHB && !bContact)
3033 gmx_fatal(FARGS, "distance is higher than what is allowed for an hbond: %f", dist);
3036 __ADIST[(int)( ang/abin)]++;
3037 __RDIST[(int)(dist/rbin)]++;
3041 if ((id = donor_index(&hb->d, grp, i)) == NOTSET)
3043 gmx_fatal(FARGS, "Invalid donor %d", i);
3045 if ((ia = acceptor_index(&hb->a, ogrp, j)) == NOTSET)
3047 gmx_fatal(FARGS, "Invalid acceptor %d", j);
3049 resdist = abs(top.atoms.atom[i].resind-
3050 top.atoms.atom[j].resind);
3051 if (resdist >= max_hx)
3055 __HBDATA->nhx[nframes][resdist]++;
3066 } /* for xi,yi,zi */
3069 } /* if (bSelected) {...} else */
3072 /* Better wait for all threads to finnish using x[] before updating it. */
3075 #pragma omp critical
3077 /* Sum up histograms and counts from p_hb[] into hb */
3080 hb->nhb[k] += p_hb[threadNr]->nhb[k];
3081 hb->ndist[k] += p_hb[threadNr]->ndist[k];
3082 for (j = 0; j < max_hx; j++)
3084 hb->nhx[k][j] += p_hb[threadNr]->nhx[k][j];
3089 /* Here are a handful of single constructs
3090 * to share the workload a bit. The most
3091 * important one is of course the last one,
3092 * where there's a potential bottleneck in form
3097 analyse_donor_properties(donor_properties, hb, k, t);
3104 do_nhb_dist(fpnhb, hb, t);
3110 trrStatus = (read_next_x(oenv, status, &t, x, box));
3120 #pragma omp critical
3122 hb->nrhb += p_hb[threadNr]->nrhb;
3123 hb->nrdist += p_hb[threadNr]->nrdist;
3125 /* Free parallel datastructures */
3126 sfree(p_hb[threadNr]->nhb);
3127 sfree(p_hb[threadNr]->ndist);
3128 sfree(p_hb[threadNr]->nhx);
3131 for (i = 0; i < nabin; i++)
3133 for (j = 0; j < actual_nThreads; j++)
3136 adist[i] += p_adist[j][i];
3140 for (i = 0; i <= nrbin; i++)
3142 for (j = 0; j < actual_nThreads; j++)
3144 rdist[i] += p_rdist[j][i];
3148 sfree(p_adist[threadNr]);
3149 sfree(p_rdist[threadNr]);
3151 } /* End of parallel region */
3158 if (nframes < 2 && (opt2bSet("-ac", NFILE, fnm) || opt2bSet("-life", NFILE, fnm)))
3160 gmx_fatal(FARGS, "Cannot calculate autocorrelation of life times with less than two frames");
3163 free_grid(ngrid, &grid);
3167 if (donor_properties)
3169 xvgrclose(donor_properties);
3177 /* Compute maximum possible number of different hbonds */
3184 max_nhb = 0.5*(hb->d.nrd*hb->a.nra);
3191 printf("No %s found!!\n", bContact ? "contacts" : "hydrogen bonds");
3195 printf("Found %d different %s in trajectory\n"
3196 "Found %d different atom-pairs within %s distance\n",
3197 hb->nrhb, bContact ? "contacts" : "hydrogen bonds",
3198 hb->nrdist, (r2cut > 0) ? "second cut-off" : "hydrogen bonding");
3202 merge_hb(hb, bTwo, bContact);
3205 if (opt2bSet("-hbn", NFILE, fnm))
3207 dump_hbmap(hb, NFILE, fnm, bTwo, bContact, isize, index, grpnames, &top.atoms);
3210 /* Moved the call to merge_hb() to a line BEFORE dump_hbmap
3211 * to make the -hbn and -hmb output match eachother.
3212 * - Erik Marklund, May 30, 2006 */
3215 /* Print out number of hbonds and distances */
3218 fp = xvgropen(opt2fn("-num", NFILE, fnm), bContact ? "Contacts" :
3219 "Hydrogen Bonds", output_env_get_xvgr_tlabel(oenv), "Number", oenv);
3221 snew(leg[0], STRLEN);
3222 snew(leg[1], STRLEN);
3223 sprintf(leg[0], "%s", bContact ? "Contacts" : "Hydrogen bonds");
3224 sprintf(leg[1], "Pairs within %g nm", (r2cut > 0) ? r2cut : rcut);
3225 xvgr_legend(fp, 2, (const char**)leg, oenv);
3229 for (i = 0; (i < nframes); i++)
3231 fprintf(fp, "%10g %10d %10d\n", hb->time[i], hb->nhb[i], hb->ndist[i]);
3232 aver_nhb += hb->nhb[i];
3233 aver_dist += hb->ndist[i];
3236 aver_nhb /= nframes;
3237 aver_dist /= nframes;
3238 /* Print HB distance distribution */
3239 if (opt2bSet("-dist", NFILE, fnm))
3244 for (i = 0; i < nrbin; i++)
3249 fp = xvgropen(opt2fn("-dist", NFILE, fnm),
3250 "Hydrogen Bond Distribution",
3252 "Donor - Acceptor Distance (nm)" :
3253 "Hydrogen - Acceptor Distance (nm)", "", oenv);
3254 for (i = 0; i < nrbin; i++)
3256 fprintf(fp, "%10g %10g\n", (i+0.5)*rbin, rdist[i]/(rbin*(real)sum));
3261 /* Print HB angle distribution */
3262 if (opt2bSet("-ang", NFILE, fnm))
3267 for (i = 0; i < nabin; i++)
3272 fp = xvgropen(opt2fn("-ang", NFILE, fnm),
3273 "Hydrogen Bond Distribution",
3274 "Hydrogen - Donor - Acceptor Angle (\\SO\\N)", "", oenv);
3275 for (i = 0; i < nabin; i++)
3277 fprintf(fp, "%10g %10g\n", (i+0.5)*abin, adist[i]/(abin*(real)sum));
3282 /* Print HB in alpha-helix */
3283 if (opt2bSet("-hx", NFILE, fnm))
3285 fp = xvgropen(opt2fn("-hx", NFILE, fnm),
3286 "Hydrogen Bonds", output_env_get_xvgr_tlabel(oenv), "Count", oenv);
3287 xvgr_legend(fp, NRHXTYPES, hxtypenames, oenv);
3288 for (i = 0; i < nframes; i++)
3290 fprintf(fp, "%10g", hb->time[i]);
3291 for (j = 0; j < max_hx; j++)
3293 fprintf(fp, " %6d", hb->nhx[i][j]);
3300 printf("Average number of %s per timeframe %.3f out of %g possible\n",
3301 bContact ? "contacts" : "hbonds",
3302 bContact ? aver_dist : aver_nhb, max_nhb);
3304 /* Do Autocorrelation etc. */
3308 Added support for -contact in ac and hbm calculations below.
3309 - Erik Marklund, May 29, 2006
3313 if (opt2bSet("-ac", NFILE, fnm) || opt2bSet("-life", NFILE, fnm))
3315 please_cite(stdout, "Spoel2006b");
3317 if (opt2bSet("-ac", NFILE, fnm))
3319 char *gemstring = NULL;
3321 do_hbac(opt2fn("-ac", NFILE, fnm), hb, nDump,
3322 bMerge, bContact, fit_start, temp, r2cut > 0, oenv,
3325 if (opt2bSet("-life", NFILE, fnm))
3327 do_hblife(opt2fn("-life", NFILE, fnm), hb, bMerge, bContact, oenv);
3329 if (opt2bSet("-hbm", NFILE, fnm))
3332 int id, ia, hh, x, y;
3333 mat.flags = mat.y0 = 0;
3335 if ((nframes > 0) && (hb->nrhb > 0))
3340 snew(mat.matrix, mat.nx);
3341 for (x = 0; (x < mat.nx); x++)
3343 snew(mat.matrix[x], mat.ny);
3346 for (id = 0; (id < hb->d.nrd); id++)
3348 for (ia = 0; (ia < hb->a.nra); ia++)
3350 for (hh = 0; (hh < hb->maxhydro); hh++)
3352 if (hb->hbmap[id][ia])
3354 if (ISHB(hb->hbmap[id][ia]->history[hh]))
3356 for (x = 0; (x <= hb->hbmap[id][ia]->nframes); x++)
3358 int nn0 = hb->hbmap[id][ia]->n0;
3359 range_check(y, 0, mat.ny);
3360 mat.matrix[x+nn0][y] = is_hb(hb->hbmap[id][ia]->h[hh], x);
3368 mat.axis_x = hb->time;
3369 snew(mat.axis_y, mat.ny);
3370 for (j = 0; j < mat.ny; j++)
3374 sprintf(mat.title, bContact ? "Contact Existence Map" :
3375 "Hydrogen Bond Existence Map");
3376 sprintf(mat.legend, bContact ? "Contacts" : "Hydrogen Bonds");
3377 sprintf(mat.label_x, "%s", output_env_get_xvgr_tlabel(oenv));
3378 sprintf(mat.label_y, bContact ? "Contact Index" : "Hydrogen Bond Index");
3379 mat.bDiscrete = TRUE;
3381 snew(mat.map, mat.nmap);
3382 for (i = 0; i < mat.nmap; i++)
3384 mat.map[i].code.c1 = hbmap[i];
3385 mat.map[i].desc = hbdesc[i];
3386 mat.map[i].rgb = hbrgb[i];
3388 fp = opt2FILE("-hbm", NFILE, fnm, "w");
3389 write_xpm_m(fp, mat);
3391 for (x = 0; x < mat.nx; x++)
3393 sfree(mat.matrix[x]);
3401 fprintf(stderr, "No hydrogen bonds/contacts found. No hydrogen bond map will be printed.\n");
3412 #define USE_THIS_GROUP(j) ( (j == gr0) || (bTwo && (j == gr1)) )
3414 fp = xvgropen(opt2fn("-dan", NFILE, fnm),
3415 "Donors and Acceptors", output_env_get_xvgr_tlabel(oenv), "Count", oenv);
3416 nleg = (bTwo ? 2 : 1)*2;
3417 snew(legnames, nleg);
3419 for (j = 0; j < grNR; j++)
3421 if (USE_THIS_GROUP(j) )
3423 sprintf(buf, "Donors %s", grpnames[j]);
3424 legnames[i++] = gmx_strdup(buf);
3425 sprintf(buf, "Acceptors %s", grpnames[j]);
3426 legnames[i++] = gmx_strdup(buf);
3431 gmx_incons("number of legend entries");
3433 xvgr_legend(fp, nleg, (const char**)legnames, oenv);
3434 for (i = 0; i < nframes; i++)
3436 fprintf(fp, "%10g", hb->time[i]);
3437 for (j = 0; (j < grNR); j++)
3439 if (USE_THIS_GROUP(j) )
3441 fprintf(fp, " %6d", hb->danr[i][j]);