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/geminate.h"
53 #include "gromacs/gmxana/gmx_ana.h"
54 #include "gromacs/legacyheaders/copyrite.h"
55 #include "gromacs/legacyheaders/macros.h"
56 #include "gromacs/legacyheaders/txtdump.h"
57 #include "gromacs/legacyheaders/viewit.h"
58 #include "gromacs/math/units.h"
59 #include "gromacs/math/vec.h"
60 #include "gromacs/pbcutil/pbc.h"
61 #include "gromacs/topology/index.h"
62 #include "gromacs/utility/cstringutil.h"
63 #include "gromacs/utility/fatalerror.h"
64 #include "gromacs/utility/futil.h"
65 #include "gromacs/utility/gmxomp.h"
66 #include "gromacs/utility/smalloc.h"
70 /*#define HAVE_NN_LOOPS*/
72 typedef short int t_E;
75 typedef int t_hx[max_hx];
76 #define NRHXTYPES max_hx
77 const char *hxtypenames[NRHXTYPES] =
78 {"n-n", "n-n+1", "n-n+2", "n-n+3", "n-n+4", "n-n+5", "n-n>6"};
82 #define MASTER_THREAD_ONLY(threadNr) ((threadNr) == 0)
84 #define MASTER_THREAD_ONLY(threadNr) ((threadNr) == (threadNr))
87 /* -----------------------------------------*/
93 hbNo, hbDist, hbHB, hbNR, hbR2
96 noDA, ACC, DON, DA, INGROUP
99 NN_NULL, NN_NONE, NN_BINARY, NN_1_over_r3, NN_dipole, NN_NR
102 static const char *grpnames[grNR] = {"0", "1", "I" };
104 static gmx_bool bDebug = FALSE;
109 #define HB_YESINS HB_YES|HB_INS
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)
131 typedef int t_icell[grNR];
132 typedef atom_id h_id[MAXHYDRO];
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 */
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
155 atom_id *acc; /* Atom numbers of the acceptors */
156 int *grp; /* Group index */
157 int *aptr; /* Map atom number to acceptor index */
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 */
170 /* Tune this to match memory requirements. It should be a signed integer type, e.g. signed char.*/
174 int len; /* The length of frame and p. */
175 int *frame; /* The frames at which transitio*/
180 /* Periodicity history. Used for the reversible geminate recombination. */
181 t_pShift **pHist; /* The periodicity of every hbond in t_hbdata->hbmap:
182 * pHist[d][a]. We can safely assume that the same
183 * periodic shift holds for all hydrogens of a da-pair.
185 * Nowadays it only stores TRANSITIONS, and not the shift at every frame.
186 * That saves a LOT of memory, an hopefully kills a mysterious bug where
187 * pHist gets contaminated. */
189 PSTYPE nper; /* The length of p2i */
190 ivec *p2i; /* Maps integer to periodic shift for a pair.*/
191 matrix P; /* Projection matrix to find the box shifts. */
192 int gemtype; /* enumerated type */
197 int *Etot; /* Total energy for each frame */
198 t_E ****E; /* Energy estimate for [d][a][h][frame-n0] */
202 gmx_bool bHBmap, bDAnr, bGem;
204 /* The following arrays are nframes long */
205 int nframes, max_frames, maxhydro;
211 /* These structures are initialized from the topology at start up */
214 /* This holds a matrix with all possible hydrogen bonds */
220 /* For parallelization reasons this will have to be a pointer.
221 * Otherwise discrepancies may arise between the periodicity data
222 * seen by different threads. */
226 static void clearPshift(t_pShift *pShift)
231 sfree(pShift->frame);
236 static void calcBoxProjection(matrix B, matrix P)
238 const int vp[] = {XX, YY, ZZ};
243 for (i = 0; i < 3; i++)
246 for (j = 0; j < 3; j++)
249 U[m][n] = i == j ? 1 : 0;
253 for (i = 0; i < 3; i++)
256 mvmul(M, U[m], P[m]);
261 static void calcBoxDistance(matrix P, rvec d, ivec ibd)
263 /* returns integer distance in box coordinates.
264 * P is the projection matrix from cartesian coordinates
265 * obtained with calcBoxProjection(). */
269 /* extend it by 0.5 in all directions since (int) rounds toward 0.*/
270 for (i = 0; i < 3; i++)
272 bd[i] = bd[i] + (bd[i] < 0 ? -0.5 : 0.5);
274 ibd[XX] = (int)bd[XX];
275 ibd[YY] = (int)bd[YY];
276 ibd[ZZ] = (int)bd[ZZ];
279 /* Changed argument 'bMerge' into 'oneHB' below,
280 * since -contact should cause maxhydro to be 1,
282 * - Erik Marklund May 29, 2006
285 static PSTYPE periodicIndex(ivec r, t_gemPeriod *per, gmx_bool daSwap)
287 /* Try to merge hbonds on the fly. That means that if the
288 * acceptor and donor are mergable, then:
289 * 1) store the hb-info so that acceptor id > donor id,
290 * 2) add the periodic shift in pairs, so that [-x,-y,-z] is
291 * stored in per.p2i[] whenever acceptor id < donor id.
292 * Note that [0,0,0] should already be the first element of per.p2i
293 * by the time this function is called. */
295 /* daSwap is TRUE if the donor and acceptor were swapped.
296 * If so, then the negative vector should be used. */
299 if (per->p2i == NULL || per->nper == 0)
301 gmx_fatal(FARGS, "'per' not initialized properly.");
303 for (i = 0; i < per->nper; i++)
305 if (r[XX] == per->p2i[i][XX] &&
306 r[YY] == per->p2i[i][YY] &&
307 r[ZZ] == per->p2i[i][ZZ])
312 /* Not found apparently. Add it to the list! */
313 /* printf("New shift found: %i,%i,%i\n",r[XX],r[YY],r[ZZ]); */
319 fprintf(stderr, "p2i not initialized. This shouldn't happen!\n");
324 srenew(per->p2i, per->nper+2);
326 copy_ivec(r, per->p2i[per->nper]);
329 /* Add the mirror too. It's rather likely that it'll be needed. */
330 per->p2i[per->nper][XX] = -r[XX];
331 per->p2i[per->nper][YY] = -r[YY];
332 per->p2i[per->nper][ZZ] = -r[ZZ];
335 return per->nper - 1 - (daSwap ? 0 : 1);
338 static t_hbdata *mk_hbdata(gmx_bool bHBmap, gmx_bool bDAnr, gmx_bool oneHB, gmx_bool bGem, int gemmode)
343 hb->wordlen = 8*sizeof(unsigned int);
353 hb->maxhydro = MAXHYDRO;
356 hb->per->gemtype = bGem ? gemmode : 0;
361 static void mk_hbmap(t_hbdata *hb)
365 snew(hb->hbmap, hb->d.nrd);
366 for (i = 0; (i < hb->d.nrd); i++)
368 snew(hb->hbmap[i], hb->a.nra);
369 if (hb->hbmap[i] == NULL)
371 gmx_fatal(FARGS, "Could not allocate enough memory for hbmap");
373 for (j = 0; (j > hb->a.nra); j++)
375 hb->hbmap[i][j] = NULL;
380 /* Consider redoing pHist so that is only stores transitions between
381 * periodicities and not the periodicity for all frames. This eats heaps of memory. */
382 static void mk_per(t_hbdata *hb)
387 snew(hb->per->pHist, hb->d.nrd);
388 for (i = 0; i < hb->d.nrd; i++)
390 snew(hb->per->pHist[i], hb->a.nra);
391 if (hb->per->pHist[i] == NULL)
393 gmx_fatal(FARGS, "Could not allocate enough memory for per->pHist");
395 for (j = 0; j < hb->a.nra; j++)
397 clearPshift(&(hb->per->pHist[i][j]));
400 /* add the [0,0,0] shift to element 0 of p2i. */
401 snew(hb->per->p2i, 1);
402 clear_ivec(hb->per->p2i[0]);
408 static void mk_hbEmap (t_hbdata *hb, int n0)
413 snew(hb->hbE.E, hb->d.nrd);
414 for (i = 0; i < hb->d.nrd; i++)
416 snew(hb->hbE.E[i], hb->a.nra);
417 for (j = 0; j < hb->a.nra; j++)
419 snew(hb->hbE.E[i][j], MAXHYDRO);
420 for (k = 0; k < MAXHYDRO; k++)
422 hb->hbE.E[i][j][k] = NULL;
429 static void free_hbEmap (t_hbdata *hb)
432 for (i = 0; i < hb->d.nrd; i++)
434 for (j = 0; j < hb->a.nra; j++)
436 for (k = 0; k < MAXHYDRO; k++)
438 sfree(hb->hbE.E[i][j][k]);
440 sfree(hb->hbE.E[i][j]);
448 static void addFramesNN(t_hbdata *hb, int frame)
451 #define DELTAFRAMES_HBE 10
453 int d, a, h, nframes;
455 if (frame >= hb->hbE.nframes)
457 nframes = hb->hbE.nframes + DELTAFRAMES_HBE;
458 srenew(hb->hbE.Etot, nframes);
460 for (d = 0; d < hb->d.nrd; d++)
462 for (a = 0; a < hb->a.nra; a++)
464 for (h = 0; h < hb->d.nhydro[d]; h++)
466 srenew(hb->hbE.E[d][a][h], nframes);
471 hb->hbE.nframes += DELTAFRAMES_HBE;
475 static t_E calcHbEnergy(int d, int a, int h, rvec x[], t_EEst EEst,
476 matrix box, rvec hbox, t_donors *donors)
481 * alpha - angle between dipoles
482 * x[] - atomic positions
483 * EEst - the type of energy estimate (see enum in hbplugin.h)
484 * box - the box vectors \
485 * hbox - half box lengths _These two are only needed for the pbc correction
490 rvec dipole[2], xmol[3], xmean[2];
496 /* Self-interaction */
503 /* This is a simple binary existence function that sets E=1 whenever
504 * the distance between the oxygens is equal too or less than 0.35 nm.
506 rvec_sub(x[d], x[a], dist);
507 pbc_correct_gem(dist, box, hbox);
508 if (norm(dist) <= 0.35)
519 /* Negative potential energy of a dipole.
520 * E = -cos(alpha) * 1/r^3 */
522 copy_rvec(x[d], xmol[0]); /* donor */
523 copy_rvec(x[donors->hydro[donors->dptr[d]][0]], xmol[1]); /* hydrogen */
524 copy_rvec(x[donors->hydro[donors->dptr[d]][1]], xmol[2]); /* hydrogen */
526 svmul(15.9994*(1/1.008), xmol[0], xmean[0]);
527 rvec_inc(xmean[0], xmol[1]);
528 rvec_inc(xmean[0], xmol[2]);
529 for (i = 0; i < 3; i++)
531 xmean[0][i] /= (15.9994 + 1.008 + 1.008)/1.008;
534 /* Assumes that all acceptors are also donors. */
535 copy_rvec(x[a], xmol[0]); /* acceptor */
536 copy_rvec(x[donors->hydro[donors->dptr[a]][0]], xmol[1]); /* hydrogen */
537 copy_rvec(x[donors->hydro[donors->dptr[a]][1]], xmol[2]); /* hydrogen */
540 svmul(15.9994*(1/1.008), xmol[0], xmean[1]);
541 rvec_inc(xmean[1], xmol[1]);
542 rvec_inc(xmean[1], xmol[2]);
543 for (i = 0; i < 3; i++)
545 xmean[1][i] /= (15.9994 + 1.008 + 1.008)/1.008;
548 rvec_sub(xmean[0], xmean[1], dist);
549 pbc_correct_gem(dist, box, hbox);
552 realE = pow(r, -3.0);
553 E = (t_E)(SCALEFACTOR_E * realE);
557 /* Negative potential energy of a (unpolarizable) dipole.
558 * E = -cos(alpha) * 1/r^3 */
559 clear_rvec(dipole[1]);
560 clear_rvec(dipole[0]);
562 copy_rvec(x[d], xmol[0]); /* donor */
563 copy_rvec(x[donors->hydro[donors->dptr[d]][0]], xmol[1]); /* hydrogen */
564 copy_rvec(x[donors->hydro[donors->dptr[d]][1]], xmol[2]); /* hydrogen */
566 rvec_inc(dipole[0], xmol[1]);
567 rvec_inc(dipole[0], xmol[2]);
568 for (i = 0; i < 3; i++)
572 rvec_dec(dipole[0], xmol[0]);
574 svmul(15.9994*(1/1.008), xmol[0], xmean[0]);
575 rvec_inc(xmean[0], xmol[1]);
576 rvec_inc(xmean[0], xmol[2]);
577 for (i = 0; i < 3; i++)
579 xmean[0][i] /= (15.9994 + 1.008 + 1.008)/1.008;
582 /* Assumes that all acceptors are also donors. */
583 copy_rvec(x[a], xmol[0]); /* acceptor */
584 copy_rvec(x[donors->hydro[donors->dptr[a]][0]], xmol[1]); /* hydrogen */
585 copy_rvec(x[donors->hydro[donors->dptr[a]][2]], xmol[2]); /* hydrogen */
588 rvec_inc(dipole[1], xmol[1]);
589 rvec_inc(dipole[1], xmol[2]);
590 for (i = 0; i < 3; i++)
594 rvec_dec(dipole[1], xmol[0]);
596 svmul(15.9994*(1/1.008), xmol[0], xmean[1]);
597 rvec_inc(xmean[1], xmol[1]);
598 rvec_inc(xmean[1], xmol[2]);
599 for (i = 0; i < 3; i++)
601 xmean[1][i] /= (15.9994 + 1.008 + 1.008)/1.008;
604 rvec_sub(xmean[0], xmean[1], dist);
605 pbc_correct_gem(dist, box, hbox);
608 double cosalpha = cos_angle(dipole[0], dipole[1]);
609 realE = cosalpha * pow(r, -3.0);
610 E = (t_E)(SCALEFACTOR_E * realE);
614 printf("Can't do that type of energy estimate: %i\n.", EEst);
621 static void storeHbEnergy(t_hbdata *hb, int d, int a, int h, t_E E, int frame)
623 /* hb - hbond data structure
627 E - estimate of the energy
628 frame - the current frame.
631 /* Store the estimated energy */
637 hb->hbE.E[d][a][h][frame] = E;
641 hb->hbE.Etot[frame] += E;
644 #endif /* HAVE_NN_LOOPS */
647 /* Finds -v[] in the periodicity index */
648 static int findMirror(PSTYPE p, ivec v[], PSTYPE nper)
652 for (i = 0; i < nper; i++)
654 if (v[i][XX] == -(v[p][XX]) &&
655 v[i][YY] == -(v[p][YY]) &&
656 v[i][ZZ] == -(v[p][ZZ]))
661 printf("Couldn't find mirror of [%i, %i, %i], index \n",
669 static void add_frames(t_hbdata *hb, int nframes)
673 if (nframes >= hb->max_frames)
675 hb->max_frames += 4096;
676 srenew(hb->time, hb->max_frames);
677 srenew(hb->nhb, hb->max_frames);
678 srenew(hb->ndist, hb->max_frames);
679 srenew(hb->n_bound, hb->max_frames);
680 srenew(hb->nhx, hb->max_frames);
683 srenew(hb->danr, hb->max_frames);
686 hb->nframes = nframes;
689 #define OFFSET(frame) (frame / 32)
690 #define MASK(frame) (1 << (frame % 32))
692 static void _set_hb(unsigned int hbexist[], unsigned int frame, gmx_bool bValue)
696 hbexist[OFFSET(frame)] |= MASK(frame);
700 hbexist[OFFSET(frame)] &= ~MASK(frame);
704 static gmx_bool is_hb(unsigned int hbexist[], int frame)
706 return ((hbexist[OFFSET(frame)] & MASK(frame)) != 0) ? 1 : 0;
709 static void set_hb(t_hbdata *hb, int id, int ih, int ia, int frame, int ihb)
711 unsigned int *ghptr = NULL;
715 ghptr = hb->hbmap[id][ia]->h[ih];
717 else if (ihb == hbDist)
719 ghptr = hb->hbmap[id][ia]->g[ih];
723 gmx_fatal(FARGS, "Incomprehensible iValue %d in set_hb", ihb);
726 _set_hb(ghptr, frame-hb->hbmap[id][ia]->n0, TRUE);
729 static void addPshift(t_pShift *pHist, PSTYPE p, int frame)
733 snew(pHist->frame, 1);
736 pHist->frame[0] = frame;
741 if (pHist->p[pHist->len-1] != p)
744 srenew(pHist->frame, pHist->len);
745 srenew(pHist->p, pHist->len);
746 pHist->frame[pHist->len-1] = frame;
747 pHist->p[pHist->len-1] = p;
748 } /* Otherwise, there is no transition. */
752 static PSTYPE getPshift(t_pShift pHist, int frame)
757 || (pHist.len > 0 && pHist.frame[0] > frame))
762 for (i = 0; i < pHist.len; i++)
775 /* It seems that frame is after the last periodic transition. Return the last periodicity. */
776 return pHist.p[pHist.len-1];
779 static void add_ff(t_hbdata *hbd, int id, int h, int ia, int frame, int ihb, PSTYPE p)
782 t_hbond *hb = hbd->hbmap[id][ia];
783 int maxhydro = min(hbd->maxhydro, hbd->d.nhydro[id]);
784 int wlen = hbd->wordlen;
786 gmx_bool bGem = hbd->bGem;
791 hb->maxframes = delta;
792 for (i = 0; (i < maxhydro); i++)
794 snew(hb->h[i], hb->maxframes/wlen);
795 snew(hb->g[i], hb->maxframes/wlen);
800 hb->nframes = frame-hb->n0;
801 /* We need a while loop here because hbonds may be returning
804 while (hb->nframes >= hb->maxframes)
806 n = hb->maxframes + delta;
807 for (i = 0; (i < maxhydro); i++)
809 srenew(hb->h[i], n/wlen);
810 srenew(hb->g[i], n/wlen);
811 for (j = hb->maxframes/wlen; (j < n/wlen); j++)
823 set_hb(hbd, id, h, ia, frame, ihb);
826 if (p >= hbd->per->nper)
828 gmx_fatal(FARGS, "invalid shift: p=%u, nper=%u", p, hbd->per->nper);
832 addPshift(&(hbd->per->pHist[id][ia]), p, frame);
840 static void inc_nhbonds(t_donors *ddd, int d, int h)
843 int dptr = ddd->dptr[d];
845 for (j = 0; (j < ddd->nhydro[dptr]); j++)
847 if (ddd->hydro[dptr][j] == h)
849 ddd->nhbonds[dptr][j]++;
853 if (j == ddd->nhydro[dptr])
855 gmx_fatal(FARGS, "No such hydrogen %d on donor %d\n", h+1, d+1);
859 static int _acceptor_index(t_acceptors *a, int grp, atom_id i,
860 const char *file, int line)
864 if (a->grp[ai] != grp)
868 fprintf(debug, "Acc. group inconsist.. grp[%d] = %d, grp = %d (%s, %d)\n",
869 ai, a->grp[ai], grp, file, line);
878 #define acceptor_index(a, grp, i) _acceptor_index(a, grp, i, __FILE__, __LINE__)
880 static int _donor_index(t_donors *d, int grp, atom_id i, const char *file, int line)
889 if (d->grp[di] != grp)
893 fprintf(debug, "Don. group inconsist.. grp[%d] = %d, grp = %d (%s, %d)\n",
894 di, d->grp[di], grp, file, line);
903 #define donor_index(d, grp, i) _donor_index(d, grp, i, __FILE__, __LINE__)
905 static gmx_bool isInterchangable(t_hbdata *hb, int d, int a, int grpa, int grpd)
907 /* g_hbond doesn't allow overlapping groups */
913 donor_index(&hb->d, grpd, a) != NOTSET
914 && acceptor_index(&hb->a, grpa, d) != NOTSET;
918 static void add_hbond(t_hbdata *hb, int d, int a, int h, int grpd, int grpa,
919 int frame, gmx_bool bMerge, int ihb, gmx_bool bContact, PSTYPE p)
922 gmx_bool daSwap = FALSE;
924 if ((id = hb->d.dptr[d]) == NOTSET)
926 gmx_fatal(FARGS, "No donor atom %d", d+1);
928 else if (grpd != hb->d.grp[id])
930 gmx_fatal(FARGS, "Inconsistent donor groups, %d iso %d, atom %d",
931 grpd, hb->d.grp[id], d+1);
933 if ((ia = hb->a.aptr[a]) == NOTSET)
935 gmx_fatal(FARGS, "No acceptor atom %d", a+1);
937 else if (grpa != hb->a.grp[ia])
939 gmx_fatal(FARGS, "Inconsistent acceptor groups, %d iso %d, atom %d",
940 grpa, hb->a.grp[ia], a+1);
946 if (isInterchangable(hb, d, a, grpd, grpa) && d > a)
947 /* Then swap identity so that the id of d is lower then that of a.
949 * This should really be redundant by now, as is_hbond() now ought to return
950 * hbNo in the cases where this conditional is TRUE. */
957 /* Now repeat donor/acc check. */
958 if ((id = hb->d.dptr[d]) == NOTSET)
960 gmx_fatal(FARGS, "No donor atom %d", d+1);
962 else if (grpd != hb->d.grp[id])
964 gmx_fatal(FARGS, "Inconsistent donor groups, %d iso %d, atom %d",
965 grpd, hb->d.grp[id], d+1);
967 if ((ia = hb->a.aptr[a]) == NOTSET)
969 gmx_fatal(FARGS, "No acceptor atom %d", a+1);
971 else if (grpa != hb->a.grp[ia])
973 gmx_fatal(FARGS, "Inconsistent acceptor groups, %d iso %d, atom %d",
974 grpa, hb->a.grp[ia], a+1);
981 /* Loop over hydrogens to find which hydrogen is in this particular HB */
982 if ((ihb == hbHB) && !bMerge && !bContact)
984 for (k = 0; (k < hb->d.nhydro[id]); k++)
986 if (hb->d.hydro[id][k] == h)
991 if (k == hb->d.nhydro[id])
993 gmx_fatal(FARGS, "Donor %d does not have hydrogen %d (a = %d)",
1005 #pragma omp critical
1007 if (hb->hbmap[id][ia] == NULL)
1009 snew(hb->hbmap[id][ia], 1);
1010 snew(hb->hbmap[id][ia]->h, hb->maxhydro);
1011 snew(hb->hbmap[id][ia]->g, hb->maxhydro);
1013 add_ff(hb, id, k, ia, frame, ihb, p);
1017 /* Strange construction with frame >=0 is a relic from old code
1018 * for selected hbond analysis. It may be necessary again if that
1019 * is made to work again.
1023 hh = hb->hbmap[id][ia]->history[k];
1029 hb->hbmap[id][ia]->history[k] = hh | 2;
1040 hb->hbmap[id][ia]->history[k] = hh | 1;
1064 if (bMerge && daSwap)
1066 h = hb->d.hydro[id][0];
1068 /* Increment number if HBonds per H */
1069 if (ihb == hbHB && !bContact)
1071 inc_nhbonds(&(hb->d), d, h);
1075 static char *mkatomname(t_atoms *atoms, int i)
1077 static char buf[32];
1080 rnr = atoms->atom[i].resind;
1081 sprintf(buf, "%4s%d%-4s",
1082 *atoms->resinfo[rnr].name, atoms->resinfo[rnr].nr, *atoms->atomname[i]);
1087 static void gen_datable(atom_id *index, int isize, unsigned char *datable, int natoms)
1089 /* Generates table of all atoms and sets the ingroup bit for atoms in index[] */
1092 for (i = 0; i < isize; i++)
1094 if (index[i] >= natoms)
1096 gmx_fatal(FARGS, "Atom has index %d larger than number of atoms %d.", index[i], natoms);
1098 datable[index[i]] |= INGROUP;
1102 static void clear_datable_grp(unsigned char *datable, int size)
1104 /* Clears group information from the table */
1106 const char mask = !(char)INGROUP;
1109 for (i = 0; i < size; i++)
1116 static void add_acc(t_acceptors *a, int ia, int grp)
1118 if (a->nra >= a->max_nra)
1121 srenew(a->acc, a->max_nra);
1122 srenew(a->grp, a->max_nra);
1124 a->grp[a->nra] = grp;
1125 a->acc[a->nra++] = ia;
1128 static void search_acceptors(t_topology *top, int isize,
1129 atom_id *index, t_acceptors *a, int grp,
1131 gmx_bool bContact, gmx_bool bDoIt, unsigned char *datable)
1137 for (i = 0; (i < isize); i++)
1141 (((*top->atoms.atomname[n])[0] == 'O') ||
1142 (bNitAcc && ((*top->atoms.atomname[n])[0] == 'N')))) &&
1143 ISINGRP(datable[n]))
1145 datable[n] |= ACC; /* set the atom's acceptor flag in datable. */
1150 snew(a->aptr, top->atoms.nr);
1151 for (i = 0; (i < top->atoms.nr); i++)
1153 a->aptr[i] = NOTSET;
1155 for (i = 0; (i < a->nra); i++)
1157 a->aptr[a->acc[i]] = i;
1161 static void add_h2d(int id, int ih, t_donors *ddd)
1165 for (i = 0; (i < ddd->nhydro[id]); i++)
1167 if (ddd->hydro[id][i] == ih)
1169 printf("Hm. This isn't the first time I found this donor (%d,%d)\n",
1174 if (i == ddd->nhydro[id])
1176 if (ddd->nhydro[id] >= MAXHYDRO)
1178 gmx_fatal(FARGS, "Donor %d has more than %d hydrogens!",
1179 ddd->don[id], MAXHYDRO);
1181 ddd->hydro[id][i] = ih;
1186 static void add_dh(t_donors *ddd, int id, int ih, int grp, unsigned char *datable)
1190 if (!datable || ISDON(datable[id]))
1192 if (ddd->dptr[id] == NOTSET) /* New donor */
1204 if (ddd->nrd >= ddd->max_nrd)
1206 ddd->max_nrd += 128;
1207 srenew(ddd->don, ddd->max_nrd);
1208 srenew(ddd->nhydro, ddd->max_nrd);
1209 srenew(ddd->hydro, ddd->max_nrd);
1210 srenew(ddd->nhbonds, ddd->max_nrd);
1211 srenew(ddd->grp, ddd->max_nrd);
1213 ddd->don[ddd->nrd] = id;
1214 ddd->nhydro[ddd->nrd] = 0;
1215 ddd->grp[ddd->nrd] = grp;
1222 add_h2d(i, ih, ddd);
1227 printf("Warning: Atom %d is not in the d/a-table!\n", id);
1231 static void search_donors(t_topology *top, int isize, atom_id *index,
1232 t_donors *ddd, int grp, gmx_bool bContact, gmx_bool bDoIt,
1233 unsigned char *datable)
1236 t_functype func_type;
1237 t_ilist *interaction;
1238 atom_id nr1, nr2, nr3;
1243 snew(ddd->dptr, top->atoms.nr);
1244 for (i = 0; (i < top->atoms.nr); i++)
1246 ddd->dptr[i] = NOTSET;
1254 for (i = 0; (i < isize); i++)
1256 datable[index[i]] |= DON;
1257 add_dh(ddd, index[i], -1, grp, datable);
1263 for (func_type = 0; (func_type < F_NRE); func_type++)
1265 interaction = &(top->idef.il[func_type]);
1266 if (func_type == F_POSRES || func_type == F_FBPOSRES)
1268 /* The ilist looks strange for posre. Bug in grompp?
1269 * We don't need posre interactions for hbonds anyway.*/
1272 for (i = 0; i < interaction->nr;
1273 i += interaction_function[top->idef.functype[interaction->iatoms[i]]].nratoms+1)
1276 if (func_type != top->idef.functype[interaction->iatoms[i]])
1278 fprintf(stderr, "Error in func_type %s",
1279 interaction_function[func_type].longname);
1283 /* check out this functype */
1284 if (func_type == F_SETTLE)
1286 nr1 = interaction->iatoms[i+1];
1287 nr2 = interaction->iatoms[i+2];
1288 nr3 = interaction->iatoms[i+3];
1290 if (ISINGRP(datable[nr1]))
1292 if (ISINGRP(datable[nr2]))
1294 datable[nr1] |= DON;
1295 add_dh(ddd, nr1, nr1+1, grp, datable);
1297 if (ISINGRP(datable[nr3]))
1299 datable[nr1] |= DON;
1300 add_dh(ddd, nr1, nr1+2, grp, datable);
1304 else if (IS_CHEMBOND(func_type))
1306 for (j = 0; j < 2; j++)
1308 nr1 = interaction->iatoms[i+1+j];
1309 nr2 = interaction->iatoms[i+2-j];
1310 if ((*top->atoms.atomname[nr1][0] == 'H') &&
1311 ((*top->atoms.atomname[nr2][0] == 'O') ||
1312 (*top->atoms.atomname[nr2][0] == 'N')) &&
1313 ISINGRP(datable[nr1]) && ISINGRP(datable[nr2]))
1315 datable[nr2] |= DON;
1316 add_dh(ddd, nr2, nr1, grp, datable);
1323 for (func_type = 0; func_type < F_NRE; func_type++)
1325 interaction = &top->idef.il[func_type];
1326 for (i = 0; i < interaction->nr;
1327 i += interaction_function[top->idef.functype[interaction->iatoms[i]]].nratoms+1)
1330 if (func_type != top->idef.functype[interaction->iatoms[i]])
1332 gmx_incons("function type in search_donors");
1335 if (interaction_function[func_type].flags & IF_VSITE)
1337 nr1 = interaction->iatoms[i+1];
1338 if (*top->atoms.atomname[nr1][0] == 'H')
1342 while (!stop && ( *top->atoms.atomname[nr2][0] == 'H'))
1353 if (!stop && ( ( *top->atoms.atomname[nr2][0] == 'O') ||
1354 ( *top->atoms.atomname[nr2][0] == 'N') ) &&
1355 ISINGRP(datable[nr1]) && ISINGRP(datable[nr2]))
1357 datable[nr2] |= DON;
1358 add_dh(ddd, nr2, nr1, grp, datable);
1368 static t_gridcell ***init_grid(gmx_bool bBox, rvec box[], real rcut, ivec ngrid)
1375 for (i = 0; i < DIM; i++)
1377 ngrid[i] = (box[i][i]/(1.2*rcut));
1381 if (!bBox || (ngrid[XX] < 3) || (ngrid[YY] < 3) || (ngrid[ZZ] < 3) )
1383 for (i = 0; i < DIM; i++)
1390 printf("\nWill do grid-seach on %dx%dx%d grid, rcut=%g\n",
1391 ngrid[XX], ngrid[YY], ngrid[ZZ], rcut);
1393 snew(grid, ngrid[ZZ]);
1394 for (z = 0; z < ngrid[ZZ]; z++)
1396 snew((grid)[z], ngrid[YY]);
1397 for (y = 0; y < ngrid[YY]; y++)
1399 snew((grid)[z][y], ngrid[XX]);
1405 static void reset_nhbonds(t_donors *ddd)
1409 for (i = 0; (i < ddd->nrd); i++)
1411 for (j = 0; (j < MAXHH); j++)
1413 ddd->nhbonds[i][j] = 0;
1418 void pbc_correct_gem(rvec dx, matrix box, rvec hbox);
1420 static void build_grid(t_hbdata *hb, rvec x[], rvec xshell,
1421 gmx_bool bBox, matrix box, rvec hbox,
1422 real rcut, real rshell,
1423 ivec ngrid, t_gridcell ***grid)
1425 int i, m, gr, xi, yi, zi, nr;
1428 rvec invdelta, dshell, xtemp = {0, 0, 0};
1430 gmx_bool bDoRshell, bInShell, bAcc;
1435 bDoRshell = (rshell > 0);
1436 rshell2 = sqr(rshell);
1439 #define DBB(x) if (debug && bDebug) fprintf(debug, "build_grid, line %d, %s = %d\n", __LINE__,#x, x)
1441 for (m = 0; m < DIM; m++)
1443 hbox[m] = box[m][m]*0.5;
1446 invdelta[m] = ngrid[m]/box[m][m];
1447 if (1/invdelta[m] < rcut)
1449 gmx_fatal(FARGS, "Your computational box has shrunk too much.\n"
1450 "%s can not handle this situation, sorry.\n",
1463 /* resetting atom counts */
1464 for (gr = 0; (gr < grNR); gr++)
1466 for (zi = 0; zi < ngrid[ZZ]; zi++)
1468 for (yi = 0; yi < ngrid[YY]; yi++)
1470 for (xi = 0; xi < ngrid[XX]; xi++)
1472 grid[zi][yi][xi].d[gr].nr = 0;
1473 grid[zi][yi][xi].a[gr].nr = 0;
1479 /* put atoms in grid cells */
1480 for (bAcc = FALSE; (bAcc <= TRUE); bAcc++)
1493 for (i = 0; (i < nr); i++)
1495 /* check if we are inside the shell */
1496 /* if bDoRshell=FALSE then bInShell=TRUE always */
1501 rvec_sub(x[ad[i]], xshell, dshell);
1504 if (FALSE && !hb->bGem)
1506 for (m = DIM-1; m >= 0 && bInShell; m--)
1508 if (dshell[m] < -hbox[m])
1510 rvec_inc(dshell, box[m]);
1512 else if (dshell[m] >= hbox[m])
1514 dshell[m] -= 2*hbox[m];
1516 /* if we're outside the cube, we're outside the sphere also! */
1517 if ( (dshell[m] > rshell) || (-dshell[m] > rshell) )
1525 gmx_bool bDone = FALSE;
1529 for (m = DIM-1; m >= 0 && bInShell; m--)
1531 if (dshell[m] < -hbox[m])
1534 rvec_inc(dshell, box[m]);
1536 if (dshell[m] >= hbox[m])
1539 dshell[m] -= 2*hbox[m];
1543 for (m = DIM-1; m >= 0 && bInShell; m--)
1545 /* if we're outside the cube, we're outside the sphere also! */
1546 if ( (dshell[m] > rshell) || (-dshell[m] > rshell) )
1553 /* if we're inside the cube, check if we're inside the sphere */
1556 bInShell = norm2(dshell) < rshell2;
1566 copy_rvec(x[ad[i]], xtemp);
1568 pbc_correct_gem(x[ad[i]], box, hbox);
1570 for (m = DIM-1; m >= 0; m--)
1572 if (TRUE || !hb->bGem)
1574 /* put atom in the box */
1575 while (x[ad[i]][m] < 0)
1577 rvec_inc(x[ad[i]], box[m]);
1579 while (x[ad[i]][m] >= box[m][m])
1581 rvec_dec(x[ad[i]], box[m]);
1584 /* determine grid index of atom */
1585 grididx[m] = x[ad[i]][m]*invdelta[m];
1586 grididx[m] = (grididx[m]+ngrid[m]) % ngrid[m];
1590 copy_rvec(xtemp, x[ad[i]]); /* copy back */
1595 range_check(gx, 0, ngrid[XX]);
1596 range_check(gy, 0, ngrid[YY]);
1597 range_check(gz, 0, ngrid[ZZ]);
1601 /* add atom to grid cell */
1604 newgrid = &(grid[gz][gy][gx].a[gr]);
1608 newgrid = &(grid[gz][gy][gx].d[gr]);
1610 if (newgrid->nr >= newgrid->maxnr)
1612 newgrid->maxnr += 10;
1613 DBB(newgrid->maxnr);
1614 srenew(newgrid->atoms, newgrid->maxnr);
1617 newgrid->atoms[newgrid->nr] = ad[i];
1625 static void count_da_grid(ivec ngrid, t_gridcell ***grid, t_icell danr)
1629 for (gr = 0; (gr < grNR); gr++)
1632 for (zi = 0; zi < ngrid[ZZ]; zi++)
1634 for (yi = 0; yi < ngrid[YY]; yi++)
1636 for (xi = 0; xi < ngrid[XX]; xi++)
1638 danr[gr] += grid[zi][yi][xi].d[gr].nr;
1646 * Without a box, the grid is 1x1x1, so all loops are 1 long.
1647 * With a rectangular box (bTric==FALSE) all loops are 3 long.
1648 * With a triclinic box all loops are 3 long, except when a cell is
1649 * located next to one of the box edges which is not parallel to the
1650 * x/y-plane, in that case all cells in a line or layer are searched.
1651 * This could be implemented slightly more efficient, but the code
1652 * would get much more complicated.
1654 static gmx_inline gmx_bool grid_loop_begin(int n, int x, gmx_bool bTric, gmx_bool bEdge)
1656 return ((n == 1) ? x : bTric && bEdge ? 0 : (x-1));
1658 static gmx_inline gmx_bool grid_loop_end(int n, int x, gmx_bool bTric, gmx_bool bEdge)
1660 return ((n == 1) ? x : bTric && bEdge ? (n-1) : (x+1));
1662 static gmx_inline int grid_mod(int j, int n)
1667 static void dump_grid(FILE *fp, ivec ngrid, t_gridcell ***grid)
1669 int gr, x, y, z, sum[grNR];
1671 fprintf(fp, "grid %dx%dx%d\n", ngrid[XX], ngrid[YY], ngrid[ZZ]);
1672 for (gr = 0; gr < grNR; gr++)
1675 fprintf(fp, "GROUP %d (%s)\n", gr, grpnames[gr]);
1676 for (z = 0; z < ngrid[ZZ]; z += 2)
1678 fprintf(fp, "Z=%d,%d\n", z, z+1);
1679 for (y = 0; y < ngrid[YY]; y++)
1681 for (x = 0; x < ngrid[XX]; x++)
1683 fprintf(fp, "%3d", grid[x][y][z].d[gr].nr);
1684 sum[gr] += grid[z][y][x].d[gr].nr;
1685 fprintf(fp, "%3d", grid[x][y][z].a[gr].nr);
1686 sum[gr] += grid[z][y][x].a[gr].nr;
1690 if ( (z+1) < ngrid[ZZ])
1692 for (x = 0; x < ngrid[XX]; x++)
1694 fprintf(fp, "%3d", grid[z+1][y][x].d[gr].nr);
1695 sum[gr] += grid[z+1][y][x].d[gr].nr;
1696 fprintf(fp, "%3d", grid[z+1][y][x].a[gr].nr);
1697 sum[gr] += grid[z+1][y][x].a[gr].nr;
1704 fprintf(fp, "TOTALS:");
1705 for (gr = 0; gr < grNR; gr++)
1707 fprintf(fp, " %d=%d", gr, sum[gr]);
1712 /* New GMX record! 5 * in a row. Congratulations!
1713 * Sorry, only four left.
1715 static void free_grid(ivec ngrid, t_gridcell ****grid)
1718 t_gridcell ***g = *grid;
1720 for (z = 0; z < ngrid[ZZ]; z++)
1722 for (y = 0; y < ngrid[YY]; y++)
1732 void pbc_correct_gem(rvec dx, matrix box, rvec hbox)
1735 gmx_bool bDone = FALSE;
1739 for (m = DIM-1; m >= 0; m--)
1741 if (dx[m] < -hbox[m])
1744 rvec_inc(dx, box[m]);
1746 if (dx[m] >= hbox[m])
1749 rvec_dec(dx, box[m]);
1755 /* Added argument r2cut, changed contact and implemented
1756 * use of second cut-off.
1757 * - Erik Marklund, June 29, 2006
1759 static int is_hbond(t_hbdata *hb, int grpd, int grpa, int d, int a,
1760 real rcut, real r2cut, real ccut,
1761 rvec x[], gmx_bool bBox, matrix box, rvec hbox,
1762 real *d_ha, real *ang, gmx_bool bDA, int *hhh,
1763 gmx_bool bContact, gmx_bool bMerge, PSTYPE *p)
1765 int h, hh, id, ja, ihb;
1766 rvec r_da, r_ha, r_dh, r = {0, 0, 0};
1768 real rc2, r2c2, rda2, rha2, ca;
1769 gmx_bool HAinrange = FALSE; /* If !bDA. Needed for returning hbDist in a correct way. */
1770 gmx_bool daSwap = FALSE;
1777 if (((id = donor_index(&hb->d, grpd, d)) == NOTSET) ||
1778 ((ja = acceptor_index(&hb->a, grpa, a)) == NOTSET))
1786 rvec_sub(x[d], x[a], r_da);
1787 /* Insert projection code here */
1789 if (bMerge && d > a && isInterchangable(hb, d, a, grpd, grpa))
1791 /* Then this hbond/contact will be found again, or it has already been found. */
1796 if (d > a && bMerge && isInterchangable(hb, d, a, grpd, grpa)) /* acceptor is also a donor and vice versa? */
1797 { /* return hbNo; */
1798 daSwap = TRUE; /* If so, then their history should be filed with donor and acceptor swapped. */
1802 copy_rvec(r_da, r); /* Save this for later */
1803 pbc_correct_gem(r_da, box, hbox);
1807 pbc_correct_gem(r_da, box, hbox);
1810 rda2 = iprod(r_da, r_da);
1814 if (daSwap && grpa == grpd)
1822 calcBoxDistance(hb->per->P, r, ri);
1823 *p = periodicIndex(ri, hb->per, daSwap); /* find (or add) periodicity index. */
1827 else if (rda2 < r2c2)
1838 if (bDA && (rda2 > rc2))
1843 for (h = 0; (h < hb->d.nhydro[id]); h++)
1845 hh = hb->d.hydro[id][h];
1849 rvec_sub(x[hh], x[a], r_ha);
1852 pbc_correct_gem(r_ha, box, hbox);
1854 rha2 = iprod(r_ha, r_ha);
1859 calcBoxDistance(hb->per->P, r, ri);
1860 *p = periodicIndex(ri, hb->per, daSwap); /* find periodicity index. */
1863 if (bDA || (!bDA && (rha2 <= rc2)))
1865 rvec_sub(x[d], x[hh], r_dh);
1868 pbc_correct_gem(r_dh, box, hbox);
1875 ca = cos_angle(r_dh, r_da);
1876 /* if angle is smaller, cos is larger */
1880 *d_ha = sqrt(bDA ? rda2 : rha2);
1886 if (bDA || (!bDA && HAinrange))
1896 /* Fixed previously undiscovered bug in the merge
1897 code, where the last frame of each hbond disappears.
1898 - Erik Marklund, June 1, 2006 */
1899 /* Added the following arguments:
1900 * ptmp[] - temporary periodicity hisory
1901 * a1 - identity of first acceptor/donor
1902 * a2 - identity of second acceptor/donor
1903 * - Erik Marklund, FEB 20 2010 */
1905 /* Merging is now done on the fly, so do_merge is most likely obsolete now.
1906 * Will do some more testing before removing the function entirely.
1907 * - Erik Marklund, MAY 10 2010 */
1908 static void do_merge(t_hbdata *hb, int ntmp,
1909 unsigned int htmp[], unsigned int gtmp[], PSTYPE ptmp[],
1910 t_hbond *hb0, t_hbond *hb1, int a1, int a2)
1912 /* Here we need to make sure we're treating periodicity in
1913 * the right way for the geminate recombination kinetics. */
1915 int m, mm, n00, n01, nn0, nnframes;
1919 /* Decide where to start from when merging */
1922 nn0 = min(n00, n01);
1923 nnframes = max(n00 + hb0->nframes, n01 + hb1->nframes) - nn0;
1924 /* Initiate tmp arrays */
1925 for (m = 0; (m < ntmp); m++)
1931 /* Fill tmp arrays with values due to first HB */
1932 /* Once again '<' had to be replaced with '<='
1933 to catch the last frame in which the hbond
1935 - Erik Marklund, June 1, 2006 */
1936 for (m = 0; (m <= hb0->nframes); m++)
1939 htmp[mm] = is_hb(hb0->h[0], m);
1942 pm = getPshift(hb->per->pHist[a1][a2], m+hb0->n0);
1943 if (pm > hb->per->nper)
1945 gmx_fatal(FARGS, "Illegal shift!");
1949 ptmp[mm] = pm; /*hb->per->pHist[a1][a2][m];*/
1953 /* If we're doing geminate recompbination we usually don't need the distances.
1954 * Let's save some memory and time. */
1955 if (TRUE || !hb->bGem || hb->per->gemtype == gemAD)
1957 for (m = 0; (m <= hb0->nframes); m++)
1960 gtmp[mm] = is_hb(hb0->g[0], m);
1964 for (m = 0; (m <= hb1->nframes); m++)
1967 htmp[mm] = htmp[mm] || is_hb(hb1->h[0], m);
1968 gtmp[mm] = gtmp[mm] || is_hb(hb1->g[0], m);
1969 if (hb->bGem /* && ptmp[mm] != 0 */)
1972 /* If this hbond has been seen before with donor and acceptor swapped,
1973 * then we need to find the mirrored (*-1) periodicity vector to truely
1974 * merge the hbond history. */
1975 pm = findMirror(getPshift(hb->per->pHist[a2][a1], m+hb1->n0), hb->per->p2i, hb->per->nper);
1976 /* Store index of mirror */
1977 if (pm > hb->per->nper)
1979 gmx_fatal(FARGS, "Illegal shift!");
1984 /* Reallocate target array */
1985 if (nnframes > hb0->maxframes)
1987 srenew(hb0->h[0], 4+nnframes/hb->wordlen);
1988 srenew(hb0->g[0], 4+nnframes/hb->wordlen);
1990 if (NULL != hb->per->pHist)
1992 clearPshift(&(hb->per->pHist[a1][a2]));
1995 /* Copy temp array to target array */
1996 for (m = 0; (m <= nnframes); m++)
1998 _set_hb(hb0->h[0], m, htmp[m]);
1999 _set_hb(hb0->g[0], m, gtmp[m]);
2002 addPshift(&(hb->per->pHist[a1][a2]), ptmp[m], m+nn0);
2006 /* Set scalar variables */
2008 hb0->maxframes = nnframes;
2011 /* Added argument bContact for nicer output.
2012 * Erik Marklund, June 29, 2006
2014 static void merge_hb(t_hbdata *hb, gmx_bool bTwo, gmx_bool bContact)
2016 int i, inrnew, indnew, j, ii, jj, m, id, ia, grp, ogrp, ntmp;
2017 unsigned int *htmp, *gtmp;
2022 indnew = hb->nrdist;
2024 /* Check whether donors are also acceptors */
2025 printf("Merging hbonds with Acceptor and Donor swapped\n");
2027 ntmp = 2*hb->max_frames;
2031 for (i = 0; (i < hb->d.nrd); i++)
2033 fprintf(stderr, "\r%d/%d", i+1, hb->d.nrd);
2035 ii = hb->a.aptr[id];
2036 for (j = 0; (j < hb->a.nra); j++)
2039 jj = hb->d.dptr[ia];
2040 if ((id != ia) && (ii != NOTSET) && (jj != NOTSET) &&
2041 (!bTwo || (bTwo && (hb->d.grp[i] != hb->a.grp[j]))))
2043 hb0 = hb->hbmap[i][j];
2044 hb1 = hb->hbmap[jj][ii];
2045 if (hb0 && hb1 && ISHB(hb0->history[0]) && ISHB(hb1->history[0]))
2047 do_merge(hb, ntmp, htmp, gtmp, ptmp, hb0, hb1, i, j);
2048 if (ISHB(hb1->history[0]))
2052 else if (ISDIST(hb1->history[0]))
2059 gmx_incons("No contact history");
2063 gmx_incons("Neither hydrogen bond nor distance");
2069 clearPshift(&(hb->per->pHist[jj][ii]));
2073 hb1->history[0] = hbNo;
2078 fprintf(stderr, "\n");
2079 printf("- Reduced number of hbonds from %d to %d\n", hb->nrhb, inrnew);
2080 printf("- Reduced number of distances from %d to %d\n", hb->nrdist, indnew);
2082 hb->nrdist = indnew;
2088 static void do_nhb_dist(FILE *fp, t_hbdata *hb, real t)
2090 int i, j, k, n_bound[MAXHH], nbtot;
2094 /* Set array to 0 */
2095 for (k = 0; (k < MAXHH); k++)
2099 /* Loop over possible donors */
2100 for (i = 0; (i < hb->d.nrd); i++)
2102 for (j = 0; (j < hb->d.nhydro[i]); j++)
2104 n_bound[hb->d.nhbonds[i][j]]++;
2107 fprintf(fp, "%12.5e", t);
2109 for (k = 0; (k < MAXHH); k++)
2111 fprintf(fp, " %8d", n_bound[k]);
2112 nbtot += n_bound[k]*k;
2114 fprintf(fp, " %8d\n", nbtot);
2117 /* Added argument bContact in do_hblife(...). Also
2118 * added support for -contact in function body.
2119 * - Erik Marklund, May 31, 2006 */
2120 /* Changed the contact code slightly.
2121 * - Erik Marklund, June 29, 2006
2123 static void do_hblife(const char *fn, t_hbdata *hb, gmx_bool bMerge, gmx_bool bContact,
2124 const output_env_t oenv)
2127 const char *leg[] = { "p(t)", "t p(t)" };
2129 int i, j, j0, k, m, nh, ihb, ohb, nhydro, ndump = 0;
2130 int nframes = hb->nframes;
2133 double sum, integral;
2136 snew(h, hb->maxhydro);
2137 snew(histo, nframes+1);
2138 /* Total number of hbonds analyzed here */
2139 for (i = 0; (i < hb->d.nrd); i++)
2141 for (k = 0; (k < hb->a.nra); k++)
2143 hbh = hb->hbmap[i][k];
2161 for (m = 0; (m < hb->maxhydro); m++)
2165 h[nhydro++] = bContact ? hbh->g[m] : hbh->h[m];
2169 for (nh = 0; (nh < nhydro); nh++)
2174 /* Changed '<' into '<=' below, just like I
2175 did in the hbm-output-loop in the main code.
2176 - Erik Marklund, May 31, 2006
2178 for (j = 0; (j <= hbh->nframes); j++)
2180 ihb = is_hb(h[nh], j);
2181 if (debug && (ndump < 10))
2183 fprintf(debug, "%5d %5d\n", j, ihb);
2203 fprintf(stderr, "\n");
2206 fp = xvgropen(fn, "Uninterrupted contact lifetime", output_env_get_xvgr_tlabel(oenv), "()", oenv);
2210 fp = xvgropen(fn, "Uninterrupted hydrogen bond lifetime", output_env_get_xvgr_tlabel(oenv), "()",
2214 xvgr_legend(fp, asize(leg), leg, oenv);
2216 while ((j0 > 0) && (histo[j0] == 0))
2221 for (i = 0; (i <= j0); i++)
2225 dt = hb->time[1]-hb->time[0];
2228 for (i = 1; (i <= j0); i++)
2230 t = hb->time[i] - hb->time[0] - 0.5*dt;
2231 x1 = t*histo[i]/sum;
2232 fprintf(fp, "%8.3f %10.3e %10.3e\n", t, histo[i]/sum, x1);
2237 printf("%s lifetime = %.2f ps\n", bContact ? "Contact" : "HB", integral);
2238 printf("Note that the lifetime obtained in this manner is close to useless\n");
2239 printf("Use the -ac option instead and check the Forward lifetime\n");
2240 please_cite(stdout, "Spoel2006b");
2245 /* Changed argument bMerge into oneHB to handle contacts properly.
2246 * - Erik Marklund, June 29, 2006
2248 static void dump_ac(t_hbdata *hb, gmx_bool oneHB, int nDump)
2251 int i, j, k, m, nd, ihb, idist;
2252 int nframes = hb->nframes;
2260 fp = gmx_ffopen("debug-ac.xvg", "w");
2261 for (j = 0; (j < nframes); j++)
2263 fprintf(fp, "%10.3f", hb->time[j]);
2264 for (i = nd = 0; (i < hb->d.nrd) && (nd < nDump); i++)
2266 for (k = 0; (k < hb->a.nra) && (nd < nDump); k++)
2270 hbh = hb->hbmap[i][k];
2275 ihb = is_hb(hbh->h[0], j);
2276 idist = is_hb(hbh->g[0], j);
2282 for (m = 0; (m < hb->maxhydro) && !ihb; m++)
2284 ihb = ihb || ((hbh->h[m]) && is_hb(hbh->h[m], j));
2285 idist = idist || ((hbh->g[m]) && is_hb(hbh->g[m], j));
2287 /* This is not correct! */
2288 /* What isn't correct? -Erik M */
2293 fprintf(fp, " %1d-%1d", ihb, idist);
2303 static real calc_dg(real tau, real temp)
2314 return kbt*log(kbt*tau/PLANCK);
2319 int n0, n1, nparams, ndelta;
2321 real *t, *ct, *nt, *kt, *sigma_ct, *sigma_nt, *sigma_kt;
2324 static real compute_weighted_rates(int n, real t[], real ct[], real nt[],
2325 real kt[], real sigma_ct[], real sigma_nt[],
2326 real sigma_kt[], real *k, real *kp,
2327 real *sigma_k, real *sigma_kp,
2333 real kkk = 0, kkp = 0, kk2 = 0, kp2 = 0, chi2;
2338 for (i = 0; (i < n); i++)
2340 if (t[i] >= fit_start)
2353 tl.sigma_ct = sigma_ct;
2354 tl.sigma_nt = sigma_nt;
2355 tl.sigma_kt = sigma_kt;
2359 chi2 = 0; /*optimize_luzar_parameters(debug, &tl, 1000, 1e-3); */
2361 *kp = tl.kkk[1] = *kp;
2363 for (j = 0; (j < NK); j++)
2365 /* (void) optimize_luzar_parameters(debug, &tl, 1000, 1e-3); */
2368 kk2 += sqr(tl.kkk[0]);
2369 kp2 += sqr(tl.kkk[1]);
2372 *sigma_k = sqrt(kk2/NK - sqr(kkk/NK));
2373 *sigma_kp = sqrt(kp2/NK - sqr(kkp/NK));
2378 static void smooth_tail(int n, real t[], real c[], real sigma_c[], real start,
2379 const output_env_t oenv)
2387 for (i = 0; (i < n); i++)
2403 do_lmfit(n, c, sigma_c, 0, t, start, t[n-1], oenv, bDebugMode(),
2404 effnEXP2, fitparm, 0);
2407 void analyse_corr(int n, real t[], real ct[], real nt[], real kt[],
2408 real sigma_ct[], real sigma_nt[], real sigma_kt[],
2409 real fit_start, real temp, real smooth_tail_start,
2410 const output_env_t oenv)
2413 real k = 1, kp = 1, kow = 1;
2414 real Q = 0, chi22, chi2, dg, dgp, tau_hb, dtau, tau_rlx, e_1, dt, sigma_k, sigma_kp, ddg;
2415 double tmp, sn2 = 0, sc2 = 0, sk2 = 0, scn = 0, sck = 0, snk = 0;
2416 gmx_bool bError = (sigma_ct != NULL) && (sigma_nt != NULL) && (sigma_kt != NULL);
2418 if (smooth_tail_start >= 0)
2420 smooth_tail(n, t, ct, sigma_ct, smooth_tail_start, oenv);
2421 smooth_tail(n, t, nt, sigma_nt, smooth_tail_start, oenv);
2422 smooth_tail(n, t, kt, sigma_kt, smooth_tail_start, oenv);
2424 for (i0 = 0; (i0 < n-2) && ((t[i0]-t[0]) < fit_start); i0++)
2430 for (i = i0; (i < n); i++)
2439 printf("Hydrogen bond thermodynamics at T = %g K\n", temp);
2440 tmp = (sn2*sc2-sqr(scn));
2441 if ((tmp > 0) && (sn2 > 0))
2443 k = (sn2*sck-scn*snk)/tmp;
2444 kp = (k*scn-snk)/sn2;
2448 for (i = i0; (i < n); i++)
2450 chi2 += sqr(k*ct[i]-kp*nt[i]-kt[i]);
2452 chi22 = compute_weighted_rates(n, t, ct, nt, kt, sigma_ct, sigma_nt,
2454 &sigma_k, &sigma_kp, fit_start);
2455 Q = 0; /* quality_of_fit(chi2, 2);*/
2456 ddg = BOLTZ*temp*sigma_k/k;
2457 printf("Fitting paramaters chi^2 = %10g, Quality of fit = %10g\n",
2459 printf("The Rate and Delta G are followed by an error estimate\n");
2460 printf("----------------------------------------------------------\n"
2461 "Type Rate (1/ps) Sigma Time (ps) DG (kJ/mol) Sigma\n");
2462 printf("Forward %10.3f %6.2f %8.3f %10.3f %6.2f\n",
2463 k, sigma_k, 1/k, calc_dg(1/k, temp), ddg);
2464 ddg = BOLTZ*temp*sigma_kp/kp;
2465 printf("Backward %10.3f %6.2f %8.3f %10.3f %6.2f\n",
2466 kp, sigma_kp, 1/kp, calc_dg(1/kp, temp), ddg);
2471 for (i = i0; (i < n); i++)
2473 chi2 += sqr(k*ct[i]-kp*nt[i]-kt[i]);
2475 printf("Fitting parameters chi^2 = %10g\nQ = %10g\n",
2477 printf("--------------------------------------------------\n"
2478 "Type Rate (1/ps) Time (ps) DG (kJ/mol) Chi^2\n");
2479 printf("Forward %10.3f %8.3f %10.3f %10g\n",
2480 k, 1/k, calc_dg(1/k, temp), chi2);
2481 printf("Backward %10.3f %8.3f %10.3f\n",
2482 kp, 1/kp, calc_dg(1/kp, temp));
2488 printf("One-way %10.3f %s%8.3f %10.3f\n",
2489 kow, bError ? " " : "", 1/kow, calc_dg(1/kow, temp));
2493 printf(" - Numerical problems computing HB thermodynamics:\n"
2494 "sc2 = %g sn2 = %g sk2 = %g sck = %g snk = %g scn = %g\n",
2495 sc2, sn2, sk2, sck, snk, scn);
2497 /* Determine integral of the correlation function */
2498 tau_hb = evaluate_integral(n, t, ct, NULL, (t[n-1]-t[0])/2, &dtau);
2499 printf("Integral %10.3f %s%8.3f %10.3f\n", 1/tau_hb,
2500 bError ? " " : "", tau_hb, calc_dg(tau_hb, temp));
2502 for (i = 0; (i < n-2); i++)
2504 if ((ct[i] > e_1) && (ct[i+1] <= e_1))
2511 /* Determine tau_relax from linear interpolation */
2512 tau_rlx = t[i]-t[0] + (e_1-ct[i])*(t[i+1]-t[i])/(ct[i+1]-ct[i]);
2513 printf("Relaxation %10.3f %8.3f %s%10.3f\n", 1/tau_rlx,
2514 tau_rlx, bError ? " " : "",
2515 calc_dg(tau_rlx, temp));
2520 printf("Correlation functions too short to compute thermodynamics\n");
2524 void compute_derivative(int nn, real x[], real y[], real dydx[])
2528 /* Compute k(t) = dc(t)/dt */
2529 for (j = 1; (j < nn-1); j++)
2531 dydx[j] = (y[j+1]-y[j-1])/(x[j+1]-x[j-1]);
2533 /* Extrapolate endpoints */
2534 dydx[0] = 2*dydx[1] - dydx[2];
2535 dydx[nn-1] = 2*dydx[nn-2] - dydx[nn-3];
2538 static void parallel_print(int *data, int nThreads)
2540 /* This prints the donors on which each tread is currently working. */
2543 fprintf(stderr, "\r");
2544 for (i = 0; i < nThreads; i++)
2546 fprintf(stderr, "%-7i", data[i]);
2550 static void normalizeACF(real *ct, real *gt, int nhb, int len)
2552 real ct_fac, gt_fac = 0;
2555 /* Xu and Berne use the same normalization constant */
2560 gt_fac = 1.0/(real)nhb;
2563 printf("Normalization for c(t) = %g for gh(t) = %g\n", ct_fac, gt_fac);
2564 for (i = 0; i < len; i++)
2574 /* Added argument bContact in do_hbac(...). Also
2575 * added support for -contact in the actual code.
2576 * - Erik Marklund, May 31, 2006 */
2577 /* Changed contact code and added argument R2
2578 * - Erik Marklund, June 29, 2006
2580 static void do_hbac(const char *fn, t_hbdata *hb,
2581 int nDump, gmx_bool bMerge, gmx_bool bContact, real fit_start,
2582 real temp, gmx_bool R2, real smooth_tail_start, const output_env_t oenv,
2583 const char *gemType, int nThreads,
2584 const int NN, const gmx_bool bBallistic, const gmx_bool bGemFit)
2587 int i, j, k, m, n, o, nd, ihb, idist, n2, nn, iter, nSets;
2588 const char *legNN[] = {
2592 static char **legGem;
2594 const char *legLuzar[] = {
2595 "Ac\\sfin sys\\v{}\\z{}(t)",
2597 "Cc\\scontact,hb\\v{}\\z{}(t)",
2598 "-dAc\\sfs\\v{}\\z{}/dt"
2600 gmx_bool bNorm = FALSE, bOMP = FALSE;
2603 real *rhbex = NULL, *ht, *gt, *ght, *dght, *kt;
2604 real *ct, *p_ct, tail, tail2, dtail, ct_fac, ght_fac, *cct;
2605 const real tol = 1e-3;
2606 int nframes = hb->nframes, nf;
2607 unsigned int **h = NULL, **g = NULL;
2608 int nh, nhbonds, nhydro, ngh;
2610 PSTYPE p, *pfound = NULL, np;
2612 int *ptimes = NULL, *poff = NULL, anhb, n0, mMax = INT_MIN;
2613 real **rHbExGem = NULL;
2617 double *ctdouble, *timedouble, *fittedct;
2618 double fittolerance = 0.1;
2619 int *dondata = NULL, thisThread;
2622 AC_NONE, AC_NN, AC_GEM, AC_LUZAR
2631 printf("Doing autocorrelation ");
2633 /* Decide what kind of ACF calculations to do. */
2634 if (NN > NN_NONE && NN < NN_NR)
2636 #ifdef HAVE_NN_LOOPS
2638 printf("using the energy estimate.\n");
2641 printf("Can't do the NN-loop. Yet.\n");
2647 printf("according to the reversible geminate recombination model by Omer Markowitch.\n");
2649 nSets = 1 + (bBallistic ? 1 : 0) + (bGemFit ? 1 : 0);
2650 snew(legGem, nSets);
2651 for (i = 0; i < nSets; i++)
2653 snew(legGem[i], 128);
2655 sprintf(legGem[0], "Ac\\s%s\\v{}\\z{}(t)", gemType);
2658 sprintf(legGem[1], "Ac'(t)");
2662 sprintf(legGem[(bBallistic ? 3 : 2)], "Ac\\s%s,fit\\v{}\\z{}(t)", gemType);
2669 printf("according to the theory of Luzar and Chandler.\n");
2673 /* build hbexist matrix in reals for autocorr */
2674 /* Allocate memory for computing ACF (rhbex) and aggregating the ACF (ct) */
2676 while (n2 < nframes)
2683 if (acType != AC_NN || bOMP)
2685 snew(h, hb->maxhydro);
2686 snew(g, hb->maxhydro);
2689 /* Dump hbonds for debugging */
2690 dump_ac(hb, bMerge || bContact, nDump);
2692 /* Total number of hbonds analyzed here */
2697 if (acType != AC_LUZAR && bOMP)
2699 nThreads = min((nThreads <= 0) ? INT_MAX : nThreads, gmx_omp_get_max_threads());
2701 gmx_omp_set_num_threads(nThreads);
2702 snew(dondata, nThreads);
2703 for (i = 0; i < nThreads; i++)
2707 printf("ACF calculations parallelized with OpenMP using %i threads.\n"
2708 "Expect close to linear scaling over this donor-loop.\n", nThreads);
2710 fprintf(stderr, "Donors: [thread no]\n");
2713 for (i = 0; i < nThreads; i++)
2715 snprintf(tmpstr, 7, "[%i]", i);
2716 fprintf(stderr, "%-7s", tmpstr);
2719 fprintf(stderr, "\n");
2723 /* Build the ACF according to acType */
2728 #ifdef HAVE_NN_LOOPS
2729 /* Here we're using the estimated energy for the hydrogen bonds. */
2732 #pragma omp parallel \
2733 private(i, j, k, nh, E, rhbex, thisThread) \
2737 thisThread = gmx_omp_get_thread_num();
2741 memset(rhbex, 0, n2*sizeof(real)); /* Trust no-one, not even malloc()! */
2744 #pragma omp for schedule (dynamic)
2745 for (i = 0; i < hb->d.nrd; i++) /* loop over donors */
2749 #pragma omp critical
2751 dondata[thisThread] = i;
2752 parallel_print(dondata, nThreads);
2757 fprintf(stderr, "\r %i", i);
2760 for (j = 0; j < hb->a.nra; j++) /* loop over acceptors */
2762 for (nh = 0; nh < hb->d.nhydro[i]; nh++) /* loop over donors' hydrogens */
2764 E = hb->hbE.E[i][j][nh];
2767 for (k = 0; k < nframes; k++)
2769 if (E[k] != NONSENSE_E)
2771 rhbex[k] = (real)E[k];
2775 low_do_autocorr(NULL, oenv, NULL, nframes, 1, -1, &(rhbex), hb->time[1]-hb->time[0],
2776 eacNormal, 1, FALSE, bNorm, FALSE, 0, -1, 0, 1);
2777 #pragma omp critical
2779 for (k = 0; (k < nn); k++)
2796 normalizeACF(ct, NULL, 0, nn);
2798 snew(timedouble, nn);
2799 for (j = 0; j < nn; j++)
2801 timedouble[j] = (double)(hb->time[j]);
2802 ctdouble[j] = (double)(ct[j]);
2805 /* Remove ballistic term */
2806 /* Ballistic component removal and fitting to the reversible geminate recombination model
2807 * will be taken out for the time being. First of all, one can remove the ballistic
2808 * component with g_analyze afterwards. Secondly, and more importantly, there are still
2809 * problems with the robustness of the fitting to the model. More work is needed.
2810 * A third reason is that we're currently using gsl for this and wish to reduce dependence
2811 * on external libraries. There are Levenberg-Marquardt and nsimplex solvers that come with
2812 * a BSD-licence that can do the job.
2814 * - Erik Marklund, June 18 2010.
2816 /* if (params->ballistic/params->tDelta >= params->nExpFit*2+1) */
2817 /* takeAwayBallistic(ctdouble, timedouble, nn, params->ballistic, params->nExpFit, params->bDt); */
2819 /* printf("\nNumber of data points is less than the number of parameters to fit\n." */
2820 /* "The system is underdetermined, hence no ballistic term can be found.\n\n"); */
2822 fp = xvgropen(fn, "Hydrogen Bond Autocorrelation", output_env_get_xvgr_tlabel(oenv), "C(t)");
2823 xvgr_legend(fp, asize(legNN), legNN);
2825 for (j = 0; (j < nn); j++)
2827 fprintf(fp, "%10g %10g %10g\n",
2828 hb->time[j]-hb->time[0],
2836 #endif /* HAVE_NN_LOOPS */
2837 break; /* case AC_NN */
2841 memset(ct, 0, 2*n2*sizeof(real));
2843 fprintf(stderr, "Donor:\n");
2846 #define __ACDATA p_ct
2849 #pragma omp parallel \
2850 private(i, k, nh, hbh, pHist, h, g, n0, nf, np, j, m, \
2851 pfound, poff, rHbExGem, p, ihb, mMax, \
2854 { /* ########## THE START OF THE ENORMOUS PARALLELIZED BLOCK! ########## */
2857 thisThread = gmx_omp_get_thread_num();
2858 snew(h, hb->maxhydro);
2859 snew(g, hb->maxhydro);
2866 memset(p_ct, 0, 2*n2*sizeof(real));
2868 /* I'm using a chunk size of 1, since I expect \
2869 * the overhead to be really small compared \
2870 * to the actual calculations \ */
2871 #pragma omp for schedule(dynamic,1) nowait
2872 for (i = 0; i < hb->d.nrd; i++)
2877 #pragma omp critical
2879 dondata[thisThread] = i;
2880 parallel_print(dondata, nThreads);
2885 fprintf(stderr, "\r %i", i);
2887 for (k = 0; k < hb->a.nra; k++)
2889 for (nh = 0; nh < ((bMerge || bContact) ? 1 : hb->d.nhydro[i]); nh++)
2891 hbh = hb->hbmap[i][k];
2894 /* Note that if hb->per->gemtype==gemDD, then distances will be stored in
2895 * hb->hbmap[d][a].h array anyway, because the contact flag will be set.
2896 * hence, it's only with the gemAD mode that hb->hbmap[d][a].g will be used. */
2897 pHist = &(hb->per->pHist[i][k]);
2898 if (ISHB(hbh->history[nh]) && pHist->len != 0)
2903 g[nh] = hb->per->gemtype == gemAD ? hbh->g[nh] : NULL;
2907 /* count the number of periodic shifts encountered and store
2908 * them in separate arrays. */
2910 for (j = 0; j < pHist->len; j++)
2913 for (m = 0; m <= np; m++)
2915 if (m == np) /* p not recognized in list. Add it and set up new array. */
2918 if (np > hb->per->nper)
2920 gmx_fatal(FARGS, "Too many pshifts. Something's utterly wrong here.");
2922 if (m >= mMax) /* Extend the arrays.
2923 * Doing it like this, using mMax to keep track of the sizes,
2924 * eleviates the need for freeing and re-allocating the arrays
2925 * when taking on the next donor-acceptor pair */
2928 srenew(pfound, np); /* The list of found periodic shifts. */
2929 srenew(rHbExGem, np); /* The hb existence functions (-aver_hb). */
2930 snew(rHbExGem[m], 2*n2);
2935 if (rHbExGem != NULL && rHbExGem[m] != NULL)
2937 /* This must be done, as this array was most likey
2938 * used to store stuff in some previous iteration. */
2939 memset(rHbExGem[m], 0, (sizeof(real)) * (2*n2));
2943 fprintf(stderr, "rHbExGem not initialized! m = %i\n", m);
2955 } /* m: Loop over found shifts */
2956 } /* j: Loop over shifts */
2958 /* Now unpack and disentangle the existence funtions. */
2959 for (j = 0; j < nf; j++)
2966 * pfound: list of periodic shifts found for this pair.
2967 * poff: list of frame offsets; that is, the first
2968 * frame a hbond has a particular periodic shift. */
2969 p = getPshift(*pHist, j+n0);
2972 for (m = 0; m < np; m++)
2980 gmx_fatal(FARGS, "Shift not found, but must be there.");
2984 ihb = is_hb(h[nh], j) || ((hb->per->gemtype != gemAD || j == 0) ? FALSE : is_hb(g[nh], j));
2989 poff[m] = j; /* Here's where the first hbond with shift p is,
2990 * relative to the start of h[0].*/
2994 gmx_fatal(FARGS, "j<poff[m]");
2996 rHbExGem[m][j-poff[m]] += 1;
3001 /* Now, build ac. */
3002 for (m = 0; m < np; m++)
3004 if (rHbExGem[m][0] > 0 && n0+poff[m] < nn /* && m==0 */)
3006 low_do_autocorr(NULL, oenv, NULL, nframes, 1, -1, &(rHbExGem[m]), hb->time[1]-hb->time[0],
3007 eacNormal, 1, FALSE, bNorm, FALSE, 0, -1, 0);
3008 for (j = 0; (j < nn); j++)
3010 __ACDATA[j] += rHbExGem[m][j];
3013 } /* Building of ac. */
3016 } /* hydrogen loop */
3017 } /* acceptor loop */
3020 for (m = 0; m <= mMax; m++)
3033 #pragma omp critical
3035 for (i = 0; i < nn; i++)
3043 } /* ########## THE END OF THE ENORMOUS PARALLELIZED BLOCK ########## */
3049 normalizeACF(ct, NULL, 0, nn);
3051 fprintf(stderr, "\n\nACF successfully calculated.\n");
3053 /* Use this part to fit to geminate recombination - JCP 129, 84505 (2008) */
3056 snew(timedouble, nn);
3059 for (j = 0; j < nn; j++)
3061 timedouble[j] = (double)(hb->time[j]);
3062 ctdouble[j] = (double)(ct[j]);
3065 /* Remove ballistic term */
3066 /* Ballistic component removal and fitting to the reversible geminate recombination model
3067 * will be taken out for the time being. First of all, one can remove the ballistic
3068 * component with g_analyze afterwards. Secondly, and more importantly, there are still
3069 * problems with the robustness of the fitting to the model. More work is needed.
3070 * A third reason is that we're currently using gsl for this and wish to reduce dependence
3071 * on external libraries. There are Levenberg-Marquardt and nsimplex solvers that come with
3072 * a BSD-licence that can do the job.
3074 * - Erik Marklund, June 18 2010.
3076 /* if (bBallistic) { */
3077 /* if (params->ballistic/params->tDelta >= params->nExpFit*2+1) */
3078 /* takeAwayBallistic(ctdouble, timedouble, nn, params->ballistic, params->nExpFit, params->bDt); */
3080 /* printf("\nNumber of data points is less than the number of parameters to fit\n." */
3081 /* "The system is underdetermined, hence no ballistic term can be found.\n\n"); */
3084 /* fitGemRecomb(ctdouble, timedouble, &fittedct, nn, params); */
3089 fp = xvgropen(fn, "Contact Autocorrelation", output_env_get_xvgr_tlabel(oenv), "C(t)", oenv);
3093 fp = xvgropen(fn, "Hydrogen Bond Autocorrelation", output_env_get_xvgr_tlabel(oenv), "C(t)", oenv);
3095 xvgr_legend(fp, asize(legGem), (const char**)legGem, oenv);
3097 for (j = 0; (j < nn); j++)
3099 fprintf(fp, "%10g %10g", hb->time[j]-hb->time[0], ct[j]);
3102 fprintf(fp, " %10g", ctdouble[j]);
3106 fprintf(fp, " %10g", fittedct[j]);
3117 break; /* case AC_GEM */
3130 for (i = 0; (i < hb->d.nrd); i++)
3132 for (k = 0; (k < hb->a.nra); k++)
3135 hbh = hb->hbmap[i][k];
3139 if (bMerge || bContact)
3141 if (ISHB(hbh->history[0]))
3150 for (m = 0; (m < hb->maxhydro); m++)
3152 if (bContact ? ISDIST(hbh->history[m]) : ISHB(hbh->history[m]))
3154 g[nhydro] = hbh->g[m];
3155 h[nhydro] = hbh->h[m];
3162 for (nh = 0; (nh < nhydro); nh++)
3164 int nrint = bContact ? hb->nrdist : hb->nrhb;
3165 if ((((nhbonds+1) % 10) == 0) || (nhbonds+1 == nrint))
3167 fprintf(stderr, "\rACF %d/%d", nhbonds+1, nrint);
3170 for (j = 0; (j < nframes); j++)
3172 /* Changed '<' into '<=' below, just like I did in
3173 the hbm-output-loop in the gmx_hbond() block.
3174 - Erik Marklund, May 31, 2006 */
3177 ihb = is_hb(h[nh], j);
3178 idist = is_hb(g[nh], j);
3185 /* For contacts: if a second cut-off is provided, use it,
3186 * otherwise use g(t) = 1-h(t) */
3187 if (!R2 && bContact)
3193 gt[j] = idist*(1-ihb);
3200 /* The autocorrelation function is normalized after summation only */
3201 low_do_autocorr(NULL, oenv, NULL, nframes, 1, -1, &rhbex, hb->time[1]-hb->time[0],
3202 eacNormal, 1, FALSE, bNorm, FALSE, 0, -1, 0);
3204 /* Cross correlation analysis for thermodynamics */
3205 for (j = nframes; (j < n2); j++)
3211 cross_corr(n2, ht, gt, dght);
3213 for (j = 0; (j < nn); j++)
3222 fprintf(stderr, "\n");
3225 normalizeACF(ct, ght, nhb, nn);
3227 /* Determine tail value for statistics */
3230 for (j = nn/2; (j < nn); j++)
3233 tail2 += ct[j]*ct[j];
3235 tail /= (nn - nn/2);
3236 tail2 /= (nn - nn/2);
3237 dtail = sqrt(tail2-tail*tail);
3239 /* Check whether the ACF is long enough */
3242 printf("\nWARNING: Correlation function is probably not long enough\n"
3243 "because the standard deviation in the tail of C(t) > %g\n"
3244 "Tail value (average C(t) over second half of acf): %g +/- %g\n",
3247 for (j = 0; (j < nn); j++)
3250 ct[j] = (cct[j]-tail)/(1-tail);
3252 /* Compute negative derivative k(t) = -dc(t)/dt */
3253 compute_derivative(nn, hb->time, ct, kt);
3254 for (j = 0; (j < nn); j++)
3262 fp = xvgropen(fn, "Contact Autocorrelation", output_env_get_xvgr_tlabel(oenv), "C(t)", oenv);
3266 fp = xvgropen(fn, "Hydrogen Bond Autocorrelation", output_env_get_xvgr_tlabel(oenv), "C(t)", oenv);
3268 xvgr_legend(fp, asize(legLuzar), legLuzar, oenv);
3271 for (j = 0; (j < nn); j++)
3273 fprintf(fp, "%10g %10g %10g %10g %10g\n",
3274 hb->time[j]-hb->time[0], ct[j], cct[j], ght[j], kt[j]);
3278 analyse_corr(nn, hb->time, ct, ght, kt, NULL, NULL, NULL,
3279 fit_start, temp, smooth_tail_start, oenv);
3281 do_view(oenv, fn, NULL);
3293 break; /* case AC_LUZAR */
3296 gmx_fatal(FARGS, "Unrecognized type of ACF-calulation. acType = %i.", acType);
3297 } /* switch (acType) */
3300 static void init_hbframe(t_hbdata *hb, int nframes, real t)
3304 hb->time[nframes] = t;
3305 hb->nhb[nframes] = 0;
3306 hb->ndist[nframes] = 0;
3307 for (i = 0; (i < max_hx); i++)
3309 hb->nhx[nframes][i] = 0;
3311 /* Loop invalidated */
3312 if (hb->bHBmap && 0)
3314 for (i = 0; (i < hb->d.nrd); i++)
3316 for (j = 0; (j < hb->a.nra); j++)
3318 for (m = 0; (m < hb->maxhydro); m++)
3320 if (hb->hbmap[i][j] && hb->hbmap[i][j]->h[m])
3322 set_hb(hb, i, m, j, nframes, HB_NO);
3328 /*set_hb(hb->hbmap[i][j]->h[m],nframes-hb->hbmap[i][j]->n0,HB_NO);*/
3331 static void analyse_donor_props(const char *fn, t_hbdata *hb, int nframes, real t,
3332 const output_env_t oenv)
3334 static FILE *fp = NULL;
3335 const char *leg[] = { "Nbound", "Nfree" };
3336 int i, j, k, nbound, nb, nhtot;
3344 // TODO: This file is never closed...
3345 fp = xvgropen(fn, "Donor properties", output_env_get_xvgr_tlabel(oenv), "Number", oenv);
3346 xvgr_legend(fp, asize(leg), leg, oenv);
3350 for (i = 0; (i < hb->d.nrd); i++)
3352 for (k = 0; (k < hb->d.nhydro[i]); k++)
3356 for (j = 0; (j < hb->a.nra) && (nb == 0); j++)
3358 if (hb->hbmap[i][j] && hb->hbmap[i][j]->h[k] &&
3359 is_hb(hb->hbmap[i][j]->h[k], nframes))
3367 fprintf(fp, "%10.3e %6d %6d\n", t, nbound, nhtot-nbound);
3370 static void dump_hbmap(t_hbdata *hb,
3371 int nfile, t_filenm fnm[], gmx_bool bTwo,
3372 gmx_bool bContact, int isize[], int *index[], char *grpnames[],
3376 int ddd, hhh, aaa, i, j, k, m, grp;
3377 char ds[32], hs[32], as[32];
3380 fp = opt2FILE("-hbn", nfile, fnm, "w");
3381 if (opt2bSet("-g", nfile, fnm))
3383 fplog = gmx_ffopen(opt2fn("-g", nfile, fnm), "w");
3384 fprintf(fplog, "# %10s %12s %12s\n", "Donor", "Hydrogen", "Acceptor");
3390 for (grp = gr0; grp <= (bTwo ? gr1 : gr0); grp++)
3392 fprintf(fp, "[ %s ]", grpnames[grp]);
3393 for (i = 0; i < isize[grp]; i++)
3395 fprintf(fp, (i%15) ? " " : "\n");
3396 fprintf(fp, " %4d", index[grp][i]+1);
3400 Added -contact support below.
3401 - Erik Marklund, May 29, 2006
3405 fprintf(fp, "[ donors_hydrogens_%s ]\n", grpnames[grp]);
3406 for (i = 0; (i < hb->d.nrd); i++)
3408 if (hb->d.grp[i] == grp)
3410 for (j = 0; (j < hb->d.nhydro[i]); j++)
3412 fprintf(fp, " %4d %4d", hb->d.don[i]+1,
3413 hb->d.hydro[i][j]+1);
3419 fprintf(fp, "[ acceptors_%s ]", grpnames[grp]);
3420 for (i = 0; (i < hb->a.nra); i++)
3422 if (hb->a.grp[i] == grp)
3424 fprintf(fp, (i%15 && !first) ? " " : "\n");
3425 fprintf(fp, " %4d", hb->a.acc[i]+1);
3434 fprintf(fp, bContact ? "[ contacts_%s-%s ]\n" :
3435 "[ hbonds_%s-%s ]\n", grpnames[0], grpnames[1]);
3439 fprintf(fp, bContact ? "[ contacts_%s ]" : "[ hbonds_%s ]\n", grpnames[0]);
3442 for (i = 0; (i < hb->d.nrd); i++)
3445 for (k = 0; (k < hb->a.nra); k++)
3448 for (m = 0; (m < hb->d.nhydro[i]); m++)
3450 if (hb->hbmap[i][k] && ISHB(hb->hbmap[i][k]->history[m]))
3452 sprintf(ds, "%s", mkatomname(atoms, ddd));
3453 sprintf(as, "%s", mkatomname(atoms, aaa));
3456 fprintf(fp, " %6d %6d\n", ddd+1, aaa+1);
3459 fprintf(fplog, "%12s %12s\n", ds, as);
3464 hhh = hb->d.hydro[i][m];
3465 sprintf(hs, "%s", mkatomname(atoms, hhh));
3466 fprintf(fp, " %6d %6d %6d\n", ddd+1, hhh+1, aaa+1);
3469 fprintf(fplog, "%12s %12s %12s\n", ds, hs, as);
3483 /* sync_hbdata() updates the parallel t_hbdata p_hb using hb as template.
3484 * It mimics add_frames() and init_frame() to some extent. */
3485 static void sync_hbdata(t_hbdata *p_hb, int nframes)
3488 if (nframes >= p_hb->max_frames)
3490 p_hb->max_frames += 4096;
3491 srenew(p_hb->nhb, p_hb->max_frames);
3492 srenew(p_hb->ndist, p_hb->max_frames);
3493 srenew(p_hb->n_bound, p_hb->max_frames);
3494 srenew(p_hb->nhx, p_hb->max_frames);
3497 srenew(p_hb->danr, p_hb->max_frames);
3499 memset(&(p_hb->nhb[nframes]), 0, sizeof(int) * (p_hb->max_frames-nframes));
3500 memset(&(p_hb->ndist[nframes]), 0, sizeof(int) * (p_hb->max_frames-nframes));
3501 p_hb->nhb[nframes] = 0;
3502 p_hb->ndist[nframes] = 0;
3505 p_hb->nframes = nframes;
3508 /* p_hb->nhx[nframes][i] */
3510 memset(&(p_hb->nhx[nframes]), 0, sizeof(int)*max_hx); /* zero the helix count for this frame */
3512 /* hb->per will remain constant througout the frame loop,
3513 * even though the data its members point to will change,
3514 * hence no need for re-syncing. */
3517 int gmx_hbond(int argc, char *argv[])
3519 const char *desc[] = {
3520 "[THISMODULE] computes and analyzes hydrogen bonds. Hydrogen bonds are",
3521 "determined based on cutoffs for the angle Hydrogen - Donor - Acceptor",
3522 "(zero is extended) and the distance Donor - Acceptor",
3523 "(or Hydrogen - Acceptor using [TT]-noda[tt]).",
3524 "OH and NH groups are regarded as donors, O is an acceptor always,",
3525 "N is an acceptor by default, but this can be switched using",
3526 "[TT]-nitacc[tt]. Dummy hydrogen atoms are assumed to be connected",
3527 "to the first preceding non-hydrogen atom.[PAR]",
3529 "You need to specify two groups for analysis, which must be either",
3530 "identical or non-overlapping. All hydrogen bonds between the two",
3531 "groups are analyzed.[PAR]",
3533 "If you set [TT]-shell[tt], you will be asked for an additional index group",
3534 "which should contain exactly one atom. In this case, only hydrogen",
3535 "bonds between atoms within the shell distance from the one atom are",
3538 "With option -ac, rate constants for hydrogen bonding can be derived with the model of Luzar and Chandler",
3539 "(Nature 394, 1996; J. Chem. Phys. 113:23, 2000) or that of Markovitz and Agmon (J. Chem. Phys 129, 2008).",
3540 "If contact kinetics are analyzed by using the -contact option, then",
3541 "n(t) can be defined as either all pairs that are not within contact distance r at time t",
3542 "(corresponding to leaving the -r2 option at the default value 0) or all pairs that",
3543 "are within distance r2 (corresponding to setting a second cut-off value with option -r2).",
3544 "See mentioned literature for more details and definitions."
3547 /* "It is also possible to analyse specific hydrogen bonds with",
3548 "[TT]-sel[tt]. This index file must contain a group of atom triplets",
3549 "Donor Hydrogen Acceptor, in the following way:[PAR]",
3557 "Note that the triplets need not be on separate lines.",
3558 "Each atom triplet specifies a hydrogen bond to be analyzed,",
3559 "note also that no check is made for the types of atoms.[PAR]",
3561 "[BB]Output:[bb][BR]",
3562 "[TT]-num[tt]: number of hydrogen bonds as a function of time.[BR]",
3563 "[TT]-ac[tt]: average over all autocorrelations of the existence",
3564 "functions (either 0 or 1) of all hydrogen bonds.[BR]",
3565 "[TT]-dist[tt]: distance distribution of all hydrogen bonds.[BR]",
3566 "[TT]-ang[tt]: angle distribution of all hydrogen bonds.[BR]",
3567 "[TT]-hx[tt]: the number of n-n+i hydrogen bonds as a function of time",
3568 "where n and n+i stand for residue numbers and i ranges from 0 to 6.",
3569 "This includes the n-n+3, n-n+4 and n-n+5 hydrogen bonds associated",
3570 "with helices in proteins.[BR]",
3571 "[TT]-hbn[tt]: all selected groups, donors, hydrogens and acceptors",
3572 "for selected groups, all hydrogen bonded atoms from all groups and",
3573 "all solvent atoms involved in insertion.[BR]",
3574 "[TT]-hbm[tt]: existence matrix for all hydrogen bonds over all",
3575 "frames, this also contains information on solvent insertion",
3576 "into hydrogen bonds. Ordering is identical to that in [TT]-hbn[tt]",
3578 "[TT]-dan[tt]: write out the number of donors and acceptors analyzed for",
3579 "each timeframe. This is especially useful when using [TT]-shell[tt].[BR]",
3580 "[TT]-nhbdist[tt]: compute the number of HBonds per hydrogen in order to",
3581 "compare results to Raman Spectroscopy.",
3583 "Note: options [TT]-ac[tt], [TT]-life[tt], [TT]-hbn[tt] and [TT]-hbm[tt]",
3584 "require an amount of memory proportional to the total numbers of donors",
3585 "times the total number of acceptors in the selected group(s)."
3588 static real acut = 30, abin = 1, rcut = 0.35, r2cut = 0, rbin = 0.005, rshell = -1;
3589 static real maxnhb = 0, fit_start = 1, fit_end = 60, temp = 298.15, smooth_tail_start = -1, D = -1;
3590 static gmx_bool bNitAcc = TRUE, bDA = TRUE, bMerge = TRUE;
3591 static int nDump = 0, nFitPoints = 100;
3592 static int nThreads = 0, nBalExp = 4;
3594 static gmx_bool bContact = FALSE, bBallistic = FALSE, bGemFit = FALSE;
3595 static real logAfterTime = 10, gemBallistic = 0.2; /* ps */
3596 static const char *NNtype[] = {NULL, "none", "binary", "oneOverR3", "dipole", NULL};
3600 { "-a", FALSE, etREAL, {&acut},
3601 "Cutoff angle (degrees, Hydrogen - Donor - Acceptor)" },
3602 { "-r", FALSE, etREAL, {&rcut},
3603 "Cutoff radius (nm, X - Acceptor, see next option)" },
3604 { "-da", FALSE, etBOOL, {&bDA},
3605 "Use distance Donor-Acceptor (if TRUE) or Hydrogen-Acceptor (FALSE)" },
3606 { "-r2", FALSE, etREAL, {&r2cut},
3607 "Second cutoff radius. Mainly useful with [TT]-contact[tt] and [TT]-ac[tt]"},
3608 { "-abin", FALSE, etREAL, {&abin},
3609 "Binwidth angle distribution (degrees)" },
3610 { "-rbin", FALSE, etREAL, {&rbin},
3611 "Binwidth distance distribution (nm)" },
3612 { "-nitacc", FALSE, etBOOL, {&bNitAcc},
3613 "Regard nitrogen atoms as acceptors" },
3614 { "-contact", FALSE, etBOOL, {&bContact},
3615 "Do not look for hydrogen bonds, but merely for contacts within the cut-off distance" },
3616 { "-shell", FALSE, etREAL, {&rshell},
3617 "when > 0, only calculate hydrogen bonds within # nm shell around "
3619 { "-fitstart", FALSE, etREAL, {&fit_start},
3620 "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]" },
3621 { "-fitend", FALSE, etREAL, {&fit_end},
3622 "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])" },
3623 { "-temp", FALSE, etREAL, {&temp},
3624 "Temperature (K) for computing the Gibbs energy corresponding to HB breaking and reforming" },
3625 { "-smooth", FALSE, etREAL, {&smooth_tail_start},
3626 "If >= 0, the tail of the ACF will be smoothed by fitting it to an exponential function: y = A exp(-x/[GRK]tau[grk])" },
3627 { "-dump", FALSE, etINT, {&nDump},
3628 "Dump the first N hydrogen bond ACFs in a single [TT].xvg[tt] file for debugging" },
3629 { "-max_hb", FALSE, etREAL, {&maxnhb},
3630 "Theoretical maximum number of hydrogen bonds used for normalizing HB autocorrelation function. Can be useful in case the program estimates it wrongly" },
3631 { "-merge", FALSE, etBOOL, {&bMerge},
3632 "H-bonds between the same donor and acceptor, but with different hydrogen are treated as a single H-bond. Mainly important for the ACF." },
3633 { "-geminate", FALSE, etENUM, {gemType},
3634 "HIDDENUse reversible geminate recombination for the kinetics/thermodynamics calclations. See Markovitch et al., J. Chem. Phys 129, 084505 (2008) for details."},
3635 { "-diff", FALSE, etREAL, {&D},
3636 "HIDDENDffusion coefficient to use in the reversible geminate recombination kinetic model. If negative, then it will be fitted to the ACF along with ka and kd."},
3638 { "-nthreads", FALSE, etINT, {&nThreads},
3639 "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)"},
3642 const char *bugs[] = {
3643 "The option [TT]-sel[tt] that used to work on selected hbonds is out of order, and therefore not available for the time being."
3646 { efTRX, "-f", NULL, ffREAD },
3647 { efTPR, NULL, NULL, ffREAD },
3648 { efNDX, NULL, NULL, ffOPTRD },
3649 /* { efNDX, "-sel", "select", ffOPTRD },*/
3650 { efXVG, "-num", "hbnum", ffWRITE },
3651 { efLOG, "-g", "hbond", ffOPTWR },
3652 { efXVG, "-ac", "hbac", ffOPTWR },
3653 { efXVG, "-dist", "hbdist", ffOPTWR },
3654 { efXVG, "-ang", "hbang", ffOPTWR },
3655 { efXVG, "-hx", "hbhelix", ffOPTWR },
3656 { efNDX, "-hbn", "hbond", ffOPTWR },
3657 { efXPM, "-hbm", "hbmap", ffOPTWR },
3658 { efXVG, "-don", "donor", ffOPTWR },
3659 { efXVG, "-dan", "danum", ffOPTWR },
3660 { efXVG, "-life", "hblife", ffOPTWR },
3661 { efXVG, "-nhbdist", "nhbdist", ffOPTWR }
3664 #define NFILE asize(fnm)
3666 char hbmap [HB_NR] = { ' ', 'o', '-', '*' };
3667 const char *hbdesc[HB_NR] = { "None", "Present", "Inserted", "Present & Inserted" };
3668 t_rgb hbrgb [HB_NR] = { {1, 1, 1}, {1, 0, 0}, {0, 0, 1}, {1, 0, 1} };
3670 t_trxstatus *status;
3675 int npargs, natoms, nframes = 0, shatom;
3681 real t, ccut, dist = 0.0, ang = 0.0;
3682 double max_nhb, aver_nhb, aver_dist;
3683 int h = 0, i = 0, j, k = 0, l, start, end, id, ja, ogrp, nsel;
3685 int xj, yj, zj, aj, xjj, yjj, zjj;
3686 int xk, yk, zk, ak, xkk, ykk, zkk;
3687 gmx_bool bSelected, bHBmap, bStop, bTwo, was, bBox, bTric;
3688 int *adist, *rdist, *aptr, *rprt;
3689 int grp, nabin, nrbin, bin, resdist, ihb;
3691 t_hbdata *hb, *hbptr;
3692 FILE *fp, *fpins = NULL, *fpnhb = NULL;
3694 t_ncell *icell, *jcell, *kcell;
3696 unsigned char *datable;
3701 int ii, jj, hh, actual_nThreads;
3703 gmx_bool bGem, bNN, bParallel;
3704 t_gemParams *params = NULL;
3705 gmx_bool bEdge_yjj, bEdge_xjj, bOMP;
3707 t_hbdata **p_hb = NULL; /* one per thread, then merge after the frame loop */
3708 int **p_adist = NULL, **p_rdist = NULL; /* a histogram for each thread. */
3717 ppa = add_acf_pargs(&npargs, pa);
3719 if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT, NFILE, fnm, npargs,
3720 ppa, asize(desc), desc, asize(bugs), bugs, &oenv))
3725 /* NN-loop? If so, what estimator to use ?*/
3727 /* Outcommented for now DvdS 2010-07-13
3728 while (NN < NN_NR && gmx_strcasecmp(NNtype[0], NNtype[NN])!=0)
3731 gmx_fatal(FARGS, "Invalid NN-loop type.");
3734 for (i = 2; bNN == FALSE && i < NN_NR; i++)
3736 bNN = bNN || NN == i;
3739 if (NN > NN_NONE && bMerge)
3744 /* geminate recombination? If so, which flavor? */
3746 while (gemmode < gemNR && gmx_strcasecmp(gemType[0], gemType[gemmode]) != 0)
3750 if (gemmode == gemNR)
3752 gmx_fatal(FARGS, "Invalid recombination type.");
3756 for (i = 2; bGem == FALSE && i < gemNR; i++)
3758 bGem = bGem || gemmode == i;
3763 printf("Geminate recombination: %s\n", gemType[gemmode]);
3766 if (gemmode != gemDD)
3768 printf("Turning off -contact option...\n");
3774 if (gemmode == gemDD)
3776 printf("Turning on -contact option...\n");
3782 if (gemmode == gemAA)
3784 printf("Turning off -merge option...\n");
3790 if (gemmode != gemAA)
3792 printf("Turning on -merge option...\n");
3800 ccut = cos(acut*DEG2RAD);
3806 gmx_fatal(FARGS, "Can not analyze selected contacts.");
3810 gmx_fatal(FARGS, "Can not analyze contact between H and A: turn off -noda");
3814 /* Initiate main data structure! */
3815 bHBmap = (opt2bSet("-ac", NFILE, fnm) ||
3816 opt2bSet("-life", NFILE, fnm) ||
3817 opt2bSet("-hbn", NFILE, fnm) ||
3818 opt2bSet("-hbm", NFILE, fnm) ||
3821 if (opt2bSet("-nhbdist", NFILE, fnm))
3823 const char *leg[MAXHH+1] = { "0 HBs", "1 HB", "2 HBs", "3 HBs", "Total" };
3824 fpnhb = xvgropen(opt2fn("-nhbdist", NFILE, fnm),
3825 "Number of donor-H with N HBs", output_env_get_xvgr_tlabel(oenv), "N", oenv);
3826 xvgr_legend(fpnhb, asize(leg), leg, oenv);
3829 hb = mk_hbdata(bHBmap, opt2bSet("-dan", NFILE, fnm), bMerge || bContact, bGem, gemmode);
3832 read_tpx_top(ftp2fn(efTPR, NFILE, fnm), &ir, box, &natoms, NULL, NULL, NULL, &top);
3834 snew(grpnames, grNR);
3837 /* Make Donor-Acceptor table */
3838 snew(datable, top.atoms.nr);
3839 gen_datable(index[0], isize[0], datable, top.atoms.nr);
3843 /* analyze selected hydrogen bonds */
3844 printf("Select group with selected atoms:\n");
3845 get_index(&(top.atoms), opt2fn("-sel", NFILE, fnm),
3846 1, &nsel, index, grpnames);
3849 gmx_fatal(FARGS, "Number of atoms in group '%s' not a multiple of 3\n"
3850 "and therefore cannot contain triplets of "
3851 "Donor-Hydrogen-Acceptor", grpnames[0]);
3855 for (i = 0; (i < nsel); i += 3)
3857 int dd = index[0][i];
3858 int aa = index[0][i+2];
3859 /* int */ hh = index[0][i+1];
3860 add_dh (&hb->d, dd, hh, i, datable);
3861 add_acc(&hb->a, aa, i);
3862 /* Should this be here ? */
3863 snew(hb->d.dptr, top.atoms.nr);
3864 snew(hb->a.aptr, top.atoms.nr);
3865 add_hbond(hb, dd, aa, hh, gr0, gr0, 0, bMerge, 0, bContact, peri);
3867 printf("Analyzing %d selected hydrogen bonds from '%s'\n",
3868 isize[0], grpnames[0]);
3872 /* analyze all hydrogen bonds: get group(s) */
3873 printf("Specify 2 groups to analyze:\n");
3874 get_index(&(top.atoms), ftp2fn_null(efNDX, NFILE, fnm),
3875 2, isize, index, grpnames);
3877 /* check if we have two identical or two non-overlapping groups */
3878 bTwo = isize[0] != isize[1];
3879 for (i = 0; (i < isize[0]) && !bTwo; i++)
3881 bTwo = index[0][i] != index[1][i];
3885 printf("Checking for overlap in atoms between %s and %s\n",
3886 grpnames[0], grpnames[1]);
3887 for (i = 0; i < isize[1]; i++)
3889 if (ISINGRP(datable[index[1][i]]))
3891 gmx_fatal(FARGS, "Partial overlap between groups '%s' and '%s'",
3892 grpnames[0], grpnames[1]);
3896 printf("Checking for overlap in atoms between %s and %s\n",
3897 grpnames[0],grpnames[1]);
3898 for (i=0; i<isize[0]; i++)
3899 for (j=0; j<isize[1]; j++)
3900 if (index[0][i] == index[1][j])
3901 gmx_fatal(FARGS,"Partial overlap between groups '%s' and '%s'",
3902 grpnames[0],grpnames[1]);
3907 printf("Calculating %s "
3908 "between %s (%d atoms) and %s (%d atoms)\n",
3909 bContact ? "contacts" : "hydrogen bonds",
3910 grpnames[0], isize[0], grpnames[1], isize[1]);
3914 fprintf(stderr, "Calculating %s in %s (%d atoms)\n",
3915 bContact ? "contacts" : "hydrogen bonds", grpnames[0], isize[0]);
3920 /* search donors and acceptors in groups */
3921 snew(datable, top.atoms.nr);
3922 for (i = 0; (i < grNR); i++)
3924 if ( ((i == gr0) && !bSelected ) ||
3925 ((i == gr1) && bTwo ))
3927 gen_datable(index[i], isize[i], datable, top.atoms.nr);
3930 search_acceptors(&top, isize[i], index[i], &hb->a, i,
3931 bNitAcc, TRUE, (bTwo && (i == gr0)) || !bTwo, datable);
3932 search_donors (&top, isize[i], index[i], &hb->d, i,
3933 TRUE, (bTwo && (i == gr1)) || !bTwo, datable);
3937 search_acceptors(&top, isize[i], index[i], &hb->a, i, bNitAcc, FALSE, TRUE, datable);
3938 search_donors (&top, isize[i], index[i], &hb->d, i, FALSE, TRUE, datable);
3942 clear_datable_grp(datable, top.atoms.nr);
3947 printf("Found %d donors and %d acceptors\n", hb->d.nrd, hb->a.nra);
3949 snew(donors[gr0D], dons[gr0D].nrd);*/
3953 printf("Making hbmap structure...");
3954 /* Generate hbond data structure */
3959 #ifdef HAVE_NN_LOOPS
3968 printf("Making per structure...");
3969 /* Generate hbond data structure */
3976 if (hb->d.nrd + hb->a.nra == 0)
3978 printf("No Donors or Acceptors found\n");
3985 printf("No Donors found\n");
3990 printf("No Acceptors found\n");
3996 gmx_fatal(FARGS, "Nothing to be done");
4005 /* get index group with atom for shell */
4008 printf("Select atom for shell (1 atom):\n");
4009 get_index(&(top.atoms), ftp2fn_null(efNDX, NFILE, fnm),
4010 1, &shisz, &shidx, &shgrpnm);
4013 printf("group contains %d atoms, should be 1 (one)\n", shisz);
4018 printf("Will calculate hydrogen bonds within a shell "
4019 "of %g nm around atom %i\n", rshell, shatom+1);
4022 /* Analyze trajectory */
4023 natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box);
4024 if (natoms > top.atoms.nr)
4026 gmx_fatal(FARGS, "Topology (%d atoms) does not match trajectory (%d atoms)",
4027 top.atoms.nr, natoms);
4030 bBox = ir.ePBC != epbcNONE;
4031 grid = init_grid(bBox, box, (rcut > r2cut) ? rcut : r2cut, ngrid);
4034 snew(adist, nabin+1);
4035 snew(rdist, nrbin+1);
4039 gmx_fatal(FARGS, "Can't do geminate recombination without periodic box.");
4045 #define __ADIST adist
4046 #define __RDIST rdist
4048 #else /* GMX_OPENMP ================================================== \
4049 * Set up the OpenMP stuff, |
4050 * like the number of threads and such |
4051 * Also start the parallel loop. |
4053 #define __ADIST p_adist[threadNr]
4054 #define __RDIST p_rdist[threadNr]
4055 #define __HBDATA p_hb[threadNr]
4059 bParallel = !bSelected;
4063 actual_nThreads = min((nThreads <= 0) ? INT_MAX : nThreads, gmx_omp_get_max_threads());
4065 gmx_omp_set_num_threads(actual_nThreads);
4066 printf("Frame loop parallelized with OpenMP using %i threads.\n", actual_nThreads);
4071 actual_nThreads = 1;
4074 snew(p_hb, actual_nThreads);
4075 snew(p_adist, actual_nThreads);
4076 snew(p_rdist, actual_nThreads);
4077 for (i = 0; i < actual_nThreads; i++)
4080 snew(p_adist[i], nabin+1);
4081 snew(p_rdist[i], nrbin+1);
4083 p_hb[i]->max_frames = 0;
4084 p_hb[i]->nhb = NULL;
4085 p_hb[i]->ndist = NULL;
4086 p_hb[i]->n_bound = NULL;
4087 p_hb[i]->time = NULL;
4088 p_hb[i]->nhx = NULL;
4090 p_hb[i]->bHBmap = hb->bHBmap;
4091 p_hb[i]->bDAnr = hb->bDAnr;
4092 p_hb[i]->bGem = hb->bGem;
4093 p_hb[i]->wordlen = hb->wordlen;
4094 p_hb[i]->nframes = hb->nframes;
4095 p_hb[i]->maxhydro = hb->maxhydro;
4096 p_hb[i]->danr = hb->danr;
4099 p_hb[i]->hbmap = hb->hbmap;
4100 p_hb[i]->time = hb->time; /* This may need re-syncing at every frame. */
4101 p_hb[i]->per = hb->per;
4103 #ifdef HAVE_NN_LOOPS
4104 p_hb[i]->hbE = hb->hbE;
4108 p_hb[i]->nrdist = 0;
4112 /* Make a thread pool here,
4113 * instead of forking anew at every frame. */
4115 #pragma omp parallel \
4117 private(j, h, ii, jj, hh, E, \
4118 xi, yi, zi, xj, yj, zj, threadNr, \
4119 dist, ang, peri, icell, jcell, \
4120 grp, ogrp, ai, aj, xjj, yjj, zjj, \
4121 xk, yk, zk, ihb, id, resdist, \
4122 xkk, ykk, zkk, kcell, ak, k, bTric, \
4123 bEdge_xjj, bEdge_yjj) \
4125 { /* Start of parallel region */
4126 threadNr = gmx_omp_get_thread_num();
4131 bTric = bBox && TRICLINIC(box);
4135 sync_hbdata(p_hb[threadNr], nframes);
4139 build_grid(hb, x, x[shatom], bBox, box, hbox, (rcut > r2cut) ? rcut : r2cut,
4140 rshell, ngrid, grid);
4141 reset_nhbonds(&(hb->d));
4143 if (debug && bDebug)
4145 dump_grid(debug, ngrid, grid);
4148 add_frames(hb, nframes);
4149 init_hbframe(hb, nframes, output_env_conv_time(oenv, t));
4153 count_da_grid(ngrid, grid, hb->danr[nframes]);
4159 p_hb[threadNr]->time = hb->time; /* This pointer may have changed. */
4164 #ifdef HAVE_NN_LOOPS /* Unlock this feature when testing */
4165 /* Loop over all atom pairs and estimate interaction energy */
4169 addFramesNN(hb, nframes);
4173 #pragma omp for schedule(dynamic)
4174 for (i = 0; i < hb->d.nrd; i++)
4176 for (j = 0; j < hb->a.nra; j++)
4179 h < (bContact ? 1 : hb->d.nhydro[i]);
4182 if (i == hb->d.nrd || j == hb->a.nra)
4184 gmx_fatal(FARGS, "out of bounds");
4187 /* Get the real atom ids */
4190 hh = hb->d.hydro[i][h];
4192 /* Estimate the energy from the geometry */
4193 E = calcHbEnergy(ii, jj, hh, x, NN, box, hbox, &(hb->d));
4194 /* Store the energy */
4195 storeHbEnergy(hb, i, j, h, E, nframes);
4199 #endif /* HAVE_NN_LOOPS */
4208 /* Do not parallelize this just yet. */
4210 for (ii = 0; (ii < nsel); ii++)
4212 int dd = index[0][i];
4213 int aa = index[0][i+2];
4214 /* int */ hh = index[0][i+1];
4215 ihb = is_hbond(hb, ii, ii, dd, aa, rcut, r2cut, ccut, x, bBox, box,
4216 hbox, &dist, &ang, bDA, &h, bContact, bMerge, &peri);
4220 /* add to index if not already there */
4222 add_hbond(hb, dd, aa, hh, ii, ii, nframes, bMerge, ihb, bContact, peri);
4226 } /* if (bSelected) */
4234 calcBoxProjection(box, hb->per->P);
4237 /* loop over all gridcells (xi,yi,zi) */
4238 /* Removed confusing macro, DvdS 27/12/98 */
4241 /* The outer grid loop will have to do for now. */
4242 #pragma omp for schedule(dynamic)
4243 for (xi = 0; xi < ngrid[XX]; xi++)
4245 for (yi = 0; (yi < ngrid[YY]); yi++)
4247 for (zi = 0; (zi < ngrid[ZZ]); zi++)
4250 /* loop over donor groups gr0 (always) and gr1 (if necessary) */
4251 for (grp = gr0; (grp <= (bTwo ? gr1 : gr0)); grp++)
4253 icell = &(grid[zi][yi][xi].d[grp]);
4264 /* loop over all hydrogen atoms from group (grp)
4265 * in this gridcell (icell)
4267 for (ai = 0; (ai < icell->nr); ai++)
4269 i = icell->atoms[ai];
4271 /* loop over all adjacent gridcells (xj,yj,zj) */
4272 for (zjj = grid_loop_begin(ngrid[ZZ], zi, bTric, FALSE);
4273 zjj <= grid_loop_end(ngrid[ZZ], zi, bTric, FALSE);
4276 zj = grid_mod(zjj, ngrid[ZZ]);
4277 bEdge_yjj = (zj == 0) || (zj == ngrid[ZZ] - 1);
4278 for (yjj = grid_loop_begin(ngrid[YY], yi, bTric, bEdge_yjj);
4279 yjj <= grid_loop_end(ngrid[YY], yi, bTric, bEdge_yjj);
4282 yj = grid_mod(yjj, ngrid[YY]);
4284 (yj == 0) || (yj == ngrid[YY] - 1) ||
4285 (zj == 0) || (zj == ngrid[ZZ] - 1);
4286 for (xjj = grid_loop_begin(ngrid[XX], xi, bTric, bEdge_xjj);
4287 xjj <= grid_loop_end(ngrid[XX], xi, bTric, bEdge_xjj);
4290 xj = grid_mod(xjj, ngrid[XX]);
4291 jcell = &(grid[zj][yj][xj].a[ogrp]);
4292 /* loop over acceptor atoms from other group (ogrp)
4293 * in this adjacent gridcell (jcell)
4295 for (aj = 0; (aj < jcell->nr); aj++)
4297 j = jcell->atoms[aj];
4299 /* check if this once was a h-bond */
4301 ihb = is_hbond(__HBDATA, grp, ogrp, i, j, rcut, r2cut, ccut, x, bBox, box,
4302 hbox, &dist, &ang, bDA, &h, bContact, bMerge, &peri);
4306 /* add to index if not already there */
4308 add_hbond(__HBDATA, i, j, h, grp, ogrp, nframes, bMerge, ihb, bContact, peri);
4310 /* make angle and distance distributions */
4311 if (ihb == hbHB && !bContact)
4315 gmx_fatal(FARGS, "distance is higher than what is allowed for an hbond: %f", dist);
4318 __ADIST[(int)( ang/abin)]++;
4319 __RDIST[(int)(dist/rbin)]++;
4323 if ((id = donor_index(&hb->d, grp, i)) == NOTSET)
4325 gmx_fatal(FARGS, "Invalid donor %d", i);
4327 if ((ia = acceptor_index(&hb->a, ogrp, j)) == NOTSET)
4329 gmx_fatal(FARGS, "Invalid acceptor %d", j);
4331 resdist = abs(top.atoms.atom[i].resind-
4332 top.atoms.atom[j].resind);
4333 if (resdist >= max_hx)
4337 __HBDATA->nhx[nframes][resdist]++;
4348 } /* for xi,yi,zi */
4351 } /* if (bSelected) {...} else */
4354 /* Better wait for all threads to finnish using x[] before updating it. */
4357 #pragma omp critical
4359 /* Sum up histograms and counts from p_hb[] into hb */
4362 hb->nhb[k] += p_hb[threadNr]->nhb[k];
4363 hb->ndist[k] += p_hb[threadNr]->ndist[k];
4364 for (j = 0; j < max_hx; j++)
4366 hb->nhx[k][j] += p_hb[threadNr]->nhx[k][j];
4371 /* Here are a handful of single constructs
4372 * to share the workload a bit. The most
4373 * important one is of course the last one,
4374 * where there's a potential bottleneck in form
4381 analyse_donor_props(opt2fn_null("-don", NFILE, fnm), hb, k, t, oenv);
4389 do_nhb_dist(fpnhb, hb, t);
4392 } /* if (bNN) {...} else + */
4396 trrStatus = (read_next_x(oenv, status, &t, x, box));
4406 #pragma omp critical
4408 hb->nrhb += p_hb[threadNr]->nrhb;
4409 hb->nrdist += p_hb[threadNr]->nrdist;
4411 /* Free parallel datastructures */
4412 sfree(p_hb[threadNr]->nhb);
4413 sfree(p_hb[threadNr]->ndist);
4414 sfree(p_hb[threadNr]->nhx);
4417 for (i = 0; i < nabin; i++)
4419 for (j = 0; j < actual_nThreads; j++)
4422 adist[i] += p_adist[j][i];
4426 for (i = 0; i <= nrbin; i++)
4428 for (j = 0; j < actual_nThreads; j++)
4430 rdist[i] += p_rdist[j][i];
4434 sfree(p_adist[threadNr]);
4435 sfree(p_rdist[threadNr]);
4437 } /* End of parallel region */
4444 if (nframes < 2 && (opt2bSet("-ac", NFILE, fnm) || opt2bSet("-life", NFILE, fnm)))
4446 gmx_fatal(FARGS, "Cannot calculate autocorrelation of life times with less than two frames");
4449 free_grid(ngrid, &grid);
4457 /* Compute maximum possible number of different hbonds */
4464 max_nhb = 0.5*(hb->d.nrd*hb->a.nra);
4466 /* Added support for -contact below.
4467 * - Erik Marklund, May 29-31, 2006 */
4468 /* Changed contact code.
4469 * - Erik Marklund, June 29, 2006 */
4474 printf("No %s found!!\n", bContact ? "contacts" : "hydrogen bonds");
4478 printf("Found %d different %s in trajectory\n"
4479 "Found %d different atom-pairs within %s distance\n",
4480 hb->nrhb, bContact ? "contacts" : "hydrogen bonds",
4481 hb->nrdist, (r2cut > 0) ? "second cut-off" : "hydrogen bonding");
4483 /*Control the pHist.*/
4487 merge_hb(hb, bTwo, bContact);
4490 if (opt2bSet("-hbn", NFILE, fnm))
4492 dump_hbmap(hb, NFILE, fnm, bTwo, bContact, isize, index, grpnames, &top.atoms);
4495 /* Moved the call to merge_hb() to a line BEFORE dump_hbmap
4496 * to make the -hbn and -hmb output match eachother.
4497 * - Erik Marklund, May 30, 2006 */
4500 /* Print out number of hbonds and distances */
4503 fp = xvgropen(opt2fn("-num", NFILE, fnm), bContact ? "Contacts" :
4504 "Hydrogen Bonds", output_env_get_xvgr_tlabel(oenv), "Number", oenv);
4506 snew(leg[0], STRLEN);
4507 snew(leg[1], STRLEN);
4508 sprintf(leg[0], "%s", bContact ? "Contacts" : "Hydrogen bonds");
4509 sprintf(leg[1], "Pairs within %g nm", (r2cut > 0) ? r2cut : rcut);
4510 xvgr_legend(fp, 2, (const char**)leg, oenv);
4514 for (i = 0; (i < nframes); i++)
4516 fprintf(fp, "%10g %10d %10d\n", hb->time[i], hb->nhb[i], hb->ndist[i]);
4517 aver_nhb += hb->nhb[i];
4518 aver_dist += hb->ndist[i];
4521 aver_nhb /= nframes;
4522 aver_dist /= nframes;
4523 /* Print HB distance distribution */
4524 if (opt2bSet("-dist", NFILE, fnm))
4529 for (i = 0; i < nrbin; i++)
4534 fp = xvgropen(opt2fn("-dist", NFILE, fnm),
4535 "Hydrogen Bond Distribution",
4537 "Donor - Acceptor Distance (nm)" :
4538 "Hydrogen - Acceptor Distance (nm)", "", oenv);
4539 for (i = 0; i < nrbin; i++)
4541 fprintf(fp, "%10g %10g\n", (i+0.5)*rbin, rdist[i]/(rbin*(real)sum));
4546 /* Print HB angle distribution */
4547 if (opt2bSet("-ang", NFILE, fnm))
4552 for (i = 0; i < nabin; i++)
4557 fp = xvgropen(opt2fn("-ang", NFILE, fnm),
4558 "Hydrogen Bond Distribution",
4559 "Hydrogen - Donor - Acceptor Angle (\\SO\\N)", "", oenv);
4560 for (i = 0; i < nabin; i++)
4562 fprintf(fp, "%10g %10g\n", (i+0.5)*abin, adist[i]/(abin*(real)sum));
4567 /* Print HB in alpha-helix */
4568 if (opt2bSet("-hx", NFILE, fnm))
4570 fp = xvgropen(opt2fn("-hx", NFILE, fnm),
4571 "Hydrogen Bonds", output_env_get_xvgr_tlabel(oenv), "Count", oenv);
4572 xvgr_legend(fp, NRHXTYPES, hxtypenames, oenv);
4573 for (i = 0; i < nframes; i++)
4575 fprintf(fp, "%10g", hb->time[i]);
4576 for (j = 0; j < max_hx; j++)
4578 fprintf(fp, " %6d", hb->nhx[i][j]);
4586 printf("Average number of %s per timeframe %.3f out of %g possible\n",
4587 bContact ? "contacts" : "hbonds",
4588 bContact ? aver_dist : aver_nhb, max_nhb);
4591 /* Do Autocorrelation etc. */
4595 Added support for -contact in ac and hbm calculations below.
4596 - Erik Marklund, May 29, 2006
4600 if (opt2bSet("-ac", NFILE, fnm) || opt2bSet("-life", NFILE, fnm))
4602 please_cite(stdout, "Spoel2006b");
4604 if (opt2bSet("-ac", NFILE, fnm))
4606 char *gemstring = NULL;
4610 params = init_gemParams(rcut, D, hb->time, hb->nframes/2, nFitPoints, fit_start, fit_end,
4611 gemBallistic, nBalExp);
4614 gmx_fatal(FARGS, "Could not initiate t_gemParams params.");
4617 gemstring = gmx_strdup(gemType[hb->per->gemtype]);
4618 do_hbac(opt2fn("-ac", NFILE, fnm), hb, nDump,
4619 bMerge, bContact, fit_start, temp, r2cut > 0, smooth_tail_start, oenv,
4620 gemstring, nThreads, NN, bBallistic, bGemFit);
4622 if (opt2bSet("-life", NFILE, fnm))
4624 do_hblife(opt2fn("-life", NFILE, fnm), hb, bMerge, bContact, oenv);
4626 if (opt2bSet("-hbm", NFILE, fnm))
4629 int id, ia, hh, x, y;
4630 mat.flags = mat.y0 = 0;
4632 if ((nframes > 0) && (hb->nrhb > 0))
4637 snew(mat.matrix, mat.nx);
4638 for (x = 0; (x < mat.nx); x++)
4640 snew(mat.matrix[x], mat.ny);
4643 for (id = 0; (id < hb->d.nrd); id++)
4645 for (ia = 0; (ia < hb->a.nra); ia++)
4647 for (hh = 0; (hh < hb->maxhydro); hh++)
4649 if (hb->hbmap[id][ia])
4651 if (ISHB(hb->hbmap[id][ia]->history[hh]))
4653 /* Changed '<' into '<=' in the for-statement below.
4654 * It fixed the previously undiscovered bug that caused
4655 * the last occurance of an hbond/contact to not be
4656 * set in mat.matrix. Have a look at any old -hbm-output
4657 * and you will notice that the last column is allways empty.
4658 * - Erik Marklund May 30, 2006
4660 for (x = 0; (x <= hb->hbmap[id][ia]->nframes); x++)
4662 int nn0 = hb->hbmap[id][ia]->n0;
4663 range_check(y, 0, mat.ny);
4664 mat.matrix[x+nn0][y] = is_hb(hb->hbmap[id][ia]->h[hh], x);
4672 mat.axis_x = hb->time;
4673 snew(mat.axis_y, mat.ny);
4674 for (j = 0; j < mat.ny; j++)
4678 sprintf(mat.title, bContact ? "Contact Existence Map" :
4679 "Hydrogen Bond Existence Map");
4680 sprintf(mat.legend, bContact ? "Contacts" : "Hydrogen Bonds");
4681 sprintf(mat.label_x, "%s", output_env_get_xvgr_tlabel(oenv));
4682 sprintf(mat.label_y, bContact ? "Contact Index" : "Hydrogen Bond Index");
4683 mat.bDiscrete = TRUE;
4685 snew(mat.map, mat.nmap);
4686 for (i = 0; i < mat.nmap; i++)
4688 mat.map[i].code.c1 = hbmap[i];
4689 mat.map[i].desc = hbdesc[i];
4690 mat.map[i].rgb = hbrgb[i];
4692 fp = opt2FILE("-hbm", NFILE, fnm, "w");
4693 write_xpm_m(fp, mat);
4695 for (x = 0; x < mat.nx; x++)
4697 sfree(mat.matrix[x]);
4705 fprintf(stderr, "No hydrogen bonds/contacts found. No hydrogen bond map will be printed.\n");
4712 fprintf(stderr, "There were %i periodic shifts\n", hb->per->nper);
4713 fprintf(stderr, "Freeing pHist for all donors...\n");
4714 for (i = 0; i < hb->d.nrd; i++)
4716 fprintf(stderr, "\r%i", i);
4717 if (hb->per->pHist[i] != NULL)
4719 for (j = 0; j < hb->a.nra; j++)
4721 clearPshift(&(hb->per->pHist[i][j]));
4723 sfree(hb->per->pHist[i]);
4726 sfree(hb->per->pHist);
4727 sfree(hb->per->p2i);
4729 fprintf(stderr, "...done.\n");
4732 #ifdef HAVE_NN_LOOPS
4745 #define USE_THIS_GROUP(j) ( (j == gr0) || (bTwo && (j == gr1)) )
4747 fp = xvgropen(opt2fn("-dan", NFILE, fnm),
4748 "Donors and Acceptors", output_env_get_xvgr_tlabel(oenv), "Count", oenv);
4749 nleg = (bTwo ? 2 : 1)*2;
4750 snew(legnames, nleg);
4752 for (j = 0; j < grNR; j++)
4754 if (USE_THIS_GROUP(j) )
4756 sprintf(buf, "Donors %s", grpnames[j]);
4757 legnames[i++] = gmx_strdup(buf);
4758 sprintf(buf, "Acceptors %s", grpnames[j]);
4759 legnames[i++] = gmx_strdup(buf);
4764 gmx_incons("number of legend entries");
4766 xvgr_legend(fp, nleg, (const char**)legnames, oenv);
4767 for (i = 0; i < nframes; i++)
4769 fprintf(fp, "%10g", hb->time[i]);
4770 for (j = 0; (j < grNR); j++)
4772 if (USE_THIS_GROUP(j) )
4774 fprintf(fp, " %6d", hb->danr[i][j]);