Replaced NOTSET from typedefs.h by local solutions.
[gromacs.git] / src / gromacs / gmxana / gmx_hbond.cpp
blob261353670a09962d1c25c32b85f258c10a89352b
1 /*
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.
37 #include "gmxpre.h"
39 #include "config.h"
41 #include <cmath>
42 #include <cstdlib>
43 #include <cstring>
45 #include <algorithm>
47 #include "gromacs/commandline/pargs.h"
48 #include "gromacs/commandline/viewit.h"
49 #include "gromacs/correlationfunctions/autocorr.h"
50 #include "gromacs/correlationfunctions/crosscorr.h"
51 #include "gromacs/correlationfunctions/expfit.h"
52 #include "gromacs/correlationfunctions/integrate.h"
53 #include "gromacs/fileio/matio.h"
54 #include "gromacs/fileio/tpxio.h"
55 #include "gromacs/fileio/trxio.h"
56 #include "gromacs/fileio/xvgr.h"
57 #include "gromacs/gmxana/gmx_ana.h"
58 #include "gromacs/gmxana/gstat.h"
59 #include "gromacs/legacyheaders/copyrite.h"
60 #include "gromacs/legacyheaders/txtdump.h"
61 #include "gromacs/legacyheaders/types/ifunc.h"
62 #include "gromacs/math/units.h"
63 #include "gromacs/math/vec.h"
64 #include "gromacs/pbcutil/pbc.h"
65 #include "gromacs/topology/index.h"
66 #include "gromacs/utility/arraysize.h"
67 #include "gromacs/utility/cstringutil.h"
68 #include "gromacs/utility/exceptions.h"
69 #include "gromacs/utility/fatalerror.h"
70 #include "gromacs/utility/futil.h"
71 #include "gromacs/utility/gmxomp.h"
72 #include "gromacs/utility/smalloc.h"
73 #include "gromacs/utility/snprintf.h"
75 #define max_hx 7
76 typedef int t_hx[max_hx];
77 #define NRHXTYPES max_hx
78 const char *hxtypenames[NRHXTYPES] =
79 {"n-n", "n-n+1", "n-n+2", "n-n+3", "n-n+4", "n-n+5", "n-n>6"};
80 #define MAXHH 4
82 static const int NOTSET = -49297;
84 #ifdef GMX_OPENMP
85 #define MASTER_THREAD_ONLY(threadNr) ((threadNr) == 0)
86 #else
87 #define MASTER_THREAD_ONLY(threadNr) ((threadNr) == (threadNr))
88 #endif
90 /* -----------------------------------------*/
92 enum {
93 gr0, gr1, grI, grNR
95 enum {
96 hbNo, hbDist, hbHB, hbNR, hbR2
98 enum {
99 noDA, ACC, DON, DA, INGROUP
102 static const char *grpnames[grNR] = {"0", "1", "I" };
104 static gmx_bool bDebug = FALSE;
106 #define HB_NO 0
107 #define HB_YES 1<<0
108 #define HB_INS 1<<1
109 #define HB_YESINS HB_YES|HB_INS
110 #define HB_NR (1<<2)
111 #define MAXHYDRO 4
113 #define ISHB(h) (((h) & 2) == 2)
114 #define ISDIST(h) (((h) & 1) == 1)
115 #define ISDIST2(h) (((h) & 4) == 4)
116 #define ISACC(h) (((h) & 1) == 1)
117 #define ISDON(h) (((h) & 2) == 2)
118 #define ISINGRP(h) (((h) & 4) == 4)
120 typedef struct {
121 int nr;
122 int maxnr;
123 atom_id *atoms;
124 } t_ncell;
126 typedef struct {
127 t_ncell d[grNR];
128 t_ncell a[grNR];
129 } t_gridcell;
131 typedef int t_icell[grNR];
132 typedef atom_id h_id[MAXHYDRO];
134 typedef struct {
135 int history[MAXHYDRO];
136 /* Has this hbond existed ever? If so as hbDist or hbHB or both.
137 * Result is stored as a bitmap (1 = hbDist) || (2 = hbHB)
139 /* Bitmask array which tells whether a hbond is present
140 * at a given time. Either of these may be NULL
142 int n0; /* First frame a HB was found */
143 int nframes, maxframes; /* Amount of frames in this hbond */
144 unsigned int **h;
145 unsigned int **g;
146 /* See Xu and Berne, JPCB 105 (2001), p. 11929. We define the
147 * function g(t) = [1-h(t)] H(t) where H(t) is one when the donor-
148 * acceptor distance is less than the user-specified distance (typically
149 * 0.35 nm).
151 } t_hbond;
153 typedef struct {
154 int nra, max_nra;
155 atom_id *acc; /* Atom numbers of the acceptors */
156 int *grp; /* Group index */
157 int *aptr; /* Map atom number to acceptor index */
158 } t_acceptors;
160 typedef struct {
161 int nrd, max_nrd;
162 int *don; /* Atom numbers of the donors */
163 int *grp; /* Group index */
164 int *dptr; /* Map atom number to donor index */
165 int *nhydro; /* Number of hydrogens for each donor */
166 h_id *hydro; /* The atom numbers of the hydrogens */
167 h_id *nhbonds; /* The number of HBs per H at current */
168 } t_donors;
170 typedef struct {
171 gmx_bool bHBmap, bDAnr;
172 int wordlen;
173 /* The following arrays are nframes long */
174 int nframes, max_frames, maxhydro;
175 int *nhb, *ndist;
176 h_id *n_bound;
177 real *time;
178 t_icell *danr;
179 t_hx *nhx;
180 /* These structures are initialized from the topology at start up */
181 t_donors d;
182 t_acceptors a;
183 /* This holds a matrix with all possible hydrogen bonds */
184 int nrhb, nrdist;
185 t_hbond ***hbmap;
186 } t_hbdata;
188 /* Changed argument 'bMerge' into 'oneHB' below,
189 * since -contact should cause maxhydro to be 1,
190 * not just -merge.
191 * - Erik Marklund May 29, 2006
194 static t_hbdata *mk_hbdata(gmx_bool bHBmap, gmx_bool bDAnr, gmx_bool oneHB)
196 t_hbdata *hb;
198 snew(hb, 1);
199 hb->wordlen = 8*sizeof(unsigned int);
200 hb->bHBmap = bHBmap;
201 hb->bDAnr = bDAnr;
202 if (oneHB)
204 hb->maxhydro = 1;
206 else
208 hb->maxhydro = MAXHYDRO;
210 return hb;
213 static void mk_hbmap(t_hbdata *hb)
215 int i, j;
217 snew(hb->hbmap, hb->d.nrd);
218 for (i = 0; (i < hb->d.nrd); i++)
220 snew(hb->hbmap[i], hb->a.nra);
221 if (hb->hbmap[i] == NULL)
223 gmx_fatal(FARGS, "Could not allocate enough memory for hbmap");
225 for (j = 0; (j > hb->a.nra); j++)
227 hb->hbmap[i][j] = NULL;
232 static void add_frames(t_hbdata *hb, int nframes)
234 if (nframes >= hb->max_frames)
236 hb->max_frames += 4096;
237 srenew(hb->time, hb->max_frames);
238 srenew(hb->nhb, hb->max_frames);
239 srenew(hb->ndist, hb->max_frames);
240 srenew(hb->n_bound, hb->max_frames);
241 srenew(hb->nhx, hb->max_frames);
242 if (hb->bDAnr)
244 srenew(hb->danr, hb->max_frames);
247 hb->nframes = nframes;
250 #define OFFSET(frame) (frame / 32)
251 #define MASK(frame) (1 << (frame % 32))
253 static void _set_hb(unsigned int hbexist[], unsigned int frame, gmx_bool bValue)
255 if (bValue)
257 hbexist[OFFSET(frame)] |= MASK(frame);
259 else
261 hbexist[OFFSET(frame)] &= ~MASK(frame);
265 static gmx_bool is_hb(unsigned int hbexist[], int frame)
267 return ((hbexist[OFFSET(frame)] & MASK(frame)) != 0) ? 1 : 0;
270 static void set_hb(t_hbdata *hb, int id, int ih, int ia, int frame, int ihb)
272 unsigned int *ghptr = NULL;
274 if (ihb == hbHB)
276 ghptr = hb->hbmap[id][ia]->h[ih];
278 else if (ihb == hbDist)
280 ghptr = hb->hbmap[id][ia]->g[ih];
282 else
284 gmx_fatal(FARGS, "Incomprehensible iValue %d in set_hb", ihb);
287 _set_hb(ghptr, frame-hb->hbmap[id][ia]->n0, TRUE);
290 static void add_ff(t_hbdata *hbd, int id, int h, int ia, int frame, int ihb)
292 int i, j, n;
293 t_hbond *hb = hbd->hbmap[id][ia];
294 int maxhydro = std::min(hbd->maxhydro, hbd->d.nhydro[id]);
295 int wlen = hbd->wordlen;
296 int delta = 32*wlen;
298 if (!hb->h[0])
300 hb->n0 = frame;
301 hb->maxframes = delta;
302 for (i = 0; (i < maxhydro); i++)
304 snew(hb->h[i], hb->maxframes/wlen);
305 snew(hb->g[i], hb->maxframes/wlen);
308 else
310 hb->nframes = frame-hb->n0;
311 /* We need a while loop here because hbonds may be returning
312 * after a long time.
314 while (hb->nframes >= hb->maxframes)
316 n = hb->maxframes + delta;
317 for (i = 0; (i < maxhydro); i++)
319 srenew(hb->h[i], n/wlen);
320 srenew(hb->g[i], n/wlen);
321 for (j = hb->maxframes/wlen; (j < n/wlen); j++)
323 hb->h[i][j] = 0;
324 hb->g[i][j] = 0;
328 hb->maxframes = n;
331 if (frame >= 0)
333 set_hb(hbd, id, h, ia, frame, ihb);
338 static void inc_nhbonds(t_donors *ddd, int d, int h)
340 int j;
341 int dptr = ddd->dptr[d];
343 for (j = 0; (j < ddd->nhydro[dptr]); j++)
345 if (ddd->hydro[dptr][j] == h)
347 ddd->nhbonds[dptr][j]++;
348 break;
351 if (j == ddd->nhydro[dptr])
353 gmx_fatal(FARGS, "No such hydrogen %d on donor %d\n", h+1, d+1);
357 static int _acceptor_index(t_acceptors *a, int grp, atom_id i,
358 const char *file, int line)
360 int ai = a->aptr[i];
362 if (a->grp[ai] != grp)
364 if (debug && bDebug)
366 fprintf(debug, "Acc. group inconsist.. grp[%d] = %d, grp = %d (%s, %d)\n",
367 ai, a->grp[ai], grp, file, line);
369 return NOTSET;
371 else
373 return ai;
376 #define acceptor_index(a, grp, i) _acceptor_index(a, grp, i, __FILE__, __LINE__)
378 static int _donor_index(t_donors *d, int grp, atom_id i, const char *file, int line)
380 int di = d->dptr[i];
382 if (di == NOTSET)
384 return NOTSET;
387 if (d->grp[di] != grp)
389 if (debug && bDebug)
391 fprintf(debug, "Don. group inconsist.. grp[%d] = %d, grp = %d (%s, %d)\n",
392 di, d->grp[di], grp, file, line);
394 return NOTSET;
396 else
398 return di;
401 #define donor_index(d, grp, i) _donor_index(d, grp, i, __FILE__, __LINE__)
403 static gmx_bool isInterchangable(t_hbdata *hb, int d, int a, int grpa, int grpd)
405 /* g_hbond doesn't allow overlapping groups */
406 if (grpa != grpd)
408 return FALSE;
410 return
411 donor_index(&hb->d, grpd, a) != NOTSET
412 && acceptor_index(&hb->a, grpa, d) != NOTSET;
416 static void add_hbond(t_hbdata *hb, int d, int a, int h, int grpd, int grpa,
417 int frame, gmx_bool bMerge, int ihb, gmx_bool bContact)
419 int k, id, ia, hh;
420 gmx_bool daSwap = FALSE;
422 if ((id = hb->d.dptr[d]) == NOTSET)
424 gmx_fatal(FARGS, "No donor atom %d", d+1);
426 else if (grpd != hb->d.grp[id])
428 gmx_fatal(FARGS, "Inconsistent donor groups, %d iso %d, atom %d",
429 grpd, hb->d.grp[id], d+1);
431 if ((ia = hb->a.aptr[a]) == NOTSET)
433 gmx_fatal(FARGS, "No acceptor atom %d", a+1);
435 else if (grpa != hb->a.grp[ia])
437 gmx_fatal(FARGS, "Inconsistent acceptor groups, %d iso %d, atom %d",
438 grpa, hb->a.grp[ia], a+1);
441 if (bMerge)
444 if (isInterchangable(hb, d, a, grpd, grpa) && d > a)
445 /* Then swap identity so that the id of d is lower then that of a.
447 * This should really be redundant by now, as is_hbond() now ought to return
448 * hbNo in the cases where this conditional is TRUE. */
450 daSwap = TRUE;
451 k = d;
452 d = a;
453 a = k;
455 /* Now repeat donor/acc check. */
456 if ((id = hb->d.dptr[d]) == NOTSET)
458 gmx_fatal(FARGS, "No donor atom %d", d+1);
460 else if (grpd != hb->d.grp[id])
462 gmx_fatal(FARGS, "Inconsistent donor groups, %d iso %d, atom %d",
463 grpd, hb->d.grp[id], d+1);
465 if ((ia = hb->a.aptr[a]) == NOTSET)
467 gmx_fatal(FARGS, "No acceptor atom %d", a+1);
469 else if (grpa != hb->a.grp[ia])
471 gmx_fatal(FARGS, "Inconsistent acceptor groups, %d iso %d, atom %d",
472 grpa, hb->a.grp[ia], a+1);
477 if (hb->hbmap)
479 /* Loop over hydrogens to find which hydrogen is in this particular HB */
480 if ((ihb == hbHB) && !bMerge && !bContact)
482 for (k = 0; (k < hb->d.nhydro[id]); k++)
484 if (hb->d.hydro[id][k] == h)
486 break;
489 if (k == hb->d.nhydro[id])
491 gmx_fatal(FARGS, "Donor %d does not have hydrogen %d (a = %d)",
492 d+1, h+1, a+1);
495 else
497 k = 0;
500 if (hb->bHBmap)
503 #pragma omp critical
507 if (hb->hbmap[id][ia] == NULL)
509 snew(hb->hbmap[id][ia], 1);
510 snew(hb->hbmap[id][ia]->h, hb->maxhydro);
511 snew(hb->hbmap[id][ia]->g, hb->maxhydro);
513 add_ff(hb, id, k, ia, frame, ihb);
515 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
519 /* Strange construction with frame >=0 is a relic from old code
520 * for selected hbond analysis. It may be necessary again if that
521 * is made to work again.
523 if (frame >= 0)
525 hh = hb->hbmap[id][ia]->history[k];
526 if (ihb == hbHB)
528 hb->nhb[frame]++;
529 if (!(ISHB(hh)))
531 hb->hbmap[id][ia]->history[k] = hh | 2;
532 hb->nrhb++;
535 else
537 if (ihb == hbDist)
539 hb->ndist[frame]++;
540 if (!(ISDIST(hh)))
542 hb->hbmap[id][ia]->history[k] = hh | 1;
543 hb->nrdist++;
549 else
551 if (frame >= 0)
553 if (ihb == hbHB)
555 hb->nhb[frame]++;
557 else
559 if (ihb == hbDist)
561 hb->ndist[frame]++;
566 if (bMerge && daSwap)
568 h = hb->d.hydro[id][0];
570 /* Increment number if HBonds per H */
571 if (ihb == hbHB && !bContact)
573 inc_nhbonds(&(hb->d), d, h);
577 static char *mkatomname(t_atoms *atoms, int i)
579 static char buf[32];
580 int rnr;
582 rnr = atoms->atom[i].resind;
583 sprintf(buf, "%4s%d%-4s",
584 *atoms->resinfo[rnr].name, atoms->resinfo[rnr].nr, *atoms->atomname[i]);
586 return buf;
589 static void gen_datable(atom_id *index, int isize, unsigned char *datable, int natoms)
591 /* Generates table of all atoms and sets the ingroup bit for atoms in index[] */
592 int i;
594 for (i = 0; i < isize; i++)
596 if (index[i] >= natoms)
598 gmx_fatal(FARGS, "Atom has index %d larger than number of atoms %d.", index[i], natoms);
600 datable[index[i]] |= INGROUP;
604 static void clear_datable_grp(unsigned char *datable, int size)
606 /* Clears group information from the table */
607 int i;
608 const char mask = !(char)INGROUP;
609 if (size > 0)
611 for (i = 0; i < size; i++)
613 datable[i] &= mask;
618 static void add_acc(t_acceptors *a, int ia, int grp)
620 if (a->nra >= a->max_nra)
622 a->max_nra += 16;
623 srenew(a->acc, a->max_nra);
624 srenew(a->grp, a->max_nra);
626 a->grp[a->nra] = grp;
627 a->acc[a->nra++] = ia;
630 static void search_acceptors(t_topology *top, int isize,
631 atom_id *index, t_acceptors *a, int grp,
632 gmx_bool bNitAcc,
633 gmx_bool bContact, gmx_bool bDoIt, unsigned char *datable)
635 int i, n;
637 if (bDoIt)
639 for (i = 0; (i < isize); i++)
641 n = index[i];
642 if ((bContact ||
643 (((*top->atoms.atomname[n])[0] == 'O') ||
644 (bNitAcc && ((*top->atoms.atomname[n])[0] == 'N')))) &&
645 ISINGRP(datable[n]))
647 datable[n] |= ACC; /* set the atom's acceptor flag in datable. */
648 add_acc(a, n, grp);
652 snew(a->aptr, top->atoms.nr);
653 for (i = 0; (i < top->atoms.nr); i++)
655 a->aptr[i] = NOTSET;
657 for (i = 0; (i < a->nra); i++)
659 a->aptr[a->acc[i]] = i;
663 static void add_h2d(int id, int ih, t_donors *ddd)
665 int i;
667 for (i = 0; (i < ddd->nhydro[id]); i++)
669 if (ddd->hydro[id][i] == ih)
671 printf("Hm. This isn't the first time I found this donor (%d,%d)\n",
672 ddd->don[id], ih);
673 break;
676 if (i == ddd->nhydro[id])
678 if (ddd->nhydro[id] >= MAXHYDRO)
680 gmx_fatal(FARGS, "Donor %d has more than %d hydrogens!",
681 ddd->don[id], MAXHYDRO);
683 ddd->hydro[id][i] = ih;
684 ddd->nhydro[id]++;
688 static void add_dh(t_donors *ddd, int id, int ih, int grp, unsigned char *datable)
690 int i;
692 if (!datable || ISDON(datable[id]))
694 if (ddd->dptr[id] == NOTSET) /* New donor */
696 i = ddd->nrd;
697 ddd->dptr[id] = i;
699 else
701 i = ddd->dptr[id];
704 if (i == ddd->nrd)
706 if (ddd->nrd >= ddd->max_nrd)
708 ddd->max_nrd += 128;
709 srenew(ddd->don, ddd->max_nrd);
710 srenew(ddd->nhydro, ddd->max_nrd);
711 srenew(ddd->hydro, ddd->max_nrd);
712 srenew(ddd->nhbonds, ddd->max_nrd);
713 srenew(ddd->grp, ddd->max_nrd);
715 ddd->don[ddd->nrd] = id;
716 ddd->nhydro[ddd->nrd] = 0;
717 ddd->grp[ddd->nrd] = grp;
718 ddd->nrd++;
720 else
722 ddd->don[i] = id;
724 add_h2d(i, ih, ddd);
726 else
727 if (datable)
729 printf("Warning: Atom %d is not in the d/a-table!\n", id);
733 static void search_donors(t_topology *top, int isize, atom_id *index,
734 t_donors *ddd, int grp, gmx_bool bContact, gmx_bool bDoIt,
735 unsigned char *datable)
737 int i, j;
738 t_functype func_type;
739 t_ilist *interaction;
740 atom_id nr1, nr2, nr3;
742 if (!ddd->dptr)
744 snew(ddd->dptr, top->atoms.nr);
745 for (i = 0; (i < top->atoms.nr); i++)
747 ddd->dptr[i] = NOTSET;
751 if (bContact)
753 if (bDoIt)
755 for (i = 0; (i < isize); i++)
757 datable[index[i]] |= DON;
758 add_dh(ddd, index[i], -1, grp, datable);
762 else
764 for (func_type = 0; (func_type < F_NRE); func_type++)
766 interaction = &(top->idef.il[func_type]);
767 if (func_type == F_POSRES || func_type == F_FBPOSRES)
769 /* The ilist looks strange for posre. Bug in grompp?
770 * We don't need posre interactions for hbonds anyway.*/
771 continue;
773 for (i = 0; i < interaction->nr;
774 i += interaction_function[top->idef.functype[interaction->iatoms[i]]].nratoms+1)
776 /* next function */
777 if (func_type != top->idef.functype[interaction->iatoms[i]])
779 fprintf(stderr, "Error in func_type %s",
780 interaction_function[func_type].longname);
781 continue;
784 /* check out this functype */
785 if (func_type == F_SETTLE)
787 nr1 = interaction->iatoms[i+1];
788 nr2 = interaction->iatoms[i+2];
789 nr3 = interaction->iatoms[i+3];
791 if (ISINGRP(datable[nr1]))
793 if (ISINGRP(datable[nr2]))
795 datable[nr1] |= DON;
796 add_dh(ddd, nr1, nr1+1, grp, datable);
798 if (ISINGRP(datable[nr3]))
800 datable[nr1] |= DON;
801 add_dh(ddd, nr1, nr1+2, grp, datable);
805 else if (IS_CHEMBOND(func_type))
807 for (j = 0; j < 2; j++)
809 nr1 = interaction->iatoms[i+1+j];
810 nr2 = interaction->iatoms[i+2-j];
811 if ((*top->atoms.atomname[nr1][0] == 'H') &&
812 ((*top->atoms.atomname[nr2][0] == 'O') ||
813 (*top->atoms.atomname[nr2][0] == 'N')) &&
814 ISINGRP(datable[nr1]) && ISINGRP(datable[nr2]))
816 datable[nr2] |= DON;
817 add_dh(ddd, nr2, nr1, grp, datable);
823 #ifdef SAFEVSITES
824 for (func_type = 0; func_type < F_NRE; func_type++)
826 interaction = &top->idef.il[func_type];
827 for (i = 0; i < interaction->nr;
828 i += interaction_function[top->idef.functype[interaction->iatoms[i]]].nratoms+1)
830 /* next function */
831 if (func_type != top->idef.functype[interaction->iatoms[i]])
833 gmx_incons("function type in search_donors");
836 if (interaction_function[func_type].flags & IF_VSITE)
838 nr1 = interaction->iatoms[i+1];
839 if (*top->atoms.atomname[nr1][0] == 'H')
841 nr2 = nr1-1;
842 stop = FALSE;
843 while (!stop && ( *top->atoms.atomname[nr2][0] == 'H'))
845 if (nr2)
847 nr2--;
849 else
851 stop = TRUE;
854 if (!stop && ( ( *top->atoms.atomname[nr2][0] == 'O') ||
855 ( *top->atoms.atomname[nr2][0] == 'N') ) &&
856 ISINGRP(datable[nr1]) && ISINGRP(datable[nr2]))
858 datable[nr2] |= DON;
859 add_dh(ddd, nr2, nr1, grp, datable);
865 #endif
869 static t_gridcell ***init_grid(gmx_bool bBox, rvec box[], real rcut, ivec ngrid)
871 t_gridcell ***grid;
872 int i, y, z;
874 if (bBox)
876 for (i = 0; i < DIM; i++)
878 ngrid[i] = static_cast<int>(box[i][i]/(1.2*rcut));
882 if (!bBox || (ngrid[XX] < 3) || (ngrid[YY] < 3) || (ngrid[ZZ] < 3) )
884 for (i = 0; i < DIM; i++)
886 ngrid[i] = 1;
889 else
891 printf("\nWill do grid-seach on %dx%dx%d grid, rcut=%g\n",
892 ngrid[XX], ngrid[YY], ngrid[ZZ], rcut);
894 snew(grid, ngrid[ZZ]);
895 for (z = 0; z < ngrid[ZZ]; z++)
897 snew((grid)[z], ngrid[YY]);
898 for (y = 0; y < ngrid[YY]; y++)
900 snew((grid)[z][y], ngrid[XX]);
903 return grid;
906 static void reset_nhbonds(t_donors *ddd)
908 int i, j;
910 for (i = 0; (i < ddd->nrd); i++)
912 for (j = 0; (j < MAXHH); j++)
914 ddd->nhbonds[i][j] = 0;
919 void pbc_correct_gem(rvec dx, matrix box, rvec hbox);
920 void pbc_in_gridbox(rvec dx, matrix box);
922 static void build_grid(t_hbdata *hb, rvec x[], rvec xshell,
923 gmx_bool bBox, matrix box, rvec hbox,
924 real rcut, real rshell,
925 ivec ngrid, t_gridcell ***grid)
927 int i, m, gr, xi, yi, zi, nr;
928 atom_id *ad;
929 ivec grididx;
930 rvec invdelta, dshell;
931 t_ncell *newgrid;
932 gmx_bool bDoRshell, bInShell, bAcc;
933 real rshell2 = 0;
934 int gx, gy, gz;
935 int dum = -1;
937 bDoRshell = (rshell > 0);
938 rshell2 = sqr(rshell);
939 bInShell = TRUE;
941 #define DBB(x) if (debug && bDebug) fprintf(debug, "build_grid, line %d, %s = %d\n", __LINE__,#x, x)
942 DBB(dum);
943 for (m = 0; m < DIM; m++)
945 hbox[m] = box[m][m]*0.5;
946 if (bBox)
948 invdelta[m] = ngrid[m]/box[m][m];
949 if (1/invdelta[m] < rcut)
951 gmx_fatal(FARGS, "Your computational box has shrunk too much.\n"
952 "%s can not handle this situation, sorry.\n",
953 ShortProgram());
956 else
958 invdelta[m] = 0;
961 grididx[XX] = 0;
962 grididx[YY] = 0;
963 grididx[ZZ] = 0;
964 DBB(dum);
965 /* resetting atom counts */
966 for (gr = 0; (gr < grNR); gr++)
968 for (zi = 0; zi < ngrid[ZZ]; zi++)
970 for (yi = 0; yi < ngrid[YY]; yi++)
972 for (xi = 0; xi < ngrid[XX]; xi++)
974 grid[zi][yi][xi].d[gr].nr = 0;
975 grid[zi][yi][xi].a[gr].nr = 0;
979 DBB(dum);
981 /* put atoms in grid cells */
982 for (bAcc = FALSE; (bAcc <= TRUE); bAcc++)
984 if (bAcc)
986 nr = hb->a.nra;
987 ad = hb->a.acc;
989 else
991 nr = hb->d.nrd;
992 ad = hb->d.don;
994 DBB(bAcc);
995 for (i = 0; (i < nr); i++)
997 /* check if we are inside the shell */
998 /* if bDoRshell=FALSE then bInShell=TRUE always */
999 DBB(i);
1000 if (bDoRshell)
1002 bInShell = TRUE;
1003 rvec_sub(x[ad[i]], xshell, dshell);
1004 if (bBox)
1006 gmx_bool bDone = FALSE;
1007 while (!bDone)
1009 bDone = TRUE;
1010 for (m = DIM-1; m >= 0 && bInShell; m--)
1012 if (dshell[m] < -hbox[m])
1014 bDone = FALSE;
1015 rvec_inc(dshell, box[m]);
1017 if (dshell[m] >= hbox[m])
1019 bDone = FALSE;
1020 dshell[m] -= 2*hbox[m];
1024 for (m = DIM-1; m >= 0 && bInShell; m--)
1026 /* if we're outside the cube, we're outside the sphere also! */
1027 if ( (dshell[m] > rshell) || (-dshell[m] > rshell) )
1029 bInShell = FALSE;
1033 /* if we're inside the cube, check if we're inside the sphere */
1034 if (bInShell)
1036 bInShell = norm2(dshell) < rshell2;
1039 DBB(i);
1040 if (bInShell)
1042 if (bBox)
1044 pbc_in_gridbox(x[ad[i]], box);
1046 for (m = DIM-1; m >= 0; m--)
1047 { /* determine grid index of atom */
1048 grididx[m] = static_cast<int>(x[ad[i]][m]*invdelta[m]);
1049 grididx[m] = (grididx[m]+ngrid[m]) % ngrid[m];
1053 gx = grididx[XX];
1054 gy = grididx[YY];
1055 gz = grididx[ZZ];
1056 range_check(gx, 0, ngrid[XX]);
1057 range_check(gy, 0, ngrid[YY]);
1058 range_check(gz, 0, ngrid[ZZ]);
1059 DBB(gx);
1060 DBB(gy);
1061 DBB(gz);
1062 /* add atom to grid cell */
1063 if (bAcc)
1065 newgrid = &(grid[gz][gy][gx].a[gr]);
1067 else
1069 newgrid = &(grid[gz][gy][gx].d[gr]);
1071 if (newgrid->nr >= newgrid->maxnr)
1073 newgrid->maxnr += 10;
1074 DBB(newgrid->maxnr);
1075 srenew(newgrid->atoms, newgrid->maxnr);
1077 DBB(newgrid->nr);
1078 newgrid->atoms[newgrid->nr] = ad[i];
1079 newgrid->nr++;
1086 static void count_da_grid(ivec ngrid, t_gridcell ***grid, t_icell danr)
1088 int gr, xi, yi, zi;
1090 for (gr = 0; (gr < grNR); gr++)
1092 danr[gr] = 0;
1093 for (zi = 0; zi < ngrid[ZZ]; zi++)
1095 for (yi = 0; yi < ngrid[YY]; yi++)
1097 for (xi = 0; xi < ngrid[XX]; xi++)
1099 danr[gr] += grid[zi][yi][xi].d[gr].nr;
1106 /* The grid loop.
1107 * Without a box, the grid is 1x1x1, so all loops are 1 long.
1108 * With a rectangular box (bTric==FALSE) all loops are 3 long.
1109 * With a triclinic box all loops are 3 long, except when a cell is
1110 * located next to one of the box edges which is not parallel to the
1111 * x/y-plane, in that case all cells in a line or layer are searched.
1112 * This could be implemented slightly more efficient, but the code
1113 * would get much more complicated.
1115 static gmx_inline gmx_bool grid_loop_begin(int n, int x, gmx_bool bTric, gmx_bool bEdge)
1117 return ((n == 1) ? x : bTric && bEdge ? 0 : (x-1));
1119 static gmx_inline gmx_bool grid_loop_end(int n, int x, gmx_bool bTric, gmx_bool bEdge)
1121 return ((n == 1) ? x : bTric && bEdge ? (n-1) : (x+1));
1123 static gmx_inline int grid_mod(int j, int n)
1125 return (j+n) % (n);
1128 static void dump_grid(FILE *fp, ivec ngrid, t_gridcell ***grid)
1130 int gr, x, y, z, sum[grNR];
1132 fprintf(fp, "grid %dx%dx%d\n", ngrid[XX], ngrid[YY], ngrid[ZZ]);
1133 for (gr = 0; gr < grNR; gr++)
1135 sum[gr] = 0;
1136 fprintf(fp, "GROUP %d (%s)\n", gr, grpnames[gr]);
1137 for (z = 0; z < ngrid[ZZ]; z += 2)
1139 fprintf(fp, "Z=%d,%d\n", z, z+1);
1140 for (y = 0; y < ngrid[YY]; y++)
1142 for (x = 0; x < ngrid[XX]; x++)
1144 fprintf(fp, "%3d", grid[x][y][z].d[gr].nr);
1145 sum[gr] += grid[z][y][x].d[gr].nr;
1146 fprintf(fp, "%3d", grid[x][y][z].a[gr].nr);
1147 sum[gr] += grid[z][y][x].a[gr].nr;
1150 fprintf(fp, " | ");
1151 if ( (z+1) < ngrid[ZZ])
1153 for (x = 0; x < ngrid[XX]; x++)
1155 fprintf(fp, "%3d", grid[z+1][y][x].d[gr].nr);
1156 sum[gr] += grid[z+1][y][x].d[gr].nr;
1157 fprintf(fp, "%3d", grid[z+1][y][x].a[gr].nr);
1158 sum[gr] += grid[z+1][y][x].a[gr].nr;
1161 fprintf(fp, "\n");
1165 fprintf(fp, "TOTALS:");
1166 for (gr = 0; gr < grNR; gr++)
1168 fprintf(fp, " %d=%d", gr, sum[gr]);
1170 fprintf(fp, "\n");
1173 /* New GMX record! 5 * in a row. Congratulations!
1174 * Sorry, only four left.
1176 static void free_grid(ivec ngrid, t_gridcell ****grid)
1178 int y, z;
1179 t_gridcell ***g = *grid;
1181 for (z = 0; z < ngrid[ZZ]; z++)
1183 for (y = 0; y < ngrid[YY]; y++)
1185 sfree(g[z][y]);
1187 sfree(g[z]);
1189 sfree(g);
1190 g = NULL;
1193 void pbc_correct_gem(rvec dx, matrix box, rvec hbox)
1195 int m;
1196 gmx_bool bDone = FALSE;
1197 while (!bDone)
1199 bDone = TRUE;
1200 for (m = DIM-1; m >= 0; m--)
1202 if (dx[m] < -hbox[m])
1204 bDone = FALSE;
1205 rvec_inc(dx, box[m]);
1207 if (dx[m] >= hbox[m])
1209 bDone = FALSE;
1210 rvec_dec(dx, box[m]);
1216 void pbc_in_gridbox(rvec dx, matrix box)
1218 int m;
1219 gmx_bool bDone = FALSE;
1220 while (!bDone)
1222 bDone = TRUE;
1223 for (m = DIM-1; m >= 0; m--)
1225 if (dx[m] < 0)
1227 bDone = FALSE;
1228 rvec_inc(dx, box[m]);
1230 if (dx[m] >= box[m][m])
1232 bDone = FALSE;
1233 rvec_dec(dx, box[m]);
1239 /* Added argument r2cut, changed contact and implemented
1240 * use of second cut-off.
1241 * - Erik Marklund, June 29, 2006
1243 static int is_hbond(t_hbdata *hb, int grpd, int grpa, int d, int a,
1244 real rcut, real r2cut, real ccut,
1245 rvec x[], gmx_bool bBox, matrix box, rvec hbox,
1246 real *d_ha, real *ang, gmx_bool bDA, int *hhh,
1247 gmx_bool bContact, gmx_bool bMerge)
1249 int h, hh, id;
1250 rvec r_da, r_ha, r_dh;
1251 real rc2, r2c2, rda2, rha2, ca;
1252 gmx_bool HAinrange = FALSE; /* If !bDA. Needed for returning hbDist in a correct way. */
1253 gmx_bool daSwap = FALSE;
1255 if (d == a)
1257 return hbNo;
1260 if (((id = donor_index(&hb->d, grpd, d)) == NOTSET) ||
1261 (acceptor_index(&hb->a, grpa, a) == NOTSET))
1263 return hbNo;
1266 rc2 = rcut*rcut;
1267 r2c2 = r2cut*r2cut;
1269 rvec_sub(x[d], x[a], r_da);
1270 /* Insert projection code here */
1272 if (bMerge && d > a && isInterchangable(hb, d, a, grpd, grpa))
1274 /* Then this hbond/contact will be found again, or it has already been found. */
1275 /*return hbNo;*/
1277 if (bBox)
1279 if (d > a && bMerge && isInterchangable(hb, d, a, grpd, grpa)) /* acceptor is also a donor and vice versa? */
1280 { /* return hbNo; */
1281 daSwap = TRUE; /* If so, then their history should be filed with donor and acceptor swapped. */
1283 pbc_correct_gem(r_da, box, hbox);
1285 rda2 = iprod(r_da, r_da);
1287 if (bContact)
1289 if (daSwap && grpa == grpd)
1291 return hbNo;
1293 if (rda2 <= rc2)
1295 return hbHB;
1297 else if (rda2 < r2c2)
1299 return hbDist;
1301 else
1303 return hbNo;
1306 *hhh = NOTSET;
1308 if (bDA && (rda2 > rc2))
1310 return hbNo;
1313 for (h = 0; (h < hb->d.nhydro[id]); h++)
1315 hh = hb->d.hydro[id][h];
1316 rha2 = rc2+1;
1317 if (!bDA)
1319 rvec_sub(x[hh], x[a], r_ha);
1320 if (bBox)
1322 pbc_correct_gem(r_ha, box, hbox);
1324 rha2 = iprod(r_ha, r_ha);
1327 if (bDA || (!bDA && (rha2 <= rc2)))
1329 rvec_sub(x[d], x[hh], r_dh);
1330 if (bBox)
1332 pbc_correct_gem(r_dh, box, hbox);
1335 if (!bDA)
1337 HAinrange = TRUE;
1339 ca = cos_angle(r_dh, r_da);
1340 /* if angle is smaller, cos is larger */
1341 if (ca >= ccut)
1343 *hhh = hh;
1344 *d_ha = std::sqrt(bDA ? rda2 : rha2);
1345 *ang = std::acos(ca);
1346 return hbHB;
1350 if (bDA || (!bDA && HAinrange))
1352 return hbDist;
1354 else
1356 return hbNo;
1360 /* Merging is now done on the fly, so do_merge is most likely obsolete now.
1361 * Will do some more testing before removing the function entirely.
1362 * - Erik Marklund, MAY 10 2010 */
1363 static void do_merge(t_hbdata *hb, int ntmp,
1364 unsigned int htmp[], unsigned int gtmp[],
1365 t_hbond *hb0, t_hbond *hb1)
1367 /* Here we need to make sure we're treating periodicity in
1368 * the right way for the geminate recombination kinetics. */
1370 int m, mm, n00, n01, nn0, nnframes;
1372 /* Decide where to start from when merging */
1373 n00 = hb0->n0;
1374 n01 = hb1->n0;
1375 nn0 = std::min(n00, n01);
1376 nnframes = std::max(n00 + hb0->nframes, n01 + hb1->nframes) - nn0;
1377 /* Initiate tmp arrays */
1378 for (m = 0; (m < ntmp); m++)
1380 htmp[m] = 0;
1381 gtmp[m] = 0;
1383 /* Fill tmp arrays with values due to first HB */
1384 /* Once again '<' had to be replaced with '<='
1385 to catch the last frame in which the hbond
1386 appears.
1387 - Erik Marklund, June 1, 2006 */
1388 for (m = 0; (m <= hb0->nframes); m++)
1390 mm = m+n00-nn0;
1391 htmp[mm] = is_hb(hb0->h[0], m);
1393 for (m = 0; (m <= hb0->nframes); m++)
1395 mm = m+n00-nn0;
1396 gtmp[mm] = is_hb(hb0->g[0], m);
1398 /* Next HB */
1399 for (m = 0; (m <= hb1->nframes); m++)
1401 mm = m+n01-nn0;
1402 htmp[mm] = htmp[mm] || is_hb(hb1->h[0], m);
1403 gtmp[mm] = gtmp[mm] || is_hb(hb1->g[0], m);
1405 /* Reallocate target array */
1406 if (nnframes > hb0->maxframes)
1408 srenew(hb0->h[0], 4+nnframes/hb->wordlen);
1409 srenew(hb0->g[0], 4+nnframes/hb->wordlen);
1412 /* Copy temp array to target array */
1413 for (m = 0; (m <= nnframes); m++)
1415 _set_hb(hb0->h[0], m, htmp[m]);
1416 _set_hb(hb0->g[0], m, gtmp[m]);
1419 /* Set scalar variables */
1420 hb0->n0 = nn0;
1421 hb0->maxframes = nnframes;
1424 static void merge_hb(t_hbdata *hb, gmx_bool bTwo, gmx_bool bContact)
1426 int i, inrnew, indnew, j, ii, jj, id, ia, ntmp;
1427 unsigned int *htmp, *gtmp;
1428 t_hbond *hb0, *hb1;
1430 inrnew = hb->nrhb;
1431 indnew = hb->nrdist;
1433 /* Check whether donors are also acceptors */
1434 printf("Merging hbonds with Acceptor and Donor swapped\n");
1436 ntmp = 2*hb->max_frames;
1437 snew(gtmp, ntmp);
1438 snew(htmp, ntmp);
1439 for (i = 0; (i < hb->d.nrd); i++)
1441 fprintf(stderr, "\r%d/%d", i+1, hb->d.nrd);
1442 id = hb->d.don[i];
1443 ii = hb->a.aptr[id];
1444 for (j = 0; (j < hb->a.nra); j++)
1446 ia = hb->a.acc[j];
1447 jj = hb->d.dptr[ia];
1448 if ((id != ia) && (ii != NOTSET) && (jj != NOTSET) &&
1449 (!bTwo || (bTwo && (hb->d.grp[i] != hb->a.grp[j]))))
1451 hb0 = hb->hbmap[i][j];
1452 hb1 = hb->hbmap[jj][ii];
1453 if (hb0 && hb1 && ISHB(hb0->history[0]) && ISHB(hb1->history[0]))
1455 do_merge(hb, ntmp, htmp, gtmp, hb0, hb1);
1456 if (ISHB(hb1->history[0]))
1458 inrnew--;
1460 else if (ISDIST(hb1->history[0]))
1462 indnew--;
1464 else
1465 if (bContact)
1467 gmx_incons("No contact history");
1469 else
1471 gmx_incons("Neither hydrogen bond nor distance");
1473 sfree(hb1->h[0]);
1474 sfree(hb1->g[0]);
1475 hb1->h[0] = NULL;
1476 hb1->g[0] = NULL;
1477 hb1->history[0] = hbNo;
1482 fprintf(stderr, "\n");
1483 printf("- Reduced number of hbonds from %d to %d\n", hb->nrhb, inrnew);
1484 printf("- Reduced number of distances from %d to %d\n", hb->nrdist, indnew);
1485 hb->nrhb = inrnew;
1486 hb->nrdist = indnew;
1487 sfree(gtmp);
1488 sfree(htmp);
1491 static void do_nhb_dist(FILE *fp, t_hbdata *hb, real t)
1493 int i, j, k, n_bound[MAXHH], nbtot;
1495 /* Set array to 0 */
1496 for (k = 0; (k < MAXHH); k++)
1498 n_bound[k] = 0;
1500 /* Loop over possible donors */
1501 for (i = 0; (i < hb->d.nrd); i++)
1503 for (j = 0; (j < hb->d.nhydro[i]); j++)
1505 n_bound[hb->d.nhbonds[i][j]]++;
1508 fprintf(fp, "%12.5e", t);
1509 nbtot = 0;
1510 for (k = 0; (k < MAXHH); k++)
1512 fprintf(fp, " %8d", n_bound[k]);
1513 nbtot += n_bound[k]*k;
1515 fprintf(fp, " %8d\n", nbtot);
1518 static void do_hblife(const char *fn, t_hbdata *hb, gmx_bool bMerge, gmx_bool bContact,
1519 const gmx_output_env_t *oenv)
1521 FILE *fp;
1522 const char *leg[] = { "p(t)", "t p(t)" };
1523 int *histo;
1524 int i, j, j0, k, m, nh, ihb, ohb, nhydro, ndump = 0;
1525 int nframes = hb->nframes;
1526 unsigned int **h;
1527 real t, x1, dt;
1528 double sum, integral;
1529 t_hbond *hbh;
1531 snew(h, hb->maxhydro);
1532 snew(histo, nframes+1);
1533 /* Total number of hbonds analyzed here */
1534 for (i = 0; (i < hb->d.nrd); i++)
1536 for (k = 0; (k < hb->a.nra); k++)
1538 hbh = hb->hbmap[i][k];
1539 if (hbh)
1541 if (bMerge)
1543 if (hbh->h[0])
1545 h[0] = hbh->h[0];
1546 nhydro = 1;
1548 else
1550 nhydro = 0;
1553 else
1555 nhydro = 0;
1556 for (m = 0; (m < hb->maxhydro); m++)
1558 if (hbh->h[m])
1560 h[nhydro++] = bContact ? hbh->g[m] : hbh->h[m];
1564 for (nh = 0; (nh < nhydro); nh++)
1566 ohb = 0;
1567 j0 = 0;
1569 for (j = 0; (j <= hbh->nframes); j++)
1571 ihb = is_hb(h[nh], j);
1572 if (debug && (ndump < 10))
1574 fprintf(debug, "%5d %5d\n", j, ihb);
1576 if (ihb != ohb)
1578 if (ihb)
1580 j0 = j;
1582 else
1584 histo[j-j0]++;
1586 ohb = ihb;
1589 ndump++;
1594 fprintf(stderr, "\n");
1595 if (bContact)
1597 fp = xvgropen(fn, "Uninterrupted contact lifetime", output_env_get_xvgr_tlabel(oenv), "()", oenv);
1599 else
1601 fp = xvgropen(fn, "Uninterrupted hydrogen bond lifetime", output_env_get_xvgr_tlabel(oenv), "()",
1602 oenv);
1605 xvgr_legend(fp, asize(leg), leg, oenv);
1606 j0 = nframes-1;
1607 while ((j0 > 0) && (histo[j0] == 0))
1609 j0--;
1611 sum = 0;
1612 for (i = 0; (i <= j0); i++)
1614 sum += histo[i];
1616 dt = hb->time[1]-hb->time[0];
1617 sum = dt*sum;
1618 integral = 0;
1619 for (i = 1; (i <= j0); i++)
1621 t = hb->time[i] - hb->time[0] - 0.5*dt;
1622 x1 = t*histo[i]/sum;
1623 fprintf(fp, "%8.3f %10.3e %10.3e\n", t, histo[i]/sum, x1);
1624 integral += x1;
1626 integral *= dt;
1627 xvgrclose(fp);
1628 printf("%s lifetime = %.2f ps\n", bContact ? "Contact" : "HB", integral);
1629 printf("Note that the lifetime obtained in this manner is close to useless\n");
1630 printf("Use the -ac option instead and check the Forward lifetime\n");
1631 please_cite(stdout, "Spoel2006b");
1632 sfree(h);
1633 sfree(histo);
1636 static void dump_ac(t_hbdata *hb, gmx_bool oneHB, int nDump)
1638 FILE *fp;
1639 int i, j, k, m, nd, ihb, idist;
1640 int nframes = hb->nframes;
1641 gmx_bool bPrint;
1642 t_hbond *hbh;
1644 if (nDump <= 0)
1646 return;
1648 fp = gmx_ffopen("debug-ac.xvg", "w");
1649 for (j = 0; (j < nframes); j++)
1651 fprintf(fp, "%10.3f", hb->time[j]);
1652 for (i = nd = 0; (i < hb->d.nrd) && (nd < nDump); i++)
1654 for (k = 0; (k < hb->a.nra) && (nd < nDump); k++)
1656 bPrint = FALSE;
1657 ihb = idist = 0;
1658 hbh = hb->hbmap[i][k];
1659 if (oneHB)
1661 if (hbh->h[0])
1663 ihb = is_hb(hbh->h[0], j);
1664 idist = is_hb(hbh->g[0], j);
1665 bPrint = TRUE;
1668 else
1670 for (m = 0; (m < hb->maxhydro) && !ihb; m++)
1672 ihb = ihb || ((hbh->h[m]) && is_hb(hbh->h[m], j));
1673 idist = idist || ((hbh->g[m]) && is_hb(hbh->g[m], j));
1675 /* This is not correct! */
1676 /* What isn't correct? -Erik M */
1677 bPrint = TRUE;
1679 if (bPrint)
1681 fprintf(fp, " %1d-%1d", ihb, idist);
1682 nd++;
1686 fprintf(fp, "\n");
1688 gmx_ffclose(fp);
1691 static real calc_dg(real tau, real temp)
1693 real kbt;
1695 kbt = BOLTZ*temp;
1696 if (tau <= 0)
1698 return -666;
1700 else
1702 return kbt*std::log(kbt*tau/PLANCK);
1706 typedef struct {
1707 int n0, n1, nparams, ndelta;
1708 real kkk[2];
1709 real *t, *ct, *nt, *kt, *sigma_ct, *sigma_nt, *sigma_kt;
1710 } t_luzar;
1712 static real compute_weighted_rates(int n, real t[], real ct[], real nt[],
1713 real kt[], real sigma_ct[], real sigma_nt[],
1714 real sigma_kt[], real *k, real *kp,
1715 real *sigma_k, real *sigma_kp,
1716 real fit_start)
1718 #define NK 10
1719 int i, j;
1720 t_luzar tl;
1721 real kkk = 0, kkp = 0, kk2 = 0, kp2 = 0, chi2;
1723 *sigma_k = 0;
1724 *sigma_kp = 0;
1726 for (i = 0; (i < n); i++)
1728 if (t[i] >= fit_start)
1730 break;
1733 tl.n0 = i;
1734 tl.n1 = n;
1735 tl.nparams = 2;
1736 tl.ndelta = 1;
1737 tl.t = t;
1738 tl.ct = ct;
1739 tl.nt = nt;
1740 tl.kt = kt;
1741 tl.sigma_ct = sigma_ct;
1742 tl.sigma_nt = sigma_nt;
1743 tl.sigma_kt = sigma_kt;
1744 tl.kkk[0] = *k;
1745 tl.kkk[1] = *kp;
1747 chi2 = 0; /*optimize_luzar_parameters(debug, &tl, 1000, 1e-3); */
1748 *k = tl.kkk[0];
1749 *kp = tl.kkk[1] = *kp;
1750 tl.ndelta = NK;
1751 for (j = 0; (j < NK); j++)
1753 kkk += tl.kkk[0];
1754 kkp += tl.kkk[1];
1755 kk2 += sqr(tl.kkk[0]);
1756 kp2 += sqr(tl.kkk[1]);
1757 tl.n0++;
1759 *sigma_k = std::sqrt(kk2/NK - sqr(kkk/NK));
1760 *sigma_kp = std::sqrt(kp2/NK - sqr(kkp/NK));
1762 return chi2;
1765 void analyse_corr(int n, real t[], real ct[], real nt[], real kt[],
1766 real sigma_ct[], real sigma_nt[], real sigma_kt[],
1767 real fit_start, real temp)
1769 int i0, i;
1770 real k = 1, kp = 1, kow = 1;
1771 real Q = 0, chi2, tau_hb, dtau, tau_rlx, e_1, sigma_k, sigma_kp, ddg;
1772 double tmp, sn2 = 0, sc2 = 0, sk2 = 0, scn = 0, sck = 0, snk = 0;
1773 gmx_bool bError = (sigma_ct != NULL) && (sigma_nt != NULL) && (sigma_kt != NULL);
1775 for (i0 = 0; (i0 < n-2) && ((t[i0]-t[0]) < fit_start); i0++)
1779 if (i0 < n-2)
1781 for (i = i0; (i < n); i++)
1783 sc2 += sqr(ct[i]);
1784 sn2 += sqr(nt[i]);
1785 sk2 += sqr(kt[i]);
1786 sck += ct[i]*kt[i];
1787 snk += nt[i]*kt[i];
1788 scn += ct[i]*nt[i];
1790 printf("Hydrogen bond thermodynamics at T = %g K\n", temp);
1791 tmp = (sn2*sc2-sqr(scn));
1792 if ((tmp > 0) && (sn2 > 0))
1794 k = (sn2*sck-scn*snk)/tmp;
1795 kp = (k*scn-snk)/sn2;
1796 if (bError)
1798 chi2 = 0;
1799 for (i = i0; (i < n); i++)
1801 chi2 += sqr(k*ct[i]-kp*nt[i]-kt[i]);
1803 compute_weighted_rates(n, t, ct, nt, kt, sigma_ct, sigma_nt,
1804 sigma_kt, &k, &kp,
1805 &sigma_k, &sigma_kp, fit_start);
1806 Q = 0; /* quality_of_fit(chi2, 2);*/
1807 ddg = BOLTZ*temp*sigma_k/k;
1808 printf("Fitting paramaters chi^2 = %10g, Quality of fit = %10g\n",
1809 chi2, Q);
1810 printf("The Rate and Delta G are followed by an error estimate\n");
1811 printf("----------------------------------------------------------\n"
1812 "Type Rate (1/ps) Sigma Time (ps) DG (kJ/mol) Sigma\n");
1813 printf("Forward %10.3f %6.2f %8.3f %10.3f %6.2f\n",
1814 k, sigma_k, 1/k, calc_dg(1/k, temp), ddg);
1815 ddg = BOLTZ*temp*sigma_kp/kp;
1816 printf("Backward %10.3f %6.2f %8.3f %10.3f %6.2f\n",
1817 kp, sigma_kp, 1/kp, calc_dg(1/kp, temp), ddg);
1819 else
1821 chi2 = 0;
1822 for (i = i0; (i < n); i++)
1824 chi2 += sqr(k*ct[i]-kp*nt[i]-kt[i]);
1826 printf("Fitting parameters chi^2 = %10g\nQ = %10g\n",
1827 chi2, Q);
1828 printf("--------------------------------------------------\n"
1829 "Type Rate (1/ps) Time (ps) DG (kJ/mol) Chi^2\n");
1830 printf("Forward %10.3f %8.3f %10.3f %10g\n",
1831 k, 1/k, calc_dg(1/k, temp), chi2);
1832 printf("Backward %10.3f %8.3f %10.3f\n",
1833 kp, 1/kp, calc_dg(1/kp, temp));
1836 if (sc2 > 0)
1838 kow = 2*sck/sc2;
1839 printf("One-way %10.3f %s%8.3f %10.3f\n",
1840 kow, bError ? " " : "", 1/kow, calc_dg(1/kow, temp));
1842 else
1844 printf(" - Numerical problems computing HB thermodynamics:\n"
1845 "sc2 = %g sn2 = %g sk2 = %g sck = %g snk = %g scn = %g\n",
1846 sc2, sn2, sk2, sck, snk, scn);
1848 /* Determine integral of the correlation function */
1849 tau_hb = evaluate_integral(n, t, ct, NULL, (t[n-1]-t[0])/2, &dtau);
1850 printf("Integral %10.3f %s%8.3f %10.3f\n", 1/tau_hb,
1851 bError ? " " : "", tau_hb, calc_dg(tau_hb, temp));
1852 e_1 = std::exp(-1.0);
1853 for (i = 0; (i < n-2); i++)
1855 if ((ct[i] > e_1) && (ct[i+1] <= e_1))
1857 break;
1860 if (i < n-2)
1862 /* Determine tau_relax from linear interpolation */
1863 tau_rlx = t[i]-t[0] + (e_1-ct[i])*(t[i+1]-t[i])/(ct[i+1]-ct[i]);
1864 printf("Relaxation %10.3f %8.3f %s%10.3f\n", 1/tau_rlx,
1865 tau_rlx, bError ? " " : "",
1866 calc_dg(tau_rlx, temp));
1869 else
1871 printf("Correlation functions too short to compute thermodynamics\n");
1875 void compute_derivative(int nn, real x[], real y[], real dydx[])
1877 int j;
1879 /* Compute k(t) = dc(t)/dt */
1880 for (j = 1; (j < nn-1); j++)
1882 dydx[j] = (y[j+1]-y[j-1])/(x[j+1]-x[j-1]);
1884 /* Extrapolate endpoints */
1885 dydx[0] = 2*dydx[1] - dydx[2];
1886 dydx[nn-1] = 2*dydx[nn-2] - dydx[nn-3];
1889 static void parallel_print(int *data, int nThreads)
1891 /* This prints the donors on which each tread is currently working. */
1892 int i;
1894 fprintf(stderr, "\r");
1895 for (i = 0; i < nThreads; i++)
1897 fprintf(stderr, "%-7i", data[i]);
1901 static void normalizeACF(real *ct, real *gt, int nhb, int len)
1903 real ct_fac, gt_fac = 0;
1904 int i;
1906 /* Xu and Berne use the same normalization constant */
1908 ct_fac = 1.0/ct[0];
1909 if (nhb != 0)
1911 gt_fac = 1.0/nhb;
1914 printf("Normalization for c(t) = %g for gh(t) = %g\n", ct_fac, gt_fac);
1915 for (i = 0; i < len; i++)
1917 ct[i] *= ct_fac;
1918 if (gt != NULL)
1920 gt[i] *= gt_fac;
1925 static void do_hbac(const char *fn, t_hbdata *hb,
1926 int nDump, gmx_bool bMerge, gmx_bool bContact, real fit_start,
1927 real temp, gmx_bool R2, const gmx_output_env_t *oenv,
1928 int nThreads)
1930 FILE *fp;
1931 int i, j, k, m, ihb, idist, n2, nn;
1933 const char *legLuzar[] = {
1934 "Ac\\sfin sys\\v{}\\z{}(t)",
1935 "Ac(t)",
1936 "Cc\\scontact,hb\\v{}\\z{}(t)",
1937 "-dAc\\sfs\\v{}\\z{}/dt"
1939 gmx_bool bNorm = FALSE, bOMP = FALSE;
1940 double nhb = 0;
1941 real *rhbex = NULL, *ht, *gt, *ght, *dght, *kt;
1942 real *ct, tail, tail2, dtail, *cct;
1943 const real tol = 1e-3;
1944 int nframes = hb->nframes;
1945 unsigned int **h = NULL, **g = NULL;
1946 int nh, nhbonds, nhydro;
1947 t_hbond *hbh;
1948 int acType;
1949 int *dondata = NULL;
1951 enum {
1952 AC_NONE, AC_NN, AC_GEM, AC_LUZAR
1955 #ifdef GMX_OPENMP
1956 bOMP = TRUE;
1957 #else
1958 bOMP = FALSE;
1959 #endif
1961 printf("Doing autocorrelation ");
1963 acType = AC_LUZAR;
1964 printf("according to the theory of Luzar and Chandler.\n");
1965 fflush(stdout);
1967 /* build hbexist matrix in reals for autocorr */
1968 /* Allocate memory for computing ACF (rhbex) and aggregating the ACF (ct) */
1969 n2 = 1;
1970 while (n2 < nframes)
1972 n2 *= 2;
1975 nn = nframes/2;
1977 if (acType != AC_NN || bOMP)
1979 snew(h, hb->maxhydro);
1980 snew(g, hb->maxhydro);
1983 /* Dump hbonds for debugging */
1984 dump_ac(hb, bMerge || bContact, nDump);
1986 /* Total number of hbonds analyzed here */
1987 nhbonds = 0;
1989 if (acType != AC_LUZAR && bOMP)
1991 nThreads = std::min((nThreads <= 0) ? INT_MAX : nThreads, gmx_omp_get_max_threads());
1993 gmx_omp_set_num_threads(nThreads);
1994 snew(dondata, nThreads);
1995 for (i = 0; i < nThreads; i++)
1997 dondata[i] = -1;
1999 printf("ACF calculations parallelized with OpenMP using %i threads.\n"
2000 "Expect close to linear scaling over this donor-loop.\n", nThreads);
2001 fflush(stdout);
2002 fprintf(stderr, "Donors: [thread no]\n");
2004 char tmpstr[7];
2005 for (i = 0; i < nThreads; i++)
2007 snprintf(tmpstr, 7, "[%i]", i);
2008 fprintf(stderr, "%-7s", tmpstr);
2011 fprintf(stderr, "\n");
2015 /* Build the ACF */
2016 snew(rhbex, 2*n2);
2017 snew(ct, 2*n2);
2018 snew(gt, 2*n2);
2019 snew(ht, 2*n2);
2020 snew(ght, 2*n2);
2021 snew(dght, 2*n2);
2023 snew(kt, nn);
2024 snew(cct, nn);
2026 for (i = 0; (i < hb->d.nrd); i++)
2028 for (k = 0; (k < hb->a.nra); k++)
2030 nhydro = 0;
2031 hbh = hb->hbmap[i][k];
2033 if (hbh)
2035 if (bMerge || bContact)
2037 if (ISHB(hbh->history[0]))
2039 h[0] = hbh->h[0];
2040 g[0] = hbh->g[0];
2041 nhydro = 1;
2044 else
2046 for (m = 0; (m < hb->maxhydro); m++)
2048 if (bContact ? ISDIST(hbh->history[m]) : ISHB(hbh->history[m]))
2050 g[nhydro] = hbh->g[m];
2051 h[nhydro] = hbh->h[m];
2052 nhydro++;
2057 int nf = hbh->nframes;
2058 for (nh = 0; (nh < nhydro); nh++)
2060 int nrint = bContact ? hb->nrdist : hb->nrhb;
2061 if ((((nhbonds+1) % 10) == 0) || (nhbonds+1 == nrint))
2063 fprintf(stderr, "\rACF %d/%d", nhbonds+1, nrint);
2065 nhbonds++;
2066 for (j = 0; (j < nframes); j++)
2068 if (j <= nf)
2070 ihb = is_hb(h[nh], j);
2071 idist = is_hb(g[nh], j);
2073 else
2075 ihb = idist = 0;
2077 rhbex[j] = ihb;
2078 /* For contacts: if a second cut-off is provided, use it,
2079 * otherwise use g(t) = 1-h(t) */
2080 if (!R2 && bContact)
2082 gt[j] = 1-ihb;
2084 else
2086 gt[j] = idist*(1-ihb);
2088 ht[j] = rhbex[j];
2089 nhb += ihb;
2092 /* The autocorrelation function is normalized after summation only */
2093 low_do_autocorr(NULL, oenv, NULL, nframes, 1, -1, &rhbex, hb->time[1]-hb->time[0],
2094 eacNormal, 1, FALSE, bNorm, FALSE, 0, -1, 0);
2096 /* Cross correlation analysis for thermodynamics */
2097 for (j = nframes; (j < n2); j++)
2099 ht[j] = 0;
2100 gt[j] = 0;
2103 cross_corr(n2, ht, gt, dght);
2105 for (j = 0; (j < nn); j++)
2107 ct[j] += rhbex[j];
2108 ght[j] += dght[j];
2114 fprintf(stderr, "\n");
2115 sfree(h);
2116 sfree(g);
2117 normalizeACF(ct, ght, static_cast<int>(nhb), nn);
2119 /* Determine tail value for statistics */
2120 tail = 0;
2121 tail2 = 0;
2122 for (j = nn/2; (j < nn); j++)
2124 tail += ct[j];
2125 tail2 += ct[j]*ct[j];
2127 tail /= (nn - nn/2);
2128 tail2 /= (nn - nn/2);
2129 dtail = std::sqrt(tail2-tail*tail);
2131 /* Check whether the ACF is long enough */
2132 if (dtail > tol)
2134 printf("\nWARNING: Correlation function is probably not long enough\n"
2135 "because the standard deviation in the tail of C(t) > %g\n"
2136 "Tail value (average C(t) over second half of acf): %g +/- %g\n",
2137 tol, tail, dtail);
2139 for (j = 0; (j < nn); j++)
2141 cct[j] = ct[j];
2142 ct[j] = (cct[j]-tail)/(1-tail);
2144 /* Compute negative derivative k(t) = -dc(t)/dt */
2145 compute_derivative(nn, hb->time, ct, kt);
2146 for (j = 0; (j < nn); j++)
2148 kt[j] = -kt[j];
2152 if (bContact)
2154 fp = xvgropen(fn, "Contact Autocorrelation", output_env_get_xvgr_tlabel(oenv), "C(t)", oenv);
2156 else
2158 fp = xvgropen(fn, "Hydrogen Bond Autocorrelation", output_env_get_xvgr_tlabel(oenv), "C(t)", oenv);
2160 xvgr_legend(fp, asize(legLuzar), legLuzar, oenv);
2163 for (j = 0; (j < nn); j++)
2165 fprintf(fp, "%10g %10g %10g %10g %10g\n",
2166 hb->time[j]-hb->time[0], ct[j], cct[j], ght[j], kt[j]);
2168 xvgrclose(fp);
2170 analyse_corr(nn, hb->time, ct, ght, kt, NULL, NULL, NULL,
2171 fit_start, temp);
2173 do_view(oenv, fn, NULL);
2174 sfree(rhbex);
2175 sfree(ct);
2176 sfree(gt);
2177 sfree(ht);
2178 sfree(ght);
2179 sfree(dght);
2180 sfree(cct);
2181 sfree(kt);
2184 static void init_hbframe(t_hbdata *hb, int nframes, real t)
2186 int i;
2188 hb->time[nframes] = t;
2189 hb->nhb[nframes] = 0;
2190 hb->ndist[nframes] = 0;
2191 for (i = 0; (i < max_hx); i++)
2193 hb->nhx[nframes][i] = 0;
2197 static FILE *open_donor_properties_file(const char *fn,
2198 t_hbdata *hb,
2199 const gmx_output_env_t *oenv)
2201 FILE *fp = NULL;
2202 const char *leg[] = { "Nbound", "Nfree" };
2204 if (!fn || !hb)
2206 return NULL;
2209 fp = xvgropen(fn, "Donor properties", output_env_get_xvgr_tlabel(oenv), "Number", oenv);
2210 xvgr_legend(fp, asize(leg), leg, oenv);
2212 return fp;
2215 static void analyse_donor_properties(FILE *fp, t_hbdata *hb, int nframes, real t)
2217 int i, j, k, nbound, nb, nhtot;
2219 if (!fp || !hb)
2221 return;
2223 nbound = 0;
2224 nhtot = 0;
2225 for (i = 0; (i < hb->d.nrd); i++)
2227 for (k = 0; (k < hb->d.nhydro[i]); k++)
2229 nb = 0;
2230 nhtot++;
2231 for (j = 0; (j < hb->a.nra) && (nb == 0); j++)
2233 if (hb->hbmap[i][j] && hb->hbmap[i][j]->h[k] &&
2234 is_hb(hb->hbmap[i][j]->h[k], nframes))
2236 nb = 1;
2239 nbound += nb;
2242 fprintf(fp, "%10.3e %6d %6d\n", t, nbound, nhtot-nbound);
2245 static void dump_hbmap(t_hbdata *hb,
2246 int nfile, t_filenm fnm[], gmx_bool bTwo,
2247 gmx_bool bContact, int isize[], int *index[], char *grpnames[],
2248 t_atoms *atoms)
2250 FILE *fp, *fplog;
2251 int ddd, hhh, aaa, i, j, k, m, grp;
2252 char ds[32], hs[32], as[32];
2253 gmx_bool first;
2255 fp = opt2FILE("-hbn", nfile, fnm, "w");
2256 if (opt2bSet("-g", nfile, fnm))
2258 fplog = gmx_ffopen(opt2fn("-g", nfile, fnm), "w");
2259 fprintf(fplog, "# %10s %12s %12s\n", "Donor", "Hydrogen", "Acceptor");
2261 else
2263 fplog = NULL;
2265 for (grp = gr0; grp <= (bTwo ? gr1 : gr0); grp++)
2267 fprintf(fp, "[ %s ]", grpnames[grp]);
2268 for (i = 0; i < isize[grp]; i++)
2270 fprintf(fp, (i%15) ? " " : "\n");
2271 fprintf(fp, " %4d", index[grp][i]+1);
2273 fprintf(fp, "\n");
2275 if (!bContact)
2277 fprintf(fp, "[ donors_hydrogens_%s ]\n", grpnames[grp]);
2278 for (i = 0; (i < hb->d.nrd); i++)
2280 if (hb->d.grp[i] == grp)
2282 for (j = 0; (j < hb->d.nhydro[i]); j++)
2284 fprintf(fp, " %4d %4d", hb->d.don[i]+1,
2285 hb->d.hydro[i][j]+1);
2287 fprintf(fp, "\n");
2290 first = TRUE;
2291 fprintf(fp, "[ acceptors_%s ]", grpnames[grp]);
2292 for (i = 0; (i < hb->a.nra); i++)
2294 if (hb->a.grp[i] == grp)
2296 fprintf(fp, (i%15 && !first) ? " " : "\n");
2297 fprintf(fp, " %4d", hb->a.acc[i]+1);
2298 first = FALSE;
2301 fprintf(fp, "\n");
2304 if (bTwo)
2306 fprintf(fp, bContact ? "[ contacts_%s-%s ]\n" :
2307 "[ hbonds_%s-%s ]\n", grpnames[0], grpnames[1]);
2309 else
2311 fprintf(fp, bContact ? "[ contacts_%s ]" : "[ hbonds_%s ]\n", grpnames[0]);
2314 for (i = 0; (i < hb->d.nrd); i++)
2316 ddd = hb->d.don[i];
2317 for (k = 0; (k < hb->a.nra); k++)
2319 aaa = hb->a.acc[k];
2320 for (m = 0; (m < hb->d.nhydro[i]); m++)
2322 if (hb->hbmap[i][k] && ISHB(hb->hbmap[i][k]->history[m]))
2324 sprintf(ds, "%s", mkatomname(atoms, ddd));
2325 sprintf(as, "%s", mkatomname(atoms, aaa));
2326 if (bContact)
2328 fprintf(fp, " %6d %6d\n", ddd+1, aaa+1);
2329 if (fplog)
2331 fprintf(fplog, "%12s %12s\n", ds, as);
2334 else
2336 hhh = hb->d.hydro[i][m];
2337 sprintf(hs, "%s", mkatomname(atoms, hhh));
2338 fprintf(fp, " %6d %6d %6d\n", ddd+1, hhh+1, aaa+1);
2339 if (fplog)
2341 fprintf(fplog, "%12s %12s %12s\n", ds, hs, as);
2348 gmx_ffclose(fp);
2349 if (fplog)
2351 gmx_ffclose(fplog);
2355 /* sync_hbdata() updates the parallel t_hbdata p_hb using hb as template.
2356 * It mimics add_frames() and init_frame() to some extent. */
2357 static void sync_hbdata(t_hbdata *p_hb, int nframes)
2359 if (nframes >= p_hb->max_frames)
2361 p_hb->max_frames += 4096;
2362 srenew(p_hb->nhb, p_hb->max_frames);
2363 srenew(p_hb->ndist, p_hb->max_frames);
2364 srenew(p_hb->n_bound, p_hb->max_frames);
2365 srenew(p_hb->nhx, p_hb->max_frames);
2366 if (p_hb->bDAnr)
2368 srenew(p_hb->danr, p_hb->max_frames);
2370 std::memset(&(p_hb->nhb[nframes]), 0, sizeof(int) * (p_hb->max_frames-nframes));
2371 std::memset(&(p_hb->ndist[nframes]), 0, sizeof(int) * (p_hb->max_frames-nframes));
2372 p_hb->nhb[nframes] = 0;
2373 p_hb->ndist[nframes] = 0;
2376 p_hb->nframes = nframes;
2378 std::memset(&(p_hb->nhx[nframes]), 0, sizeof(int)*max_hx); /* zero the helix count for this frame */
2381 int gmx_hbond(int argc, char *argv[])
2383 const char *desc[] = {
2384 "[THISMODULE] computes and analyzes hydrogen bonds. Hydrogen bonds are",
2385 "determined based on cutoffs for the angle Hydrogen - Donor - Acceptor",
2386 "(zero is extended) and the distance Donor - Acceptor",
2387 "(or Hydrogen - Acceptor using [TT]-noda[tt]).",
2388 "OH and NH groups are regarded as donors, O is an acceptor always,",
2389 "N is an acceptor by default, but this can be switched using",
2390 "[TT]-nitacc[tt]. Dummy hydrogen atoms are assumed to be connected",
2391 "to the first preceding non-hydrogen atom.[PAR]",
2393 "You need to specify two groups for analysis, which must be either",
2394 "identical or non-overlapping. All hydrogen bonds between the two",
2395 "groups are analyzed.[PAR]",
2397 "If you set [TT]-shell[tt], you will be asked for an additional index group",
2398 "which should contain exactly one atom. In this case, only hydrogen",
2399 "bonds between atoms within the shell distance from the one atom are",
2400 "considered.[PAR]",
2402 "With option -ac, rate constants for hydrogen bonding can be derived with the model of Luzar and Chandler",
2403 "(Nature 394, 1996; J. Chem. Phys. 113:23, 2000) or that of Markovitz and Agmon (J. Chem. Phys 129, 2008).",
2404 "If contact kinetics are analyzed by using the -contact option, then",
2405 "n(t) can be defined as either all pairs that are not within contact distance r at time t",
2406 "(corresponding to leaving the -r2 option at the default value 0) or all pairs that",
2407 "are within distance r2 (corresponding to setting a second cut-off value with option -r2).",
2408 "See mentioned literature for more details and definitions."
2409 "[PAR]",
2411 /* "It is also possible to analyse specific hydrogen bonds with",
2412 "[TT]-sel[tt]. This index file must contain a group of atom triplets",
2413 "Donor Hydrogen Acceptor, in the following way::",
2415 "[ selected ]",
2416 " 20 21 24",
2417 " 25 26 29",
2418 " 1 3 6",
2420 "Note that the triplets need not be on separate lines.",
2421 "Each atom triplet specifies a hydrogen bond to be analyzed,",
2422 "note also that no check is made for the types of atoms.[PAR]",
2425 "[BB]Output:[bb]",
2427 " * [TT]-num[tt]: number of hydrogen bonds as a function of time.",
2428 " * [TT]-ac[tt]: average over all autocorrelations of the existence",
2429 " functions (either 0 or 1) of all hydrogen bonds.",
2430 " * [TT]-dist[tt]: distance distribution of all hydrogen bonds.",
2431 " * [TT]-ang[tt]: angle distribution of all hydrogen bonds.",
2432 " * [TT]-hx[tt]: the number of n-n+i hydrogen bonds as a function of time",
2433 " where n and n+i stand for residue numbers and i ranges from 0 to 6.",
2434 " This includes the n-n+3, n-n+4 and n-n+5 hydrogen bonds associated",
2435 " with helices in proteins.",
2436 " * [TT]-hbn[tt]: all selected groups, donors, hydrogens and acceptors",
2437 " for selected groups, all hydrogen bonded atoms from all groups and",
2438 " all solvent atoms involved in insertion.",
2439 " * [TT]-hbm[tt]: existence matrix for all hydrogen bonds over all",
2440 " frames, this also contains information on solvent insertion",
2441 " into hydrogen bonds. Ordering is identical to that in [TT]-hbn[tt]",
2442 " index file.",
2443 " * [TT]-dan[tt]: write out the number of donors and acceptors analyzed for",
2444 " each timeframe. This is especially useful when using [TT]-shell[tt].",
2445 " * [TT]-nhbdist[tt]: compute the number of HBonds per hydrogen in order to",
2446 " compare results to Raman Spectroscopy.",
2448 "Note: options [TT]-ac[tt], [TT]-life[tt], [TT]-hbn[tt] and [TT]-hbm[tt]",
2449 "require an amount of memory proportional to the total numbers of donors",
2450 "times the total number of acceptors in the selected group(s)."
2453 static real acut = 30, abin = 1, rcut = 0.35, r2cut = 0, rbin = 0.005, rshell = -1;
2454 static real maxnhb = 0, fit_start = 1, fit_end = 60, temp = 298.15;
2455 static gmx_bool bNitAcc = TRUE, bDA = TRUE, bMerge = TRUE;
2456 static int nDump = 0;
2457 static int nThreads = 0;
2459 static gmx_bool bContact = FALSE;
2461 /* options */
2462 t_pargs pa [] = {
2463 { "-a", FALSE, etREAL, {&acut},
2464 "Cutoff angle (degrees, Hydrogen - Donor - Acceptor)" },
2465 { "-r", FALSE, etREAL, {&rcut},
2466 "Cutoff radius (nm, X - Acceptor, see next option)" },
2467 { "-da", FALSE, etBOOL, {&bDA},
2468 "Use distance Donor-Acceptor (if TRUE) or Hydrogen-Acceptor (FALSE)" },
2469 { "-r2", FALSE, etREAL, {&r2cut},
2470 "Second cutoff radius. Mainly useful with [TT]-contact[tt] and [TT]-ac[tt]"},
2471 { "-abin", FALSE, etREAL, {&abin},
2472 "Binwidth angle distribution (degrees)" },
2473 { "-rbin", FALSE, etREAL, {&rbin},
2474 "Binwidth distance distribution (nm)" },
2475 { "-nitacc", FALSE, etBOOL, {&bNitAcc},
2476 "Regard nitrogen atoms as acceptors" },
2477 { "-contact", FALSE, etBOOL, {&bContact},
2478 "Do not look for hydrogen bonds, but merely for contacts within the cut-off distance" },
2479 { "-shell", FALSE, etREAL, {&rshell},
2480 "when > 0, only calculate hydrogen bonds within # nm shell around "
2481 "one particle" },
2482 { "-fitstart", FALSE, etREAL, {&fit_start},
2483 "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]" },
2484 { "-fitend", FALSE, etREAL, {&fit_end},
2485 "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])" },
2486 { "-temp", FALSE, etREAL, {&temp},
2487 "Temperature (K) for computing the Gibbs energy corresponding to HB breaking and reforming" },
2488 { "-dump", FALSE, etINT, {&nDump},
2489 "Dump the first N hydrogen bond ACFs in a single [REF].xvg[ref] file for debugging" },
2490 { "-max_hb", FALSE, etREAL, {&maxnhb},
2491 "Theoretical maximum number of hydrogen bonds used for normalizing HB autocorrelation function. Can be useful in case the program estimates it wrongly" },
2492 { "-merge", FALSE, etBOOL, {&bMerge},
2493 "H-bonds between the same donor and acceptor, but with different hydrogen are treated as a single H-bond. Mainly important for the ACF." },
2494 #ifdef GMX_OPENMP
2495 { "-nthreads", FALSE, etINT, {&nThreads},
2496 "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)"},
2497 #endif
2499 const char *bugs[] = {
2500 "The option [TT]-sel[tt] that used to work on selected hbonds is out of order, and therefore not available for the time being."
2502 t_filenm fnm[] = {
2503 { efTRX, "-f", NULL, ffREAD },
2504 { efTPR, NULL, NULL, ffREAD },
2505 { efNDX, NULL, NULL, ffOPTRD },
2506 /* { efNDX, "-sel", "select", ffOPTRD },*/
2507 { efXVG, "-num", "hbnum", ffWRITE },
2508 { efLOG, "-g", "hbond", ffOPTWR },
2509 { efXVG, "-ac", "hbac", ffOPTWR },
2510 { efXVG, "-dist", "hbdist", ffOPTWR },
2511 { efXVG, "-ang", "hbang", ffOPTWR },
2512 { efXVG, "-hx", "hbhelix", ffOPTWR },
2513 { efNDX, "-hbn", "hbond", ffOPTWR },
2514 { efXPM, "-hbm", "hbmap", ffOPTWR },
2515 { efXVG, "-don", "donor", ffOPTWR },
2516 { efXVG, "-dan", "danum", ffOPTWR },
2517 { efXVG, "-life", "hblife", ffOPTWR },
2518 { efXVG, "-nhbdist", "nhbdist", ffOPTWR }
2521 #define NFILE asize(fnm)
2523 char hbmap [HB_NR] = { ' ', 'o', '-', '*' };
2524 const char *hbdesc[HB_NR] = { "None", "Present", "Inserted", "Present & Inserted" };
2525 t_rgb hbrgb [HB_NR] = { {1, 1, 1}, {1, 0, 0}, {0, 0, 1}, {1, 0, 1} };
2527 t_trxstatus *status;
2528 int trrStatus = 1;
2529 t_topology top;
2530 t_inputrec ir;
2531 t_pargs *ppa;
2532 int npargs, natoms, nframes = 0, shatom;
2533 int *isize;
2534 char **grpnames;
2535 atom_id **index;
2536 rvec *x, hbox;
2537 matrix box;
2538 real t, ccut, dist = 0.0, ang = 0.0;
2539 double max_nhb, aver_nhb, aver_dist;
2540 int h = 0, i = 0, j, k = 0, ogrp, nsel;
2541 int xi, yi, zi, ai;
2542 int xj, yj, zj, aj, xjj, yjj, zjj;
2543 gmx_bool bSelected, bHBmap, bStop, bTwo, bBox, bTric;
2544 int *adist, *rdist;
2545 int grp, nabin, nrbin, resdist, ihb;
2546 char **leg;
2547 t_hbdata *hb;
2548 FILE *fp, *fpnhb = NULL, *donor_properties = NULL;
2549 t_gridcell ***grid;
2550 t_ncell *icell, *jcell;
2551 ivec ngrid;
2552 unsigned char *datable;
2553 gmx_output_env_t *oenv;
2554 int ii, hh, actual_nThreads;
2555 int threadNr = 0;
2556 gmx_bool bParallel;
2557 gmx_bool bEdge_yjj, bEdge_xjj, bOMP;
2559 t_hbdata **p_hb = NULL; /* one per thread, then merge after the frame loop */
2560 int **p_adist = NULL, **p_rdist = NULL; /* a histogram for each thread. */
2562 #ifdef GMX_OPENMP
2563 bOMP = TRUE;
2564 #else
2565 bOMP = FALSE;
2566 #endif
2568 npargs = asize(pa);
2569 ppa = add_acf_pargs(&npargs, pa);
2571 if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT, NFILE, fnm, npargs,
2572 ppa, asize(desc), desc, asize(bugs), bugs, &oenv))
2574 return 0;
2577 /* process input */
2578 bSelected = FALSE;
2579 ccut = std::cos(acut*DEG2RAD);
2581 if (bContact)
2583 if (bSelected)
2585 gmx_fatal(FARGS, "Can not analyze selected contacts.");
2587 if (!bDA)
2589 gmx_fatal(FARGS, "Can not analyze contact between H and A: turn off -noda");
2593 /* Initiate main data structure! */
2594 bHBmap = (opt2bSet("-ac", NFILE, fnm) ||
2595 opt2bSet("-life", NFILE, fnm) ||
2596 opt2bSet("-hbn", NFILE, fnm) ||
2597 opt2bSet("-hbm", NFILE, fnm));
2599 if (opt2bSet("-nhbdist", NFILE, fnm))
2601 const char *leg[MAXHH+1] = { "0 HBs", "1 HB", "2 HBs", "3 HBs", "Total" };
2602 fpnhb = xvgropen(opt2fn("-nhbdist", NFILE, fnm),
2603 "Number of donor-H with N HBs", output_env_get_xvgr_tlabel(oenv), "N", oenv);
2604 xvgr_legend(fpnhb, asize(leg), leg, oenv);
2607 hb = mk_hbdata(bHBmap, opt2bSet("-dan", NFILE, fnm), bMerge || bContact);
2609 /* get topology */
2610 read_tpx_top(ftp2fn(efTPR, NFILE, fnm), &ir, box, &natoms, NULL, NULL, &top);
2612 snew(grpnames, grNR);
2613 snew(index, grNR);
2614 snew(isize, grNR);
2615 /* Make Donor-Acceptor table */
2616 snew(datable, top.atoms.nr);
2617 gen_datable(index[0], isize[0], datable, top.atoms.nr);
2619 if (bSelected)
2621 /* analyze selected hydrogen bonds */
2622 printf("Select group with selected atoms:\n");
2623 get_index(&(top.atoms), opt2fn("-sel", NFILE, fnm),
2624 1, &nsel, index, grpnames);
2625 if (nsel % 3)
2627 gmx_fatal(FARGS, "Number of atoms in group '%s' not a multiple of 3\n"
2628 "and therefore cannot contain triplets of "
2629 "Donor-Hydrogen-Acceptor", grpnames[0]);
2631 bTwo = FALSE;
2633 for (i = 0; (i < nsel); i += 3)
2635 int dd = index[0][i];
2636 int aa = index[0][i+2];
2637 /* int */ hh = index[0][i+1];
2638 add_dh (&hb->d, dd, hh, i, datable);
2639 add_acc(&hb->a, aa, i);
2640 /* Should this be here ? */
2641 snew(hb->d.dptr, top.atoms.nr);
2642 snew(hb->a.aptr, top.atoms.nr);
2643 add_hbond(hb, dd, aa, hh, gr0, gr0, 0, bMerge, 0, bContact);
2645 printf("Analyzing %d selected hydrogen bonds from '%s'\n",
2646 isize[0], grpnames[0]);
2648 else
2650 /* analyze all hydrogen bonds: get group(s) */
2651 printf("Specify 2 groups to analyze:\n");
2652 get_index(&(top.atoms), ftp2fn_null(efNDX, NFILE, fnm),
2653 2, isize, index, grpnames);
2655 /* check if we have two identical or two non-overlapping groups */
2656 bTwo = isize[0] != isize[1];
2657 for (i = 0; (i < isize[0]) && !bTwo; i++)
2659 bTwo = index[0][i] != index[1][i];
2661 if (bTwo)
2663 printf("Checking for overlap in atoms between %s and %s\n",
2664 grpnames[0], grpnames[1]);
2665 for (i = 0; i < isize[1]; i++)
2667 if (ISINGRP(datable[index[1][i]]))
2669 gmx_fatal(FARGS, "Partial overlap between groups '%s' and '%s'",
2670 grpnames[0], grpnames[1]);
2674 printf("Checking for overlap in atoms between %s and %s\n",
2675 grpnames[0],grpnames[1]);
2676 for (i=0; i<isize[0]; i++)
2677 for (j=0; j<isize[1]; j++)
2678 if (index[0][i] == index[1][j])
2679 gmx_fatal(FARGS,"Partial overlap between groups '%s' and '%s'",
2680 grpnames[0],grpnames[1]);
2683 if (bTwo)
2685 printf("Calculating %s "
2686 "between %s (%d atoms) and %s (%d atoms)\n",
2687 bContact ? "contacts" : "hydrogen bonds",
2688 grpnames[0], isize[0], grpnames[1], isize[1]);
2690 else
2692 fprintf(stderr, "Calculating %s in %s (%d atoms)\n",
2693 bContact ? "contacts" : "hydrogen bonds", grpnames[0], isize[0]);
2696 sfree(datable);
2698 /* search donors and acceptors in groups */
2699 snew(datable, top.atoms.nr);
2700 for (i = 0; (i < grNR); i++)
2702 if ( ((i == gr0) && !bSelected ) ||
2703 ((i == gr1) && bTwo ))
2705 gen_datable(index[i], isize[i], datable, top.atoms.nr);
2706 if (bContact)
2708 search_acceptors(&top, isize[i], index[i], &hb->a, i,
2709 bNitAcc, TRUE, (bTwo && (i == gr0)) || !bTwo, datable);
2710 search_donors (&top, isize[i], index[i], &hb->d, i,
2711 TRUE, (bTwo && (i == gr1)) || !bTwo, datable);
2713 else
2715 search_acceptors(&top, isize[i], index[i], &hb->a, i, bNitAcc, FALSE, TRUE, datable);
2716 search_donors (&top, isize[i], index[i], &hb->d, i, FALSE, TRUE, datable);
2718 if (bTwo)
2720 clear_datable_grp(datable, top.atoms.nr);
2724 sfree(datable);
2725 printf("Found %d donors and %d acceptors\n", hb->d.nrd, hb->a.nra);
2726 /*if (bSelected)
2727 snew(donors[gr0D], dons[gr0D].nrd);*/
2729 donor_properties = open_donor_properties_file(opt2fn_null("-don", NFILE, fnm), hb, oenv);
2731 if (bHBmap)
2733 printf("Making hbmap structure...");
2734 /* Generate hbond data structure */
2735 mk_hbmap(hb);
2736 printf("done.\n");
2739 /* check input */
2740 bStop = FALSE;
2741 if (hb->d.nrd + hb->a.nra == 0)
2743 printf("No Donors or Acceptors found\n");
2744 bStop = TRUE;
2746 if (!bStop)
2748 if (hb->d.nrd == 0)
2750 printf("No Donors found\n");
2751 bStop = TRUE;
2753 if (hb->a.nra == 0)
2755 printf("No Acceptors found\n");
2756 bStop = TRUE;
2759 if (bStop)
2761 gmx_fatal(FARGS, "Nothing to be done");
2764 shatom = 0;
2765 if (rshell > 0)
2767 int shisz;
2768 atom_id *shidx;
2769 char *shgrpnm;
2770 /* get index group with atom for shell */
2773 printf("Select atom for shell (1 atom):\n");
2774 get_index(&(top.atoms), ftp2fn_null(efNDX, NFILE, fnm),
2775 1, &shisz, &shidx, &shgrpnm);
2776 if (shisz != 1)
2778 printf("group contains %d atoms, should be 1 (one)\n", shisz);
2781 while (shisz != 1);
2782 shatom = shidx[0];
2783 printf("Will calculate hydrogen bonds within a shell "
2784 "of %g nm around atom %i\n", rshell, shatom+1);
2787 /* Analyze trajectory */
2788 natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box);
2789 if (natoms > top.atoms.nr)
2791 gmx_fatal(FARGS, "Topology (%d atoms) does not match trajectory (%d atoms)",
2792 top.atoms.nr, natoms);
2795 bBox = ir.ePBC != epbcNONE;
2796 grid = init_grid(bBox, box, (rcut > r2cut) ? rcut : r2cut, ngrid);
2797 nabin = static_cast<int>(acut/abin);
2798 nrbin = static_cast<int>(rcut/rbin);
2799 snew(adist, nabin+1);
2800 snew(rdist, nrbin+1);
2802 #ifndef GMX_OPENMP
2803 #define __ADIST adist
2804 #define __RDIST rdist
2805 #define __HBDATA hb
2806 #else /* GMX_OPENMP ================================================== \
2807 * Set up the OpenMP stuff, |
2808 * like the number of threads and such |
2809 * Also start the parallel loop. |
2811 #define __ADIST p_adist[threadNr]
2812 #define __RDIST p_rdist[threadNr]
2813 #define __HBDATA p_hb[threadNr]
2814 #endif
2815 if (bOMP)
2817 bParallel = !bSelected;
2819 if (bParallel)
2821 actual_nThreads = std::min((nThreads <= 0) ? INT_MAX : nThreads, gmx_omp_get_max_threads());
2823 gmx_omp_set_num_threads(actual_nThreads);
2824 printf("Frame loop parallelized with OpenMP using %i threads.\n", actual_nThreads);
2825 fflush(stdout);
2827 else
2829 actual_nThreads = 1;
2832 snew(p_hb, actual_nThreads);
2833 snew(p_adist, actual_nThreads);
2834 snew(p_rdist, actual_nThreads);
2835 for (i = 0; i < actual_nThreads; i++)
2837 snew(p_hb[i], 1);
2838 snew(p_adist[i], nabin+1);
2839 snew(p_rdist[i], nrbin+1);
2841 p_hb[i]->max_frames = 0;
2842 p_hb[i]->nhb = NULL;
2843 p_hb[i]->ndist = NULL;
2844 p_hb[i]->n_bound = NULL;
2845 p_hb[i]->time = NULL;
2846 p_hb[i]->nhx = NULL;
2848 p_hb[i]->bHBmap = hb->bHBmap;
2849 p_hb[i]->bDAnr = hb->bDAnr;
2850 p_hb[i]->wordlen = hb->wordlen;
2851 p_hb[i]->nframes = hb->nframes;
2852 p_hb[i]->maxhydro = hb->maxhydro;
2853 p_hb[i]->danr = hb->danr;
2854 p_hb[i]->d = hb->d;
2855 p_hb[i]->a = hb->a;
2856 p_hb[i]->hbmap = hb->hbmap;
2857 p_hb[i]->time = hb->time; /* This may need re-syncing at every frame. */
2859 p_hb[i]->nrhb = 0;
2860 p_hb[i]->nrdist = 0;
2864 /* Make a thread pool here,
2865 * instead of forking anew at every frame. */
2867 #pragma omp parallel \
2868 firstprivate(i) \
2869 private(j, h, ii, hh, \
2870 xi, yi, zi, xj, yj, zj, threadNr, \
2871 dist, ang, icell, jcell, \
2872 grp, ogrp, ai, aj, xjj, yjj, zjj, \
2873 ihb, resdist, \
2874 k, bTric, \
2875 bEdge_xjj, bEdge_yjj) \
2876 default(shared)
2877 { /* Start of parallel region */
2878 threadNr = gmx_omp_get_thread_num();
2883 bTric = bBox && TRICLINIC(box);
2885 if (bOMP)
2889 sync_hbdata(p_hb[threadNr], nframes);
2891 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
2893 #pragma omp single
2897 build_grid(hb, x, x[shatom], bBox, box, hbox, (rcut > r2cut) ? rcut : r2cut,
2898 rshell, ngrid, grid);
2899 reset_nhbonds(&(hb->d));
2901 if (debug && bDebug)
2903 dump_grid(debug, ngrid, grid);
2906 add_frames(hb, nframes);
2907 init_hbframe(hb, nframes, output_env_conv_time(oenv, t));
2909 if (hb->bDAnr)
2911 count_da_grid(ngrid, grid, hb->danr[nframes]);
2914 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
2915 } /* omp single */
2917 if (bOMP)
2919 p_hb[threadNr]->time = hb->time; /* This pointer may have changed. */
2922 if (bSelected)
2925 #pragma omp single
2929 /* Do not parallelize this just yet. */
2930 /* int ii; */
2931 for (ii = 0; (ii < nsel); ii++)
2933 int dd = index[0][i];
2934 int aa = index[0][i+2];
2935 /* int */ hh = index[0][i+1];
2936 ihb = is_hbond(hb, ii, ii, dd, aa, rcut, r2cut, ccut, x, bBox, box,
2937 hbox, &dist, &ang, bDA, &h, bContact, bMerge);
2939 if (ihb)
2941 /* add to index if not already there */
2942 /* Add a hbond */
2943 add_hbond(hb, dd, aa, hh, ii, ii, nframes, bMerge, ihb, bContact);
2947 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
2948 } /* omp single */
2949 } /* if (bSelected) */
2950 else
2952 /* The outer grid loop will have to do for now. */
2953 #pragma omp for schedule(dynamic)
2954 for (xi = 0; xi < ngrid[XX]; xi++)
2958 for (yi = 0; (yi < ngrid[YY]); yi++)
2960 for (zi = 0; (zi < ngrid[ZZ]); zi++)
2963 /* loop over donor groups gr0 (always) and gr1 (if necessary) */
2964 for (grp = gr0; (grp <= (bTwo ? gr1 : gr0)); grp++)
2966 icell = &(grid[zi][yi][xi].d[grp]);
2968 if (bTwo)
2970 ogrp = 1-grp;
2972 else
2974 ogrp = grp;
2977 /* loop over all hydrogen atoms from group (grp)
2978 * in this gridcell (icell)
2980 for (ai = 0; (ai < icell->nr); ai++)
2982 i = icell->atoms[ai];
2984 /* loop over all adjacent gridcells (xj,yj,zj) */
2985 for (zjj = grid_loop_begin(ngrid[ZZ], zi, bTric, FALSE);
2986 zjj <= grid_loop_end(ngrid[ZZ], zi, bTric, FALSE);
2987 zjj++)
2989 zj = grid_mod(zjj, ngrid[ZZ]);
2990 bEdge_yjj = (zj == 0) || (zj == ngrid[ZZ] - 1);
2991 for (yjj = grid_loop_begin(ngrid[YY], yi, bTric, bEdge_yjj);
2992 yjj <= grid_loop_end(ngrid[YY], yi, bTric, bEdge_yjj);
2993 yjj++)
2995 yj = grid_mod(yjj, ngrid[YY]);
2996 bEdge_xjj =
2997 (yj == 0) || (yj == ngrid[YY] - 1) ||
2998 (zj == 0) || (zj == ngrid[ZZ] - 1);
2999 for (xjj = grid_loop_begin(ngrid[XX], xi, bTric, bEdge_xjj);
3000 xjj <= grid_loop_end(ngrid[XX], xi, bTric, bEdge_xjj);
3001 xjj++)
3003 xj = grid_mod(xjj, ngrid[XX]);
3004 jcell = &(grid[zj][yj][xj].a[ogrp]);
3005 /* loop over acceptor atoms from other group (ogrp)
3006 * in this adjacent gridcell (jcell)
3008 for (aj = 0; (aj < jcell->nr); aj++)
3010 j = jcell->atoms[aj];
3012 /* check if this once was a h-bond */
3013 ihb = is_hbond(__HBDATA, grp, ogrp, i, j, rcut, r2cut, ccut, x, bBox, box,
3014 hbox, &dist, &ang, bDA, &h, bContact, bMerge);
3016 if (ihb)
3018 /* add to index if not already there */
3019 /* Add a hbond */
3020 add_hbond(__HBDATA, i, j, h, grp, ogrp, nframes, bMerge, ihb, bContact);
3022 /* make angle and distance distributions */
3023 if (ihb == hbHB && !bContact)
3025 if (dist > rcut)
3027 gmx_fatal(FARGS, "distance is higher than what is allowed for an hbond: %f", dist);
3029 ang *= RAD2DEG;
3030 __ADIST[static_cast<int>( ang/abin)]++;
3031 __RDIST[static_cast<int>(dist/rbin)]++;
3032 if (!bTwo)
3034 if (donor_index(&hb->d, grp, i) == NOTSET)
3036 gmx_fatal(FARGS, "Invalid donor %d", i);
3038 if (acceptor_index(&hb->a, ogrp, j) == NOTSET)
3040 gmx_fatal(FARGS, "Invalid acceptor %d", j);
3042 resdist = std::abs(top.atoms.atom[i].resind-top.atoms.atom[j].resind);
3043 if (resdist >= max_hx)
3045 resdist = max_hx-1;
3047 __HBDATA->nhx[nframes][resdist]++;
3052 } /* for aj */
3053 } /* for xjj */
3054 } /* for yjj */
3055 } /* for zjj */
3056 } /* for ai */
3057 } /* for grp */
3058 } /* for xi,yi,zi */
3061 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
3063 } /* if (bSelected) {...} else */
3066 /* Better wait for all threads to finnish using x[] before updating it. */
3067 k = nframes;
3068 #pragma omp barrier
3069 #pragma omp critical
3073 /* Sum up histograms and counts from p_hb[] into hb */
3074 if (bOMP)
3076 hb->nhb[k] += p_hb[threadNr]->nhb[k];
3077 hb->ndist[k] += p_hb[threadNr]->ndist[k];
3078 for (j = 0; j < max_hx; j++)
3080 hb->nhx[k][j] += p_hb[threadNr]->nhx[k][j];
3084 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
3087 /* Here are a handful of single constructs
3088 * to share the workload a bit. The most
3089 * important one is of course the last one,
3090 * where there's a potential bottleneck in form
3091 * of slow I/O. */
3092 #pragma omp barrier
3093 #pragma omp single
3097 analyse_donor_properties(donor_properties, hb, k, t);
3099 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
3102 #pragma omp single
3106 if (fpnhb)
3108 do_nhb_dist(fpnhb, hb, t);
3111 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
3114 #pragma omp single
3118 trrStatus = (read_next_x(oenv, status, &t, x, box));
3119 nframes++;
3121 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
3124 #pragma omp barrier
3126 while (trrStatus);
3128 if (bOMP)
3130 #pragma omp critical
3132 hb->nrhb += p_hb[threadNr]->nrhb;
3133 hb->nrdist += p_hb[threadNr]->nrdist;
3136 /* Free parallel datastructures */
3137 sfree(p_hb[threadNr]->nhb);
3138 sfree(p_hb[threadNr]->ndist);
3139 sfree(p_hb[threadNr]->nhx);
3141 #pragma omp for
3142 for (i = 0; i < nabin; i++)
3146 for (j = 0; j < actual_nThreads; j++)
3149 adist[i] += p_adist[j][i];
3152 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
3154 #pragma omp for
3155 for (i = 0; i <= nrbin; i++)
3159 for (j = 0; j < actual_nThreads; j++)
3161 rdist[i] += p_rdist[j][i];
3164 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
3167 sfree(p_adist[threadNr]);
3168 sfree(p_rdist[threadNr]);
3170 } /* End of parallel region */
3171 if (bOMP)
3173 sfree(p_adist);
3174 sfree(p_rdist);
3177 if (nframes < 2 && (opt2bSet("-ac", NFILE, fnm) || opt2bSet("-life", NFILE, fnm)))
3179 gmx_fatal(FARGS, "Cannot calculate autocorrelation of life times with less than two frames");
3182 free_grid(ngrid, &grid);
3184 close_trj(status);
3186 if (donor_properties)
3188 xvgrclose(donor_properties);
3191 if (fpnhb)
3193 xvgrclose(fpnhb);
3196 /* Compute maximum possible number of different hbonds */
3197 if (maxnhb > 0)
3199 max_nhb = maxnhb;
3201 else
3203 max_nhb = 0.5*(hb->d.nrd*hb->a.nra);
3206 if (bHBmap)
3208 if (hb->nrhb == 0)
3210 printf("No %s found!!\n", bContact ? "contacts" : "hydrogen bonds");
3212 else
3214 printf("Found %d different %s in trajectory\n"
3215 "Found %d different atom-pairs within %s distance\n",
3216 hb->nrhb, bContact ? "contacts" : "hydrogen bonds",
3217 hb->nrdist, (r2cut > 0) ? "second cut-off" : "hydrogen bonding");
3219 if (bMerge)
3221 merge_hb(hb, bTwo, bContact);
3224 if (opt2bSet("-hbn", NFILE, fnm))
3226 dump_hbmap(hb, NFILE, fnm, bTwo, bContact, isize, index, grpnames, &top.atoms);
3229 /* Moved the call to merge_hb() to a line BEFORE dump_hbmap
3230 * to make the -hbn and -hmb output match eachother.
3231 * - Erik Marklund, May 30, 2006 */
3234 /* Print out number of hbonds and distances */
3235 aver_nhb = 0;
3236 aver_dist = 0;
3237 fp = xvgropen(opt2fn("-num", NFILE, fnm), bContact ? "Contacts" :
3238 "Hydrogen Bonds", output_env_get_xvgr_tlabel(oenv), "Number", oenv);
3239 snew(leg, 2);
3240 snew(leg[0], STRLEN);
3241 snew(leg[1], STRLEN);
3242 sprintf(leg[0], "%s", bContact ? "Contacts" : "Hydrogen bonds");
3243 sprintf(leg[1], "Pairs within %g nm", (r2cut > 0) ? r2cut : rcut);
3244 xvgr_legend(fp, 2, (const char**)leg, oenv);
3245 sfree(leg[1]);
3246 sfree(leg[0]);
3247 sfree(leg);
3248 for (i = 0; (i < nframes); i++)
3250 fprintf(fp, "%10g %10d %10d\n", hb->time[i], hb->nhb[i], hb->ndist[i]);
3251 aver_nhb += hb->nhb[i];
3252 aver_dist += hb->ndist[i];
3254 xvgrclose(fp);
3255 aver_nhb /= nframes;
3256 aver_dist /= nframes;
3257 /* Print HB distance distribution */
3258 if (opt2bSet("-dist", NFILE, fnm))
3260 int sum;
3262 sum = 0;
3263 for (i = 0; i < nrbin; i++)
3265 sum += rdist[i];
3268 fp = xvgropen(opt2fn("-dist", NFILE, fnm),
3269 "Hydrogen Bond Distribution",
3270 bDA ?
3271 "Donor - Acceptor Distance (nm)" :
3272 "Hydrogen - Acceptor Distance (nm)", "", oenv);
3273 for (i = 0; i < nrbin; i++)
3275 fprintf(fp, "%10g %10g\n", (i+0.5)*rbin, rdist[i]/(rbin*sum));
3277 xvgrclose(fp);
3280 /* Print HB angle distribution */
3281 if (opt2bSet("-ang", NFILE, fnm))
3283 long sum;
3285 sum = 0;
3286 for (i = 0; i < nabin; i++)
3288 sum += adist[i];
3291 fp = xvgropen(opt2fn("-ang", NFILE, fnm),
3292 "Hydrogen Bond Distribution",
3293 "Hydrogen - Donor - Acceptor Angle (\\SO\\N)", "", oenv);
3294 for (i = 0; i < nabin; i++)
3296 fprintf(fp, "%10g %10g\n", (i+0.5)*abin, adist[i]/(abin*sum));
3298 xvgrclose(fp);
3301 /* Print HB in alpha-helix */
3302 if (opt2bSet("-hx", NFILE, fnm))
3304 fp = xvgropen(opt2fn("-hx", NFILE, fnm),
3305 "Hydrogen Bonds", output_env_get_xvgr_tlabel(oenv), "Count", oenv);
3306 xvgr_legend(fp, NRHXTYPES, hxtypenames, oenv);
3307 for (i = 0; i < nframes; i++)
3309 fprintf(fp, "%10g", hb->time[i]);
3310 for (j = 0; j < max_hx; j++)
3312 fprintf(fp, " %6d", hb->nhx[i][j]);
3314 fprintf(fp, "\n");
3316 xvgrclose(fp);
3319 printf("Average number of %s per timeframe %.3f out of %g possible\n",
3320 bContact ? "contacts" : "hbonds",
3321 bContact ? aver_dist : aver_nhb, max_nhb);
3323 /* Do Autocorrelation etc. */
3324 if (hb->bHBmap)
3327 Added support for -contact in ac and hbm calculations below.
3328 - Erik Marklund, May 29, 2006
3330 if (opt2bSet("-ac", NFILE, fnm) || opt2bSet("-life", NFILE, fnm))
3332 please_cite(stdout, "Spoel2006b");
3334 if (opt2bSet("-ac", NFILE, fnm))
3336 do_hbac(opt2fn("-ac", NFILE, fnm), hb, nDump,
3337 bMerge, bContact, fit_start, temp, r2cut > 0, oenv,
3338 nThreads);
3340 if (opt2bSet("-life", NFILE, fnm))
3342 do_hblife(opt2fn("-life", NFILE, fnm), hb, bMerge, bContact, oenv);
3344 if (opt2bSet("-hbm", NFILE, fnm))
3346 t_matrix mat;
3347 int id, ia, hh, x, y;
3348 mat.flags = mat.y0 = 0;
3350 if ((nframes > 0) && (hb->nrhb > 0))
3352 mat.nx = nframes;
3353 mat.ny = hb->nrhb;
3355 snew(mat.matrix, mat.nx);
3356 for (x = 0; (x < mat.nx); x++)
3358 snew(mat.matrix[x], mat.ny);
3360 y = 0;
3361 for (id = 0; (id < hb->d.nrd); id++)
3363 for (ia = 0; (ia < hb->a.nra); ia++)
3365 for (hh = 0; (hh < hb->maxhydro); hh++)
3367 if (hb->hbmap[id][ia])
3369 if (ISHB(hb->hbmap[id][ia]->history[hh]))
3371 for (x = 0; (x <= hb->hbmap[id][ia]->nframes); x++)
3373 int nn0 = hb->hbmap[id][ia]->n0;
3374 range_check(y, 0, mat.ny);
3375 mat.matrix[x+nn0][y] = is_hb(hb->hbmap[id][ia]->h[hh], x);
3377 y++;
3383 mat.axis_x = hb->time;
3384 snew(mat.axis_y, mat.ny);
3385 for (j = 0; j < mat.ny; j++)
3387 mat.axis_y[j] = j;
3389 sprintf(mat.title, bContact ? "Contact Existence Map" :
3390 "Hydrogen Bond Existence Map");
3391 sprintf(mat.legend, bContact ? "Contacts" : "Hydrogen Bonds");
3392 sprintf(mat.label_x, "%s", output_env_get_xvgr_tlabel(oenv));
3393 sprintf(mat.label_y, bContact ? "Contact Index" : "Hydrogen Bond Index");
3394 mat.bDiscrete = TRUE;
3395 mat.nmap = 2;
3396 snew(mat.map, mat.nmap);
3397 for (i = 0; i < mat.nmap; i++)
3399 mat.map[i].code.c1 = hbmap[i];
3400 mat.map[i].desc = hbdesc[i];
3401 mat.map[i].rgb = hbrgb[i];
3403 fp = opt2FILE("-hbm", NFILE, fnm, "w");
3404 write_xpm_m(fp, mat);
3405 gmx_ffclose(fp);
3406 for (x = 0; x < mat.nx; x++)
3408 sfree(mat.matrix[x]);
3410 sfree(mat.axis_y);
3411 sfree(mat.matrix);
3412 sfree(mat.map);
3414 else
3416 fprintf(stderr, "No hydrogen bonds/contacts found. No hydrogen bond map will be printed.\n");
3421 if (hb->bDAnr)
3423 int i, j, nleg;
3424 char **legnames;
3425 char buf[STRLEN];
3427 #define USE_THIS_GROUP(j) ( (j == gr0) || (bTwo && (j == gr1)) )
3429 fp = xvgropen(opt2fn("-dan", NFILE, fnm),
3430 "Donors and Acceptors", output_env_get_xvgr_tlabel(oenv), "Count", oenv);
3431 nleg = (bTwo ? 2 : 1)*2;
3432 snew(legnames, nleg);
3433 i = 0;
3434 for (j = 0; j < grNR; j++)
3436 if (USE_THIS_GROUP(j) )
3438 sprintf(buf, "Donors %s", grpnames[j]);
3439 legnames[i++] = gmx_strdup(buf);
3440 sprintf(buf, "Acceptors %s", grpnames[j]);
3441 legnames[i++] = gmx_strdup(buf);
3444 if (i != nleg)
3446 gmx_incons("number of legend entries");
3448 xvgr_legend(fp, nleg, (const char**)legnames, oenv);
3449 for (i = 0; i < nframes; i++)
3451 fprintf(fp, "%10g", hb->time[i]);
3452 for (j = 0; (j < grNR); j++)
3454 if (USE_THIS_GROUP(j) )
3456 fprintf(fp, " %6d", hb->danr[i][j]);
3459 fprintf(fp, "\n");
3461 xvgrclose(fp);
3464 return 0;