1 /* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
11 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
12 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
13 * Copyright (c) 2001-2008, The GROMACS development team,
14 * check out http://www.gromacs.org for more information.
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * If you want to redistribute modifications, please consider that
22 * scientific software is very special. Version control is crucial -
23 * bugs must be traceable. We will be happy to consider code for
24 * inclusion in the official distribution, but derived work must not
25 * be called official GROMACS. Details are found in the README & COPYING
26 * files - if they are missing, get the official version at www.gromacs.org.
28 * To help us fund GROMACS development, we humbly ask that you cite
29 * the papers on the package - you can find them in the top README file.
31 * For more info, check our website at http://www.gromacs.org
34 * Groningen Machine for Chemical Simulation
41 /*#define HAVE_NN_LOOPS*/
42 /* Set environment variable CFLAGS = "-fopenmp" when running
43 * configure and define DOUSEOPENMP to make use of parallelized
44 * calculation of autocorrelation function.
45 * It also adds a new option -nthreads which sets the number of threads.
47 /*#define DOUSEOPENMP*/
62 #include "gmx_fatal.h"
75 typedef short int t_E
;
78 typedef int t_hx
[max_hx
];
79 #define NRHXTYPES max_hx
80 char *hxtypenames
[NRHXTYPES
]=
81 {"n-n","n-n+1","n-n+2","n-n+3","n-n+4","n-n+5","n-n>6"};
85 #define MASTER_THREAD_ONLY(threadNr) ((threadNr)==0)
87 #define MASTER_THREAD_ONLY(threadNr) ((threadNr)==(threadNr))
90 /* -----------------------------------------*/
92 enum { gr0
, gr1
, grI
, grNR
};
93 enum { hbNo
, hbDist
, hbHB
, hbNR
, hbR2
};
94 enum { noDA
, ACC
, DON
, DA
, INGROUP
};
95 enum {NN_NULL
, NN_NONE
, NN_BINARY
, NN_1_over_r3
, NN_dipole
, NN_NR
};
97 static const char *grpnames
[grNR
] = {"0","1","I" };
99 static bool bDebug
= FALSE
;
104 #define HB_YESINS HB_YES|HB_INS
108 #define ISHB(h) (((h) & 2) == 2)
109 #define ISDIST(h) (((h) & 1) == 1)
110 #define ISDIST2(h) (((h) & 4) == 4)
111 #define ISACC(h) (((h) & 1) == 1)
112 #define ISDON(h) (((h) & 2) == 2)
113 #define ISINGRP(h) (((h) & 4) == 4)
126 typedef int t_icell
[grNR
];
127 typedef atom_id h_id
[MAXHYDRO
];
130 int history
[MAXHYDRO
];
131 /* Has this hbond existed ever? If so as hbDist or hbHB or both.
132 * Result is stored as a bitmap (1 = hbDist) || (2 = hbHB)
134 /* Bitmask array which tells whether a hbond is present
135 * at a given time. Either of these may be NULL
137 int n0
; /* First frame a HB was found */
138 int nframes
,maxframes
; /* Amount of frames in this hbond */
141 /* See Xu and Berne, JPCB 105 (2001), p. 11929. We define the
142 * function g(t) = [1-h(t)] H(t) where H(t) is one when the donor-
143 * acceptor distance is less than the user-specified distance (typically
150 atom_id
*acc
; /* Atom numbers of the acceptors */
151 int *grp
; /* Group index */
152 int *aptr
; /* Map atom number to acceptor index */
157 int *don
; /* Atom numbers of the donors */
158 int *grp
; /* Group index */
159 int *dptr
; /* Map atom number to donor index */
160 int *nhydro
; /* Number of hydrogens for each donor */
161 h_id
*hydro
; /* The atom numbers of the hydrogens */
162 h_id
*nhbonds
; /* The number of HBs per H at current */
165 /* Tune this to match memory requirements. It should be a signed integer type, e.g. signed char.*/
169 int len
; /* The length of frame and p. */
170 int *frame
; /* The frames at which transitio*/
175 /* Periodicity history. Used for the reversible geminate recombination. */
176 t_pShift
**pHist
; /* The periodicity of every hbond in t_hbdata->hbmap:
177 * pHist[d][a]. We can safely assume that the same
178 * periodic shift holds for all hydrogens of a da-pair.
180 * Nowadays it only stores TRANSITIONS, and not the shift at every frame.
181 * That saves a LOT of memory, an hopefully kills a mysterious bug where
182 * pHist gets contaminated. */
184 PSTYPE nper
; /* The length of p2i */
185 ivec
*p2i
; /* Maps integer to periodic shift for a pair.*/
186 matrix P
; /* Projection matrix to find the box shifts. */
187 int gemtype
; /* enumerated type */
192 int *Etot
; /* Total energy for each frame */
193 t_E
****E
; /* Energy estimate for [d][a][h][frame-n0] */
197 bool bHBmap
,bDAnr
,bGem
;
199 /* The following arrays are nframes long */
200 int nframes
,max_frames
,maxhydro
;
206 /* These structures are initialized from the topology at start up */
209 /* This holds a matrix with all possible hydrogen bonds */
215 /* For parallelization reasons this will have to be a pointer.
216 * Otherwise discrepancies may arise between the periodicity data
217 * seen by different threads. */
221 static void dumpN(real
*e
, int nn
)
223 /* For debugging only */
225 #define N_FILENAME "Nt.dat"
226 char *fn
= N_FILENAME
;
232 "@ xaxis label \"Frame\"\n"
233 "@ yaxis label \"N\"\n"
234 "@ s0 line type 3\n");
236 fprintf(f
, "%-10i %-g\n", i
, e
[i
]);
240 static void clearPshift(t_pShift
*pShift
)
242 if (pShift
->len
> 0) {
244 sfree(pShift
->frame
);
249 static void calcBoxProjection(matrix B
, matrix P
)
251 const int vp
[] = {XX
,YY
,ZZ
};
256 for (i
=0; i
<3; i
++){ m
= vp
[i
];
257 for (j
=0; j
<3; j
++){ n
= vp
[j
];
258 U
[m
][n
] = i
==j
? 1:0;
262 for (i
=0; i
<3; i
++){ m
= vp
[i
];
263 mvmul(M
, U
[m
], P
[m
]);
268 static void calcBoxDistance(matrix P
, rvec d
, ivec ibd
){
269 /* returns integer distance in box coordinates.
270 * P is the projection matrix from cartesian coordinates
271 * obtained with calcBoxProjection(). */
275 /* extend it by 0.5 in all directions since (int) rounds toward 0.*/
277 bd
[i
]=bd
[i
] + (bd
[i
]<0 ? -0.5 : 0.5);
278 ibd
[XX
] = (int)bd
[XX
];
279 ibd
[YY
] = (int)bd
[YY
];
280 ibd
[ZZ
] = (int)bd
[ZZ
];
283 /* Changed argument 'bMerge' into 'oneHB' below,
284 * since -contact should cause maxhydro to be 1,
286 * - Erik Marklund May 29, 2006
289 static PSTYPE
periodicIndex(ivec r
, t_gemPeriod
*per
, bool daSwap
) {
290 /* Try to merge hbonds on the fly. That means that if the
291 * acceptor and donor are mergable, then:
292 * 1) store the hb-info so that acceptor id > donor id,
293 * 2) add the periodic shift in pairs, so that [-x,-y,-z] is
294 * stored in per.p2i[] whenever acceptor id < donor id.
295 * Note that [0,0,0] should already be the first element of per.p2i
296 * by the time this function is called. */
298 /* daSwap is TRUE if the donor and acceptor were swapped.
299 * If so, then the negative vector should be used. */
302 if (per
->p2i
== NULL
|| per
->nper
== 0)
303 gmx_fatal(FARGS
, "'per' not initialized properly.");
304 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
])
310 /* Not found apparently. Add it to the list! */
311 /* printf("New shift found: %i,%i,%i\n",r[XX],r[YY],r[ZZ]); */
313 /* Unfortunately this needs to be critical it seems. */
319 fprintf(stderr
, "p2i not initialized. This shouldn't happen!\n");
323 srenew(per
->p2i
, per
->nper
+2);
324 copy_ivec(r
, per
->p2i
[per
->nper
]);
327 /* Add the mirror too. It's rather likely that it'll be needed. */
328 per
->p2i
[per
->nper
][XX
] = -r
[XX
];
329 per
->p2i
[per
->nper
][YY
] = -r
[YY
];
330 per
->p2i
[per
->nper
][ZZ
] = -r
[ZZ
];
333 return per
->nper
- 1 - (daSwap
? 0:1);
336 static t_hbdata
*mk_hbdata(bool bHBmap
,bool bDAnr
,bool oneHB
, bool bGem
, int gemmode
)
341 hb
->wordlen
= 8*sizeof(unsigned int);
348 hb
->maxhydro
= MAXHYDRO
;
350 hb
->per
->gemtype
= bGem
? gemmode
: 0;
355 static void mk_hbmap(t_hbdata
*hb
,bool bTwo
,bool bInsert
)
359 snew(hb
->hbmap
,hb
->d
.nrd
);
360 for(i
=0; (i
<hb
->d
.nrd
); i
++) {
361 snew(hb
->hbmap
[i
],hb
->a
.nra
);
362 if (hb
->hbmap
[i
] == NULL
)
363 gmx_fatal(FARGS
,"Could not allocate enough memory for hbmap");
364 for (j
=0; (j
>hb
->a
.nra
); j
++)
365 hb
->hbmap
[i
][j
] == NULL
;
369 /* Consider redoing pHist so that is only stores transitions between
370 * periodicities and not the periodicity for all frames. This eats heaps of memory. */
371 static void mk_per(t_hbdata
*hb
)
375 snew(hb
->per
->pHist
, hb
->d
.nrd
);
376 for (i
=0; i
<hb
->d
.nrd
; i
++) {
377 snew(hb
->per
->pHist
[i
], hb
->a
.nra
);
378 if (hb
->per
->pHist
[i
]==NULL
)
379 gmx_fatal(FARGS
,"Could not allocate enough memory for per->pHist");
380 for (j
=0; j
<hb
->a
.nra
; j
++) {
381 clearPshift(&(hb
->per
->pHist
[i
][j
]));
384 /* add the [0,0,0] shift to element 0 of p2i. */
385 snew(hb
->per
->p2i
, 1);
386 clear_ivec(hb
->per
->p2i
[0]);
392 static void mk_hbEmap (t_hbdata
*hb
, int n0
)
397 snew(hb
->hbE
.E
, hb
->d
.nrd
);
398 for (i
=0; i
<hb
->d
.nrd
; i
++)
400 snew(hb
->hbE
.E
[i
], hb
->a
.nra
);
401 for (j
=0; j
<hb
->a
.nra
; j
++)
403 snew(hb
->hbE
.E
[i
][j
], MAXHYDRO
);
404 for (k
=0; k
<MAXHYDRO
; k
++)
405 hb
->hbE
.E
[i
][j
][k
] = NULL
;
411 static void free_hbEmap (t_hbdata
*hb
)
414 for (i
=0; i
<hb
->d
.nrd
; i
++)
416 for (j
=0; j
<hb
->a
.nra
; j
++)
418 for (k
=0; k
<MAXHYDRO
; k
++)
419 sfree(hb
->hbE
.E
[i
][j
][k
]);
420 sfree(hb
->hbE
.E
[i
][j
]);
428 static void addFramesNN(t_hbdata
*hb
, int frame
)
431 #define DELTAFRAMES_HBE 10
435 if (frame
>= hb
->hbE
.nframes
) {
436 nframes
= hb
->hbE
.nframes
+ DELTAFRAMES_HBE
;
437 srenew(hb
->hbE
.Etot
, nframes
);
439 for (d
=0; d
<hb
->d
.nrd
; d
++)
440 for (a
=0; a
<hb
->a
.nra
; a
++)
441 for (h
=0; h
<hb
->d
.nhydro
[d
]; h
++)
442 srenew(hb
->hbE
.E
[d
][a
][h
], nframes
);
444 hb
->hbE
.nframes
+= DELTAFRAMES_HBE
;
448 static t_E
calcHbEnergy(int d
, int a
, int h
, rvec x
[], t_EEst EEst
,
449 matrix box
, rvec hbox
, t_donors
*donors
){
453 * alpha - angle between dipoles
454 * x[] - atomic positions
455 * EEst - the type of energy estimate (see enum in hbplugin.h)
456 * box - the box vectors \
457 * hbox - half box lengths _These two are only needed for the pbc correction
462 rvec dipole
[2], xmol
[3], xmean
[2];
467 /* Self-interaction */
473 /* This is a simple binary existence function that sets E=1 whenever
474 * the distance between the oxygens is equal too or less than 0.35 nm.
476 rvec_sub(x
[d
], x
[a
], dist
);
477 pbc_correct_gem(dist
, box
, hbox
);
478 if (norm(dist
) <= 0.35)
485 /* Negative potential energy of a dipole.
486 * E = -cos(alpha) * 1/r^3 */
488 copy_rvec(x
[d
], xmol
[0]); /* donor */
489 copy_rvec(x
[donors
->hydro
[donors
->dptr
[d
]][0]], xmol
[1]); /* hydrogen */
490 copy_rvec(x
[donors
->hydro
[donors
->dptr
[d
]][1]], xmol
[2]); /* hydrogen */
492 svmul(15.9994*(1/1.008), xmol
[0], xmean
[0]);
493 rvec_inc(xmean
[0], xmol
[1]);
494 rvec_inc(xmean
[0], xmol
[2]);
496 xmean
[0][i
] /= (15.9994 + 1.008 + 1.008)/1.008;
498 /* Assumes that all acceptors are also donors. */
499 copy_rvec(x
[a
], xmol
[0]); /* acceptor */
500 copy_rvec(x
[donors
->hydro
[donors
->dptr
[a
]][0]], xmol
[1]); /* hydrogen */
501 copy_rvec(x
[donors
->hydro
[donors
->dptr
[a
]][1]], xmol
[2]); /* hydrogen */
504 svmul(15.9994*(1/1.008), xmol
[0], xmean
[1]);
505 rvec_inc(xmean
[1], xmol
[1]);
506 rvec_inc(xmean
[1], xmol
[2]);
508 xmean
[1][i
] /= (15.9994 + 1.008 + 1.008)/1.008;
510 rvec_sub(xmean
[0], xmean
[1], dist
);
511 pbc_correct_gem(dist
, box
, hbox
);
514 realE
= pow(r
, -3.0);
515 E
= (t_E
)(SCALEFACTOR_E
* realE
);
519 /* Negative potential energy of a (unpolarizable) dipole.
520 * E = -cos(alpha) * 1/r^3 */
521 clear_rvec(dipole
[1]);
522 clear_rvec(dipole
[0]);
524 copy_rvec(x
[d
], xmol
[0]); /* donor */
525 copy_rvec(x
[donors
->hydro
[donors
->dptr
[d
]][0]], xmol
[1]); /* hydrogen */
526 copy_rvec(x
[donors
->hydro
[donors
->dptr
[d
]][1]], xmol
[2]); /* hydrogen */
528 rvec_inc(dipole
[0], xmol
[1]);
529 rvec_inc(dipole
[0], xmol
[2]);
532 rvec_dec(dipole
[0], xmol
[0]);
534 svmul(15.9994*(1/1.008), xmol
[0], xmean
[0]);
535 rvec_inc(xmean
[0], xmol
[1]);
536 rvec_inc(xmean
[0], xmol
[2]);
538 xmean
[0][i
] /= (15.9994 + 1.008 + 1.008)/1.008;
540 /* Assumes that all acceptors are also donors. */
541 copy_rvec(x
[a
], xmol
[0]); /* acceptor */
542 copy_rvec(x
[donors
->hydro
[donors
->dptr
[a
]][0]], xmol
[1]); /* hydrogen */
543 copy_rvec(x
[donors
->hydro
[donors
->dptr
[a
]][2]], xmol
[2]); /* hydrogen */
546 rvec_inc(dipole
[1], xmol
[1]);
547 rvec_inc(dipole
[1], xmol
[2]);
550 rvec_dec(dipole
[1], xmol
[0]);
552 svmul(15.9994*(1/1.008), xmol
[0], xmean
[1]);
553 rvec_inc(xmean
[1], xmol
[1]);
554 rvec_inc(xmean
[1], xmol
[2]);
556 xmean
[1][i
] /= (15.9994 + 1.008 + 1.008)/1.008;
558 rvec_sub(xmean
[0], xmean
[1], dist
);
559 pbc_correct_gem(dist
, box
, hbox
);
562 double cosalpha
= cos_angle(dipole
[0],dipole
[1]);
563 realE
= cosalpha
* pow(r
, -3.0);
564 E
= (t_E
)(SCALEFACTOR_E
* realE
);
568 printf("Can't do that type of energy estimate: %i\n.", EEst
);
575 static void storeHbEnergy(t_hbdata
*hb
, int d
, int a
, int h
, t_E E
, int frame
){
576 /* hb - hbond data structure
580 E - estimate of the energy
581 frame - the current frame.
584 /* Store the estimated energy */
588 hb
->hbE
.E
[d
][a
][h
][frame
] = E
;
593 hb
->hbE
.Etot
[frame
] += E
;
596 #endif /* HAVE_NN_LOOPS */
599 /* Finds -v[] in the periodicity index */
600 static int findMirror(PSTYPE p
, ivec v
[], PSTYPE nper
)
604 for (i
=0; i
<nper
; i
++){
605 if (v
[i
][XX
] == -(v
[p
][XX
]) &&
606 v
[i
][YY
] == -(v
[p
][YY
]) &&
607 v
[i
][ZZ
] == -(v
[p
][ZZ
]))
610 printf("Couldn't find mirror of [%i, %i, %i], index \n",
618 static void add_frames(t_hbdata
*hb
,int nframes
)
622 if (nframes
>= hb
->max_frames
) {
623 hb
->max_frames
+= 4096;
624 srenew(hb
->time
,hb
->max_frames
);
625 srenew(hb
->nhb
,hb
->max_frames
);
626 srenew(hb
->ndist
,hb
->max_frames
);
627 srenew(hb
->n_bound
,hb
->max_frames
);
628 srenew(hb
->nhx
,hb
->max_frames
);
630 srenew(hb
->danr
,hb
->max_frames
);
635 #define OFFSET(frame) (frame / 32)
636 #define MASK(frame) (1 << (frame % 32))
638 static void _set_hb(unsigned int hbexist
[],unsigned int frame
,bool bValue
)
641 hbexist
[OFFSET(frame
)] |= MASK(frame
);
643 hbexist
[OFFSET(frame
)] &= ~MASK(frame
);
646 static bool is_hb(unsigned int hbexist
[],int frame
)
648 return ((hbexist
[OFFSET(frame
)] & MASK(frame
)) != 0) ? 1 : 0;
651 static void set_hb(t_hbdata
*hb
,int id
,int ih
, int ia
,int frame
,int ihb
)
653 unsigned int *ghptr
=NULL
;
656 ghptr
= hb
->hbmap
[id
][ia
]->h
[ih
];
657 else if (ihb
== hbDist
)
658 ghptr
= hb
->hbmap
[id
][ia
]->g
[ih
];
660 gmx_fatal(FARGS
,"Incomprehensible iValue %d in set_hb",ihb
);
662 _set_hb(ghptr
,frame
-hb
->hbmap
[id
][ia
]->n0
,TRUE
);
665 static void addPshift(t_pShift
*pHist
, PSTYPE p
, int frame
)
667 if (pHist
->len
== 0) {
668 snew(pHist
->frame
, 1);
671 pHist
->frame
[0] = frame
;
675 if (pHist
->p
[pHist
->len
-1] != p
) {
677 srenew(pHist
->frame
, pHist
->len
);
678 srenew(pHist
->p
, pHist
->len
);
679 pHist
->frame
[pHist
->len
-1] = frame
;
680 pHist
->p
[pHist
->len
-1] = p
;
681 } /* Otherwise, there is no transition. */
685 static PSTYPE
getPshift(t_pShift pHist
, int frame
)
690 || (pHist
.len
> 0 && pHist
.frame
[0]>frame
))
693 for (i
=0; i
<pHist
.len
; i
++)
702 /* It seems that frame is after the last periodic transition. Return the last periodicity. */
703 return pHist
.p
[pHist
.len
-1];
706 static void add_ff(t_hbdata
*hbd
,int id
,int h
,int ia
,int frame
,int ihb
, PSTYPE p
)
709 t_hbond
*hb
= hbd
->hbmap
[id
][ia
];
710 int maxhydro
= min(hbd
->maxhydro
,hbd
->d
.nhydro
[id
]);
711 int wlen
= hbd
->wordlen
;
713 bool bGem
= hbd
->bGem
;
717 hb
->maxframes
= delta
;
718 for(i
=0; (i
<maxhydro
); i
++) {
719 snew(hb
->h
[i
],hb
->maxframes
/wlen
);
720 snew(hb
->g
[i
],hb
->maxframes
/wlen
);
723 hb
->nframes
= frame
-hb
->n0
;
724 /* We need a while loop here because hbonds may be returning
727 while (hb
->nframes
>= hb
->maxframes
) {
728 n
= hb
->maxframes
+ delta
;
729 for(i
=0; (i
<maxhydro
); i
++) {
730 srenew(hb
->h
[i
],n
/wlen
);
731 srenew(hb
->g
[i
],n
/wlen
);
732 for(j
=hb
->maxframes
/wlen
; (j
<n
/wlen
); j
++) {
742 set_hb(hbd
,id
,h
,ia
,frame
,ihb
);
744 if (p
>=hbd
->per
->nper
)
745 gmx_fatal(FARGS
, "invalid shift: p=%u, nper=%u", p
, hbd
->per
->nper
);
747 addPshift(&(hbd
->per
->pHist
[id
][ia
]), p
, frame
);
753 static void inc_nhbonds(t_donors
*ddd
,int d
, int h
)
756 int dptr
= ddd
->dptr
[d
];
758 for(j
=0; (j
<ddd
->nhydro
[dptr
]); j
++)
759 if (ddd
->hydro
[dptr
][j
] == h
) {
760 ddd
->nhbonds
[dptr
][j
]++;
763 if (j
== ddd
->nhydro
[dptr
])
764 gmx_fatal(FARGS
,"No such hydrogen %d on donor %d\n",h
+1,d
+1);
767 static int _acceptor_index(t_acceptors
*a
,int grp
,atom_id i
,
768 const char *file
,int line
)
772 if (a
->grp
[ai
] != grp
) {
774 fprintf(debug
,"Acc. group inconsist.. grp[%d] = %d, grp = %d (%s, %d)\n",
775 ai
,a
->grp
[ai
],grp
,file
,line
);
781 #define acceptor_index(a,grp,i) _acceptor_index(a,grp,i,__FILE__,__LINE__)
783 static int _donor_index(t_donors
*d
,int grp
,atom_id i
,const char *file
,int line
)
787 if (d
->grp
[di
] != grp
) {
789 fprintf(debug
,"Don. group inconsist.. grp[%d] = %d, grp = %d (%s, %d)\n",
790 di
,d
->grp
[di
],grp
,file
,line
);
796 #define donor_index(d,grp,i) _donor_index(d,grp,i,__FILE__,__LINE__)
798 static bool isInterchangable(t_hbdata
*hb
, int d
, int a
, int grpa
, int grpd
)
801 donor_index(&hb
->d
,grpd
,a
) != NOTSET
802 && acceptor_index(&hb
->a
,grpa
,d
) != NOTSET
;
806 static void add_hbond(t_hbdata
*hb
,int d
,int a
,int h
,int grpd
,int grpa
,
807 int frame
,bool bInsert
,bool bMerge
,int ihb
,bool bContact
, PSTYPE p
)
812 if ((id
= hb
->d
.dptr
[d
]) == NOTSET
)
813 gmx_fatal(FARGS
,"No donor atom %d",d
+1);
814 else if (grpd
!= hb
->d
.grp
[id
])
815 gmx_fatal(FARGS
,"Inconsistent donor groups, %d iso %d, atom %d",
816 grpd
,hb
->d
.grp
[id
],d
+1);
817 if ((ia
= hb
->a
.aptr
[a
]) == NOTSET
)
818 gmx_fatal(FARGS
,"No acceptor atom %d",a
+1);
819 else if (grpa
!= hb
->a
.grp
[ia
])
820 gmx_fatal(FARGS
,"Inconsistent acceptor groups, %d iso %d, atom %d",
821 grpa
,hb
->a
.grp
[ia
],a
+1);
824 if ((daSwap
= isInterchangable(hb
, d
, a
, grpd
, grpa
) || bContact
) && d
>a
)
825 /* Then swap identity so that the id of d is lower then that of a.
827 * This should really be redundant by now, as is_hbond() now ought to return
828 * hbNo in the cases where this conditional is TRUE. */
834 /* Now repeat donor/acc check. */
835 if ((id
= hb
->d
.dptr
[d
]) == NOTSET
)
836 gmx_fatal(FARGS
,"No donor atom %d",d
+1);
837 else if (grpd
!= hb
->d
.grp
[id
])
838 gmx_fatal(FARGS
,"Inconsistent donor groups, %d iso %d, atom %d",
839 grpd
,hb
->d
.grp
[id
],d
+1);
840 if ((ia
= hb
->a
.aptr
[a
]) == NOTSET
)
841 gmx_fatal(FARGS
,"No acceptor atom %d",a
+1);
842 else if (grpa
!= hb
->a
.grp
[ia
])
843 gmx_fatal(FARGS
,"Inconsistent acceptor groups, %d iso %d, atom %d",
844 grpa
,hb
->a
.grp
[ia
],a
+1);
848 /* Loop over hydrogens to find which hydrogen is in this particular HB */
849 if ((ihb
== hbHB
) && !bMerge
&& !bContact
) {
850 for(k
=0; (k
<hb
->d
.nhydro
[id
]); k
++)
851 if (hb
->d
.hydro
[id
][k
] == h
)
853 if (k
== hb
->d
.nhydro
[id
])
854 gmx_fatal(FARGS
,"Donor %d does not have hydrogen %d (a = %d)",
861 if (hb
->hbmap
[id
][ia
] == NULL
) {
862 snew(hb
->hbmap
[id
][ia
],1);
863 snew(hb
->hbmap
[id
][ia
]->h
,hb
->maxhydro
);
864 snew(hb
->hbmap
[id
][ia
]->g
,hb
->maxhydro
);
866 add_ff(hb
,id
,k
,ia
,frame
,ihb
,p
);
869 /* Strange construction with frame >=0 is a relic from old code
870 * for selected hbond analysis. It may be necessary again if that
871 * is made to work again.
874 hh
= hb
->hbmap
[id
][ia
]->history
[k
];
878 hb
->hbmap
[id
][ia
]->history
[k
] = hh
| 2;
887 hb
->hbmap
[id
][ia
]->history
[k
] = hh
| 1;
904 if (bMerge
&& daSwap
)
905 h
= hb
->d
.hydro
[id
][0];
906 /* Increment number if HBonds per H */
907 if (ihb
== hbHB
&& !bContact
)
908 inc_nhbonds(&(hb
->d
),d
,h
);
911 /* Now a redundant function. It might find use at some point though. */
912 static bool in_list(atom_id selection
,int isize
,atom_id
*index
)
918 for(i
=0; (i
<isize
) && !bFound
; i
++)
919 if(selection
== index
[i
])
925 static char *mkatomname(t_atoms
*atoms
,int i
)
930 rnr
= atoms
->atom
[i
].resind
;
931 sprintf(buf
,"%4s%d%-4s",
932 *atoms
->resinfo
[rnr
].name
,atoms
->resinfo
[rnr
].nr
,*atoms
->atomname
[i
]);
937 static void gen_datable(atom_id
*index
, int isize
, unsigned char *datable
, int natoms
){
938 /* Generates table of all atoms and sets the ingroup bit for atoms in index[] */
941 for (i
=0; i
<isize
; i
++){
942 if (index
[i
] >= natoms
)
943 gmx_fatal(FARGS
,"Atom has index %d larger than number of atoms %d.",index
[i
],natoms
);
944 datable
[index
[i
]] |= INGROUP
;
948 static void clear_datable_grp(unsigned char *datable
, int size
){
949 /* Clears group information from the table */
951 const char mask
= !(char)INGROUP
;
957 static void add_acc(t_acceptors
*a
,int ia
,int grp
)
959 if (a
->nra
>= a
->max_nra
) {
961 srenew(a
->acc
,a
->max_nra
);
962 srenew(a
->grp
,a
->max_nra
);
964 a
->grp
[a
->nra
] = grp
;
965 a
->acc
[a
->nra
++] = ia
;
968 static void search_acceptors(t_topology
*top
,int isize
,
969 atom_id
*index
,t_acceptors
*a
,int grp
,
971 bool bContact
,bool bDoIt
, unsigned char *datable
)
976 for (i
=0; (i
<isize
); i
++) {
979 (((*top
->atoms
.atomname
[n
])[0] == 'O') ||
980 (bNitAcc
&& ((*top
->atoms
.atomname
[n
])[0] == 'N')))) &&
981 ISINGRP(datable
[n
])) {
982 datable
[n
] |= ACC
; /* set the atom's acceptor flag in datable. */
987 snew(a
->aptr
,top
->atoms
.nr
);
988 for(i
=0; (i
<top
->atoms
.nr
); i
++)
990 for(i
=0; (i
<a
->nra
); i
++)
991 a
->aptr
[a
->acc
[i
]] = i
;
994 static void add_h2d(int id
,int ih
,t_donors
*ddd
)
998 for(i
=0; (i
<ddd
->nhydro
[id
]); i
++)
999 if (ddd
->hydro
[id
][i
] == ih
) {
1000 printf("Hm. This isn't first time I find this donor (%d,%d)\n",
1004 if (i
== ddd
->nhydro
[id
]) {
1005 if (ddd
->nhydro
[id
] >= MAXHYDRO
)
1006 gmx_fatal(FARGS
,"Donor %d has more than %d hydrogens!",
1007 ddd
->don
[id
],MAXHYDRO
);
1008 ddd
->hydro
[id
][i
] = ih
;
1013 static void add_dh(t_donors
*ddd
,int id
,int ih
,int grp
, unsigned char *datable
)
1017 if (ISDON(datable
[id
]) || !datable
) {
1018 if (ddd
->dptr
[id
] == NOTSET
) { /* New donor */
1024 if (i
== ddd
->nrd
) {
1025 if (ddd
->nrd
>= ddd
->max_nrd
) {
1026 ddd
->max_nrd
+= 128;
1027 srenew(ddd
->don
,ddd
->max_nrd
);
1028 srenew(ddd
->nhydro
,ddd
->max_nrd
);
1029 srenew(ddd
->hydro
,ddd
->max_nrd
);
1030 srenew(ddd
->nhbonds
,ddd
->max_nrd
);
1031 srenew(ddd
->grp
,ddd
->max_nrd
);
1033 ddd
->don
[ddd
->nrd
] = id
;
1034 ddd
->nhydro
[ddd
->nrd
] = 0;
1035 ddd
->grp
[ddd
->nrd
] = grp
;
1042 printf("Warning: Atom %d is not in the d/a-table!\n", id
);
1045 static void search_donors(t_topology
*top
, int isize
, atom_id
*index
,
1046 t_donors
*ddd
,int grp
,bool bContact
,bool bDoIt
,
1047 unsigned char *datable
)
1050 t_functype func_type
;
1051 t_ilist
*interaction
;
1056 snew(ddd
->dptr
,top
->atoms
.nr
);
1057 for(i
=0; (i
<top
->atoms
.nr
); i
++)
1058 ddd
->dptr
[i
] = NOTSET
;
1063 for(i
=0; (i
<isize
); i
++) {
1064 datable
[index
[i
]] |= DON
;
1065 add_dh(ddd
,index
[i
],-1,grp
,datable
);
1069 for(func_type
=0; (func_type
< F_NRE
); func_type
++) {
1070 interaction
=&(top
->idef
.il
[func_type
]);
1071 for(i
=0; i
< interaction
->nr
;
1072 i
+=interaction_function
[top
->idef
.functype
[interaction
->iatoms
[i
]]].nratoms
+1) {
1074 if (func_type
!= top
->idef
.functype
[interaction
->iatoms
[i
]]) {
1075 fprintf(stderr
,"Error in func_type %s",
1076 interaction_function
[func_type
].longname
);
1080 /* check out this functype */
1081 if (func_type
== F_SETTLE
) {
1082 nr1
=interaction
->iatoms
[i
+1];
1084 if (ISINGRP(datable
[nr1
])) {
1085 if (ISINGRP(datable
[nr1
+1])) {
1086 datable
[nr1
] |= DON
;
1087 add_dh(ddd
,nr1
,nr1
+1,grp
,datable
);
1089 if (ISINGRP(datable
[nr1
+2])) {
1090 datable
[nr1
] |= DON
;
1091 add_dh(ddd
,nr1
,nr1
+2,grp
,datable
);
1095 else if (IS_CHEMBOND(func_type
)) {
1096 for (j
=0; j
<2; j
++) {
1097 nr1
=interaction
->iatoms
[i
+1+j
];
1098 nr2
=interaction
->iatoms
[i
+2-j
];
1099 if ((*top
->atoms
.atomname
[nr1
][0] == 'H') &&
1100 ((*top
->atoms
.atomname
[nr2
][0] == 'O') ||
1101 (*top
->atoms
.atomname
[nr2
][0] == 'N')) &&
1102 ISINGRP(datable
[nr1
]) && ISINGRP(datable
[nr2
])) {
1103 datable
[nr2
] |= DON
;
1104 add_dh(ddd
,nr2
,nr1
,grp
,datable
);
1111 for(func_type
=0; func_type
< F_NRE
; func_type
++) {
1112 interaction
=&top
->idef
.il
[func_type
];
1113 for(i
=0; i
< interaction
->nr
;
1114 i
+=interaction_function
[top
->idef
.functype
[interaction
->iatoms
[i
]]].nratoms
+1) {
1116 if (func_type
!= top
->idef
.functype
[interaction
->iatoms
[i
]])
1117 gmx_incons("function type in search_donors");
1119 if ( interaction_function
[func_type
].flags
& IF_VSITE
) {
1120 nr1
=interaction
->iatoms
[i
+1];
1121 if ( *top
->atoms
.atomname
[nr1
][0] == 'H') {
1124 while (!stop
&& ( *top
->atoms
.atomname
[nr2
][0] == 'H'))
1129 if ( !stop
&& ( ( *top
->atoms
.atomname
[nr2
][0] == 'O') ||
1130 ( *top
->atoms
.atomname
[nr2
][0] == 'N') ) &&
1131 ISINGRP(datable
[nr1
]) && ISINGRP(datable
[nr2
])) {
1132 datable
[nr2
] |= DON
;
1133 add_dh(ddd
,nr2
,nr1
,grp
,datable
);
1143 static t_gridcell
***init_grid(bool bBox
,rvec box
[],real rcut
,ivec ngrid
)
1149 for(i
=0; i
<DIM
; i
++)
1150 ngrid
[i
]=(box
[i
][i
]/(1.2*rcut
));
1152 if ( !bBox
|| (ngrid
[XX
]<3) || (ngrid
[YY
]<3) || (ngrid
[ZZ
]<3) )
1153 for(i
=0; i
<DIM
; i
++)
1156 printf("\nWill do grid-seach on %dx%dx%d grid, rcut=%g\n",
1157 ngrid
[XX
],ngrid
[YY
],ngrid
[ZZ
],rcut
);
1158 snew(grid
,ngrid
[ZZ
]);
1159 for (z
=0; z
<ngrid
[ZZ
]; z
++) {
1160 snew((grid
)[z
],ngrid
[YY
]);
1161 for (y
=0; y
<ngrid
[YY
]; y
++)
1162 snew((grid
)[z
][y
],ngrid
[XX
]);
1167 static void control_pHist(t_hbdata
*hb
, int nframes
)
1171 for (i
=0;i
<hb
->d
.nrd
;i
++)
1172 for (j
=0;j
<hb
->a
.nra
;j
++)
1173 if (hb
->per
->pHist
[i
][j
].len
!= 0)
1174 for (k
=hb
->hbmap
[i
][j
][0].n0
; k
<nframes
; k
++) {
1175 p
= getPshift(hb
->per
->pHist
[i
][j
], k
);
1176 if (p
>hb
->per
->nper
)
1177 fprintf(stderr
, "Weird stuff in pHist[%i][%i].p at frame %i: p=%i\n",
1182 static void reset_nhbonds(t_donors
*ddd
)
1186 for(i
=0; (i
<ddd
->nrd
); i
++)
1187 for(j
=0; (j
<MAXHH
); j
++)
1188 ddd
->nhbonds
[i
][j
] = 0;
1191 void pbc_correct_gem(rvec dx
,matrix box
,rvec hbox
);
1193 static void build_grid(t_hbdata
*hb
,rvec x
[], rvec xshell
,
1194 bool bBox
, matrix box
, rvec hbox
,
1195 real rcut
, real rshell
,
1196 ivec ngrid
, t_gridcell
***grid
)
1198 int i
,m
,gr
,xi
,yi
,zi
,nr
;
1201 rvec invdelta
,dshell
,xtemp
;
1203 bool bDoRshell
,bInShell
,bAcc
;
1208 bDoRshell
= (rshell
> 0);
1209 rshell2
= sqr(rshell
);
1212 #define DBB(x) if (debug && bDebug) fprintf(debug,"build_grid, line %d, %s = %d\n",__LINE__,#x,x)
1214 for(m
=0; m
<DIM
; m
++) {
1215 hbox
[m
]=box
[m
][m
]*0.5;
1217 invdelta
[m
]=ngrid
[m
]/box
[m
][m
];
1218 if (1/invdelta
[m
] < rcut
)
1219 gmx_fatal(FARGS
,"Your computational box has shrunk too much.\n"
1220 "%s can not handle this situation, sorry.\n",
1229 /* resetting atom counts */
1230 for(gr
=0; (gr
<grNR
); gr
++) {
1231 for (zi
=0; zi
<ngrid
[ZZ
]; zi
++)
1232 for (yi
=0; yi
<ngrid
[YY
]; yi
++)
1233 for (xi
=0; xi
<ngrid
[XX
]; xi
++) {
1234 grid
[zi
][yi
][xi
].d
[gr
].nr
=0;
1235 grid
[zi
][yi
][xi
].a
[gr
].nr
=0;
1239 /* put atoms in grid cells */
1240 for(bAcc
=FALSE
; (bAcc
<=TRUE
); bAcc
++) {
1250 for(i
=0; (i
<nr
); i
++) {
1251 /* check if we are inside the shell */
1252 /* if bDoRshell=FALSE then bInShell=TRUE always */
1256 rvec_sub(x
[ad
[i
]],xshell
,dshell
);
1258 if (FALSE
&& !hb
->bGem
) {
1259 for(m
=DIM
-1; m
>=0 && bInShell
; m
--) {
1260 if ( dshell
[m
] < -hbox
[m
] )
1261 rvec_inc(dshell
,box
[m
]);
1262 else if ( dshell
[m
] >= hbox
[m
] )
1263 dshell
[m
] -= 2*hbox
[m
];
1264 /* if we're outside the cube, we're outside the sphere also! */
1265 if ( (dshell
[m
]>rshell
) || (-dshell
[m
]>rshell
) )
1273 for(m
=DIM
-1; m
>=0 && bInShell
; m
--) {
1274 if ( dshell
[m
] < -hbox
[m
] ) {
1276 rvec_inc(dshell
,box
[m
]);
1278 if ( dshell
[m
] >= hbox
[m
] ) {
1280 dshell
[m
] -= 2*hbox
[m
];
1284 for(m
=DIM
-1; m
>=0 && bInShell
; m
--) {
1285 /* if we're outside the cube, we're outside the sphere also! */
1286 if ( (dshell
[m
]>rshell
) || (-dshell
[m
]>rshell
) )
1291 /* if we're inside the cube, check if we're inside the sphere */
1293 bInShell
= norm2(dshell
) < rshell2
;
1299 copy_rvec(x
[ad
[i
]], xtemp
);
1300 pbc_correct_gem(x
[ad
[i
]], box
, hbox
);
1302 for(m
=DIM
-1; m
>=0; m
--) {
1303 if (TRUE
|| !hb
->bGem
){
1304 /* put atom in the box */
1305 while( x
[ad
[i
]][m
] < 0 )
1306 rvec_inc(x
[ad
[i
]],box
[m
]);
1307 while( x
[ad
[i
]][m
] >= box
[m
][m
] )
1308 rvec_dec(x
[ad
[i
]],box
[m
]);
1310 /* determine grid index of atom */
1311 grididx
[m
]=x
[ad
[i
]][m
]*invdelta
[m
];
1312 grididx
[m
] = (grididx
[m
]+ngrid
[m
]) % ngrid
[m
];
1315 copy_rvec(xtemp
, x
[ad
[i
]]); /* copy back */
1319 range_check(gx
,0,ngrid
[XX
]);
1320 range_check(gy
,0,ngrid
[YY
]);
1321 range_check(gz
,0,ngrid
[ZZ
]);
1325 /* add atom to grid cell */
1327 newgrid
=&(grid
[gz
][gy
][gx
].a
[gr
]);
1329 newgrid
=&(grid
[gz
][gy
][gx
].d
[gr
]);
1330 if (newgrid
->nr
>= newgrid
->maxnr
) {
1332 DBB(newgrid
->maxnr
);
1333 srenew(newgrid
->atoms
, newgrid
->maxnr
);
1336 newgrid
->atoms
[newgrid
->nr
]=ad
[i
];
1344 static void count_da_grid(ivec ngrid
, t_gridcell
***grid
, t_icell danr
)
1348 for(gr
=0; (gr
<grNR
); gr
++) {
1350 for (zi
=0; zi
<ngrid
[ZZ
]; zi
++)
1351 for (yi
=0; yi
<ngrid
[YY
]; yi
++)
1352 for (xi
=0; xi
<ngrid
[XX
]; xi
++) {
1353 danr
[gr
] += grid
[zi
][yi
][xi
].d
[gr
].nr
;
1359 * Without a box, the grid is 1x1x1, so all loops are 1 long.
1360 * With a rectangular box (bTric==FALSE) all loops are 3 long.
1361 * With a triclinic box all loops are 3 long, except when a cell is
1362 * located next to one of the box edges which is not parallel to the
1363 * x/y-plane, in that case all cells in a line or layer are searched.
1364 * This could be implemented slightly more efficient, but the code
1365 * would get much more complicated.
1367 #define B(n,x,bTric,bEdge) ((n==1) ? x : bTric&&(bEdge) ? 0 : (x-1))
1368 #define E(n,x,bTric,bEdge) ((n==1) ? x : bTric&&(bEdge) ? n-1 : (x+1))
1369 #define GRIDMOD(j,n) (j+n)%(n)
1370 #define LOOPGRIDINNER(x,y,z,xx,yy,zz,xo,yo,zo,n,bTric) \
1371 for(zz=B(n[ZZ],zo,bTric,FALSE); zz<=E(n[ZZ],zo,bTric,FALSE); zz++) { \
1372 z=GRIDMOD(zz,n[ZZ]); \
1373 for(yy=B(n[YY],yo,bTric,z==0||z==n[ZZ]-1); \
1374 yy<=E(n[YY],yo,bTric,z==0||z==n[ZZ]-1); yy++) { \
1375 y=GRIDMOD(yy,n[YY]); \
1376 for(xx=B(n[XX],xo,bTric,y==0||y==n[YY]-1||z==0||z==n[ZZ]-1); \
1377 xx<=E(n[XX],xo,bTric,y==0||y==n[YY]-1||z==0||z==n[ZZ]-1); xx++) { \
1378 x=GRIDMOD(xx,n[XX]);
1379 #define ENDLOOPGRIDINNER \
1385 static void dump_grid(FILE *fp, ivec ngrid, t_gridcell ***grid)
1387 int gr
,x
,y
,z
,sum
[grNR
];
1389 fprintf(fp
,"grid %dx%dx%d\n",ngrid
[XX
],ngrid
[YY
],ngrid
[ZZ
]);
1390 for (gr
=0; gr
<grNR
; gr
++) {
1392 fprintf(fp
,"GROUP %d (%s)\n",gr
,grpnames
[gr
]);
1393 for (z
=0; z
<ngrid
[ZZ
]; z
+=2) {
1394 fprintf(fp
,"Z=%d,%d\n",z
,z
+1);
1395 for (y
=0; y
<ngrid
[YY
]; y
++) {
1396 for (x
=0; x
<ngrid
[XX
]; x
++) {
1397 fprintf(fp
,"%3d",grid
[x
][y
][z
].d
[gr
].nr
);
1398 sum
[gr
]+=grid
[z
][y
][x
].d
[gr
].nr
;
1399 fprintf(fp
,"%3d",grid
[x
][y
][z
].a
[gr
].nr
);
1400 sum
[gr
]+=grid
[z
][y
][x
].a
[gr
].nr
;
1404 if ( (z
+1) < ngrid
[ZZ
] )
1405 for (x
=0; x
<ngrid
[XX
]; x
++) {
1406 fprintf(fp
,"%3d",grid
[z
+1][y
][x
].d
[gr
].nr
);
1407 sum
[gr
]+=grid
[z
+1][y
][x
].d
[gr
].nr
;
1408 fprintf(fp
,"%3d",grid
[z
+1][y
][x
].a
[gr
].nr
);
1409 sum
[gr
]+=grid
[z
+1][y
][x
].a
[gr
].nr
;
1415 fprintf(fp
,"TOTALS:");
1416 for (gr
=0; gr
<grNR
; gr
++)
1417 fprintf(fp
," %d=%d",gr
,sum
[gr
]);
1421 /* New GMX record! 5 * in a row. Congratulations!
1422 * Sorry, only four left.
1424 static void free_grid(ivec ngrid
, t_gridcell
****grid
)
1427 t_gridcell
***g
= *grid
;
1429 for (z
=0; z
<ngrid
[ZZ
]; z
++) {
1430 for (y
=0; y
<ngrid
[YY
]; y
++) {
1439 static void pbc_correct(rvec dx
,matrix box
,rvec hbox
)
1442 for(m
=DIM
-1; m
>=0; m
--) {
1443 if ( dx
[m
] < -hbox
[m
] )
1444 rvec_inc(dx
,box
[m
]);
1445 else if ( dx
[m
] >= hbox
[m
] )
1446 rvec_dec(dx
,box
[m
]);
1450 void pbc_correct_gem(rvec dx
,matrix box
,rvec hbox
)
1456 for(m
=DIM
-1; m
>=0; m
--) {
1457 if ( dx
[m
] < -hbox
[m
] ) {
1459 rvec_inc(dx
,box
[m
]);
1461 if ( dx
[m
] >= hbox
[m
] ) {
1463 rvec_dec(dx
,box
[m
]);
1469 /* Added argument r2cut, changed contact and implemented
1470 * use of second cut-off.
1471 * - Erik Marklund, June 29, 2006
1473 static int is_hbond(t_hbdata
*hb
,int grpd
,int grpa
,int d
,int a
,
1474 real rcut
, real r2cut
, real ccut
,
1475 rvec x
[], bool bBox
, matrix box
,rvec hbox
,
1476 real
*d_ha
, real
*ang
,bool bDA
,int *hhh
,
1477 bool bContact
, bool bMerge
, PSTYPE
*p
)
1480 rvec r_da
,r_ha
,r_dh
, r
;
1482 real rc2
,r2c2
,rda2
,rha2
,ca
;
1483 bool HAinrange
= FALSE
; /* If !bDA. Needed for returning hbDist in a correct way. */
1484 bool daSwap
= FALSE
;
1489 if (((id
= donor_index(&hb
->d
,grpd
,d
)) == NOTSET
) ||
1490 ((ja
= acceptor_index(&hb
->a
,grpa
,a
)) == NOTSET
))
1496 rvec_sub(x
[d
],x
[a
],r_da
);
1497 /* Insert projection code here */
1499 /* if (d>a && ((isInterchangable(hb, d, a, grpd, grpa) && bMerge) || bContact)) */
1500 /* /\* Then this hbond will be found again, or it has already been found. *\/ */
1504 if (d
>a
&& bMerge
&& (bContact
|| isInterchangable(hb
, d
, a
, grpd
, grpa
))) { /* acceptor is also a donor and vice versa? */
1506 daSwap
= TRUE
; /* If so, then their history should be filed with donor and acceptor swapped. */
1509 copy_rvec(r_da
, r
); /* Save this for later */
1510 pbc_correct_gem(r_da
,box
,hbox
);
1512 pbc_correct_gem(r_da
,box
,hbox
);
1515 rda2
= iprod(r_da
,r_da
);
1522 calcBoxDistance(hb
->per
->P
, r
, ri
);
1523 *p
= periodicIndex(ri
, hb
->per
, daSwap
); /* find (or add) periodicity index. */
1527 else if (rda2
< r2c2
)
1534 if (bDA
&& (rda2
> rc2
))
1537 for(h
=0; (h
< hb
->d
.nhydro
[id
]); h
++) {
1538 hh
= hb
->d
.hydro
[id
][h
];
1541 rvec_sub(x
[hh
],x
[a
],r_ha
);
1543 pbc_correct_gem(r_ha
,box
,hbox
);
1545 rha2
= iprod(r_ha
,r_ha
);
1549 calcBoxDistance(hb
->per
->P
, r
, ri
);
1550 *p
= periodicIndex(ri
, hb
->per
, daSwap
); /* find periodicity index. */
1553 if (bDA
|| (!bDA
&& (rha2
<= rc2
))) {
1554 rvec_sub(x
[d
],x
[hh
],r_dh
);
1557 pbc_correct_gem(r_dh
,box
,hbox
);
1559 pbc_correct_gem(r_dh
,box
,hbox
);
1564 ca
= cos_angle(r_dh
,r_da
);
1565 /* if angle is smaller, cos is larger */
1568 *d_ha
= sqrt(bDA
?rda2
:rha2
);
1574 if (bDA
|| (!bDA
&& HAinrange
))
1580 /* Fixed previously undiscovered bug in the merge
1581 code, where the last frame of each hbond disappears.
1582 - Erik Marklund, June 1, 2006 */
1583 /* Added the following arguments:
1584 * ptmp[] - temporary periodicity hisory
1585 * a1 - identity of first acceptor/donor
1586 * a2 - identity of second acceptor/donor
1587 * - Erik Marklund, FEB 20 2010 */
1589 /* Merging is now done on the fly, so do_merge is most likely obsolete now.
1590 * Will do some more testing before removing the function entirely.
1591 * - Erik Marklund, MAY 10 2010 */
1592 static void do_merge(t_hbdata
*hb
,int ntmp
,
1593 unsigned int htmp
[],unsigned int gtmp
[],PSTYPE ptmp
[],
1594 t_hbond
*hb0
,t_hbond
*hb1
, int a1
, int a2
)
1596 /* Here we need to make sure we're treating periodicity in
1597 * the right way for the geminate recombination kinetics. */
1599 int m
,mm
,n00
,n01
,nn0
,nnframes
;
1603 /* Decide where to start from when merging */
1607 nnframes
= max(n00
+ hb0
->nframes
,n01
+ hb1
->nframes
) - nn0
;
1608 /* Initiate tmp arrays */
1609 for(m
=0; (m
<ntmp
); m
++) {
1614 /* Fill tmp arrays with values due to first HB */
1615 /* Once again '<' had to be replaced with '<='
1616 to catch the last frame in which the hbond
1618 - Erik Marklund, June 1, 2006 */
1619 for(m
=0; (m
<=hb0
->nframes
); m
++) {
1621 htmp
[mm
] = is_hb(hb0
->h
[0],m
);
1623 pm
= getPshift(hb
->per
->pHist
[a1
][a2
], m
+hb0
->n0
);
1624 if (pm
> hb
->per
->nper
)
1625 gmx_fatal(FARGS
, "Illegal shift!");
1627 ptmp
[mm
] = pm
; /*hb->per->pHist[a1][a2][m];*/
1630 /* If we're doing geminate recompbination we usually don't need the distances.
1631 * Let's save some memory and time. */
1632 if (TRUE
|| !hb
->bGem
|| hb
->per
->gemtype
== gemAD
){
1633 for(m
=0; (m
<=hb0
->nframes
); m
++) {
1635 gtmp
[mm
] = is_hb(hb0
->g
[0],m
);
1639 for(m
=0; (m
<=hb1
->nframes
); m
++) {
1641 htmp
[mm
] = htmp
[mm
] || is_hb(hb1
->h
[0],m
);
1642 gtmp
[mm
] = gtmp
[mm
] || is_hb(hb1
->g
[0],m
);
1643 if (hb
->bGem
/* && ptmp[mm] != 0 */) {
1645 /* If this hbond has been seen before with donor and acceptor swapped,
1646 * then we need to find the mirrored (*-1) periodicity vector to truely
1647 * merge the hbond history. */
1648 pm
= findMirror(getPshift(hb
->per
->pHist
[a2
][a1
],m
+hb1
->n0
), hb
->per
->p2i
, hb
->per
->nper
);
1649 /* Store index of mirror */
1650 if (pm
> hb
->per
->nper
)
1651 gmx_fatal(FARGS
, "Illegal shift!");
1655 /* Reallocate target array */
1656 if (nnframes
> hb0
->maxframes
) {
1657 srenew(hb0
->h
[0],4+nnframes
/hb
->wordlen
);
1658 srenew(hb0
->g
[0],4+nnframes
/hb
->wordlen
);
1660 clearPshift(&(hb
->per
->pHist
[a1
][a2
]));
1662 /* Copy temp array to target array */
1663 for(m
=0; (m
<=nnframes
); m
++) {
1664 _set_hb(hb0
->h
[0],m
,htmp
[m
]);
1665 _set_hb(hb0
->g
[0],m
,gtmp
[m
]);
1667 addPshift(&(hb
->per
->pHist
[a1
][a2
]), ptmp
[m
], m
+nn0
);
1670 /* Set scalar variables */
1672 hb0
->maxframes
= nnframes
;
1675 /* Added argument bContact for nicer output.
1676 * Erik Marklund, June 29, 2006
1678 static void merge_hb(t_hbdata
*hb
,bool bTwo
, bool bContact
){
1679 int i
,inrnew
,indnew
,j
,ii
,jj
,m
,id
,ia
,grp
,ogrp
,ntmp
;
1680 unsigned int *htmp
,*gtmp
;
1685 indnew
= hb
->nrdist
;
1687 /* Check whether donors are also acceptors */
1688 printf("Merging hbonds with Acceptor and Donor swapped\n");
1690 ntmp
= 2*hb
->max_frames
;
1694 for(i
=0; (i
<hb
->d
.nrd
); i
++) {
1695 fprintf(stderr
,"\r%d/%d",i
+1,hb
->d
.nrd
);
1697 ii
= hb
->a
.aptr
[id
];
1698 for(j
=0; (j
<hb
->a
.nra
); j
++) {
1700 jj
= hb
->d
.dptr
[ia
];
1701 if ((id
!= ia
) && (ii
!= NOTSET
) && (jj
!= NOTSET
) &&
1702 (!bTwo
|| (bTwo
&& (hb
->d
.grp
[i
] != hb
->a
.grp
[j
])))) {
1703 hb0
= hb
->hbmap
[i
][j
];
1704 hb1
= hb
->hbmap
[jj
][ii
];
1705 if (hb0
&& hb1
&& ISHB(hb0
->history
[0]) && ISHB(hb1
->history
[0])) {
1706 do_merge(hb
,ntmp
,htmp
,gtmp
,ptmp
,hb0
,hb1
,i
,j
);
1707 if (ISHB(hb1
->history
[0]))
1709 else if (ISDIST(hb1
->history
[0]))
1713 gmx_incons("No contact history");
1715 gmx_incons("Neither hydrogen bond nor distance");
1719 clearPshift(&(hb
->per
->pHist
[jj
][ii
]));
1723 hb1
->history
[0] = hbNo
;
1728 fprintf(stderr
,"\n");
1729 printf("- Reduced number of hbonds from %d to %d\n",hb
->nrhb
,inrnew
);
1730 printf("- Reduced number of distances from %d to %d\n",hb
->nrdist
,indnew
);
1732 hb
->nrdist
= indnew
;
1738 static void do_nhb_dist(FILE *fp
,t_hbdata
*hb
,real t
)
1740 int i
,j
,k
,n_bound
[MAXHH
],nbtot
;
1744 /* Set array to 0 */
1745 for(k
=0; (k
<MAXHH
); k
++)
1747 /* Loop over possible donors */
1748 for(i
=0; (i
<hb
->d
.nrd
); i
++) {
1749 for(j
=0; (j
<hb
->d
.nhydro
[i
]); j
++)
1750 n_bound
[hb
->d
.nhbonds
[i
][j
]]++;
1752 fprintf(fp
,"%12.5e",t
);
1754 for(k
=0; (k
<MAXHH
); k
++) {
1755 fprintf(fp
," %8d",n_bound
[k
]);
1756 nbtot
+= n_bound
[k
]*k
;
1758 fprintf(fp
," %8d\n",nbtot
);
1761 /* Added argument bContact in do_hblife(...). Also
1762 * added support for -contact in function body.
1763 * - Erik Marklund, May 31, 2006 */
1764 /* Changed the contact code slightly.
1765 * - Erik Marklund, June 29, 2006
1767 static void do_hblife(const char *fn
,t_hbdata
*hb
,bool bMerge
,bool bContact
,
1768 const output_env_t oenv
)
1771 char *leg
[] = { "p(t)", "t p(t)" };
1773 int i
,j
,j0
,k
,m
,nh
,ihb
,ohb
,nhydro
,ndump
=0;
1774 int nframes
= hb
->nframes
;
1777 double sum
,integral
;
1780 snew(h
,hb
->maxhydro
);
1781 snew(histo
,nframes
+1);
1782 /* Total number of hbonds analyzed here */
1783 for(i
=0; (i
<hb
->d
.nrd
); i
++) {
1784 for(k
=0; (k
<hb
->a
.nra
); k
++) {
1785 hbh
= hb
->hbmap
[i
][k
];
1797 for(m
=0; (m
<hb
->maxhydro
); m
++)
1799 h
[nhydro
++] = bContact
? hbh
->g
[m
] : hbh
->h
[m
];
1802 for(nh
=0; (nh
<nhydro
); nh
++) {
1806 /* Changed '<' into '<=' below, just like I
1807 did in the hbm-output-loop in the main code.
1808 - Erik Marklund, May 31, 2006
1810 for(j
=0; (j
<=hbh
->nframes
); j
++) {
1811 ihb
= is_hb(h
[nh
],j
);
1812 if (debug
&& (ndump
< 10))
1813 fprintf(debug
,"%5d %5d\n",j
,ihb
);
1829 fprintf(stderr
,"\n");
1831 fp
= xvgropen(fn
,"Uninterrupted contact lifetime","Time (ps)","()",oenv
);
1833 fp
= xvgropen(fn
,"Uninterrupted hydrogen bond lifetime","Time (ps)","()",
1836 xvgr_legend(fp
,asize(leg
),leg
,oenv
);
1838 while ((j0
> 0) && (histo
[j0
] == 0))
1841 for(i
=0; (i
<=j0
); i
++)
1843 dt
= hb
->time
[1]-hb
->time
[0];
1846 for(i
=1; (i
<=j0
); i
++) {
1847 t
= hb
->time
[i
] - hb
->time
[0] - 0.5*dt
;
1848 x1
= t
*histo
[i
]/sum
;
1849 fprintf(fp
,"%8.3f %10.3e %10.3e\n",t
,histo
[i
]/sum
,x1
);
1854 printf("%s lifetime = %.2f ps\n", bContact
?"Contact":"HB", integral
);
1855 printf("Note that the lifetime obtained in this manner is close to useless\n");
1856 printf("Use the -ac option instead and check the Forward lifetime\n");
1857 please_cite(stdout
,"Spoel2006b");
1862 /* Changed argument bMerge into oneHB to handle contacts properly.
1863 * - Erik Marklund, June 29, 2006
1865 static void dump_ac(t_hbdata
*hb
,bool oneHB
,int nDump
)
1868 int i
,j
,k
,m
,nd
,ihb
,idist
;
1869 int nframes
= hb
->nframes
;
1875 fp
= ffopen("debug-ac.xvg","w");
1876 for(j
=0; (j
<nframes
); j
++) {
1877 fprintf(fp
,"%10.3f",hb
->time
[j
]);
1878 for(i
=nd
=0; (i
<hb
->d
.nrd
) && (nd
< nDump
); i
++) {
1879 for(k
=0; (k
<hb
->a
.nra
) && (nd
< nDump
); k
++) {
1882 hbh
= hb
->hbmap
[i
][k
];
1885 ihb
= is_hb(hbh
->h
[0],j
);
1886 idist
= is_hb(hbh
->g
[0],j
);
1891 for(m
=0; (m
<hb
->maxhydro
) && !ihb
; m
++) {
1892 ihb
= ihb
|| ((hbh
->h
[m
]) && is_hb(hbh
->h
[m
],j
));
1893 idist
= idist
|| ((hbh
->g
[m
]) && is_hb(hbh
->g
[m
],j
));
1895 /* This is not correct! */
1896 /* What isn't correct? -Erik M */
1900 fprintf(fp
," %1d-%1d",ihb
,idist
);
1910 static real
calc_dg(real tau
,real temp
)
1918 return kbt
*log(kbt
*tau
/PLANCK
);
1922 int n0
,n1
,nparams
,ndelta
;
1924 real
*t
,*ct
,*nt
,*kt
,*sigma_ct
,*sigma_nt
,*sigma_kt
;
1928 #include <gsl/gsl_multimin.h>
1929 #include <gsl/gsl_sf.h>
1930 #include <gsl/gsl_version.h>
1932 static double my_f(const gsl_vector
*v
,void *params
)
1934 t_luzar
*tl
= (t_luzar
*)params
;
1936 double tol
=1e-16,chi2
=0;
1940 for(i
=0; (i
<tl
->nparams
); i
++) {
1941 tl
->kkk
[i
] = gsl_vector_get(v
, i
);
1946 for(i
=tl
->n0
; (i
<tl
->n1
); i
+=tl
->ndelta
) {
1947 di
=sqr(k
*tl
->sigma_ct
[i
]) + sqr(kp
*tl
->sigma_nt
[i
]) + sqr(tl
->sigma_kt
[i
]);
1950 chi2
+= sqr(k
*tl
->ct
[i
]-kp
*tl
->nt
[i
]-tl
->kt
[i
])/di
;
1953 fprintf(stderr
,"WARNING: sigma_ct = %g, sigma_nt = %g, sigma_kt = %g\n"
1954 "di = %g k = %g kp = %g\n",tl
->sigma_ct
[i
],
1955 tl
->sigma_nt
[i
],tl
->sigma_kt
[i
],di
,k
,kp
);
1958 chi2
= 0.3*sqr(k
-0.6)+0.7*sqr(kp
-1.3);
1963 static real
optimize_luzar_parameters(FILE *fp
,t_luzar
*tl
,int maxiter
,
1971 const gsl_multimin_fminimizer_type
*T
;
1972 gsl_multimin_fminimizer
*s
;
1975 gsl_multimin_function my_func
;
1978 my_func
.n
= tl
->nparams
;
1979 my_func
.params
= (void *) tl
;
1981 /* Starting point */
1982 x
= gsl_vector_alloc (my_func
.n
);
1983 for(i
=0; (i
<my_func
.n
); i
++)
1984 gsl_vector_set (x
, i
, tl
->kkk
[i
]);
1986 /* Step size, different for each of the parameters */
1987 dx
= gsl_vector_alloc (my_func
.n
);
1988 for(i
=0; (i
<my_func
.n
); i
++)
1989 gsl_vector_set (dx
, i
, 0.01*tl
->kkk
[i
]);
1991 T
= gsl_multimin_fminimizer_nmsimplex
;
1992 s
= gsl_multimin_fminimizer_alloc (T
, my_func
.n
);
1994 gsl_multimin_fminimizer_set (s
, &my_func
, x
, dx
);
1995 gsl_vector_free (x
);
1996 gsl_vector_free (dx
);
1999 fprintf(fp
,"%5s %12s %12s %12s %12s\n","Iter","k","kp","NM Size","Chi2");
2003 status
= gsl_multimin_fminimizer_iterate (s
);
2006 gmx_fatal(FARGS
,"Something went wrong in the iteration in minimizer %s",
2007 gsl_multimin_fminimizer_name(s
));
2009 d2
= gsl_multimin_fminimizer_minimum(s
);
2010 size
= gsl_multimin_fminimizer_size(s
);
2011 status
= gsl_multimin_test_size(size
,tol
);
2013 if (status
== GSL_SUCCESS
)
2015 fprintf(fp
,"Minimum found using %s at:\n",
2016 gsl_multimin_fminimizer_name(s
));
2019 fprintf(fp
,"%5d", iter
);
2020 for(i
=0; (i
<my_func
.n
); i
++)
2021 fprintf(fp
," %12.4e",gsl_vector_get (s
->x
,i
));
2022 fprintf (fp
," %12.4e %12.4e\n",size
,d2
);
2025 while ((status
== GSL_CONTINUE
) && (iter
< maxiter
));
2027 gsl_multimin_fminimizer_free (s
);
2032 static real
quality_of_fit(real chi2
,int N
)
2034 return gsl_sf_gamma_inc_Q((N
-2)/2.0,chi2
/2.0);
2038 static real
optimize_luzar_parameters(FILE *fp
,t_luzar
*tl
,int maxiter
,
2041 fprintf(stderr
,"This program needs the GNU scientific library to work.\n");
2045 static real
quality_of_fit(real chi2
,int N
)
2047 fprintf(stderr
,"This program needs the GNU scientific library to work.\n");
2054 static real
compute_weighted_rates(int n
,real t
[],real ct
[],real nt
[],
2055 real kt
[],real sigma_ct
[],real sigma_nt
[],
2056 real sigma_kt
[],real
*k
,real
*kp
,
2057 real
*sigma_k
,real
*sigma_kp
,
2063 real kkk
=0,kkp
=0,kk2
=0,kp2
=0,chi2
;
2068 for(i
=0; (i
<n
); i
++) {
2069 if (t
[i
] >= fit_start
)
2080 tl
.sigma_ct
= sigma_ct
;
2081 tl
.sigma_nt
= sigma_nt
;
2082 tl
.sigma_kt
= sigma_kt
;
2086 chi2
= optimize_luzar_parameters(debug
,&tl
,1000,1e-3);
2088 *kp
= tl
.kkk
[1] = *kp
;
2090 for(j
=0; (j
<NK
); j
++) {
2091 (void) optimize_luzar_parameters(debug
,&tl
,1000,1e-3);
2094 kk2
+= sqr(tl
.kkk
[0]);
2095 kp2
+= sqr(tl
.kkk
[1]);
2098 *sigma_k
= sqrt(kk2
/NK
- sqr(kkk
/NK
));
2099 *sigma_kp
= sqrt(kp2
/NK
- sqr(kkp
/NK
));
2104 static void smooth_tail(int n
,real t
[],real c
[],real sigma_c
[],real start
,
2105 const output_env_t oenv
)
2108 real e_1
,fitparm
[4];
2112 for(i
=0; (i
<n
); i
++)
2120 do_lmfit(n
,c
,sigma_c
,0,t
,start
,t
[n
-1],oenv
,bDebugMode(),effnEXP2
,fitparm
,0);
2123 void analyse_corr(int n
,real t
[],real ct
[],real nt
[],real kt
[],
2124 real sigma_ct
[],real sigma_nt
[],real sigma_kt
[],
2125 real fit_start
,real temp
,real smooth_tail_start
,
2126 const output_env_t oenv
)
2129 real k
=1,kp
=1,kow
=1;
2130 real Q
=0,chi22
,chi2
,dg
,dgp
,tau_hb
,dtau
,tau_rlx
,e_1
,dt
,sigma_k
,sigma_kp
,ddg
;
2131 double tmp
,sn2
=0,sc2
=0,sk2
=0,scn
=0,sck
=0,snk
=0;
2132 bool bError
= (sigma_ct
!= NULL
) && (sigma_nt
!= NULL
) && (sigma_kt
!= NULL
);
2134 if (smooth_tail_start
>= 0) {
2135 smooth_tail(n
,t
,ct
,sigma_ct
,smooth_tail_start
,oenv
);
2136 smooth_tail(n
,t
,nt
,sigma_nt
,smooth_tail_start
,oenv
);
2137 smooth_tail(n
,t
,kt
,sigma_kt
,smooth_tail_start
,oenv
);
2139 for(i0
=0; (i0
<n
-2) && ((t
[i0
]-t
[0]) < fit_start
); i0
++)
2142 for(i
=i0
; (i
<n
); i
++) {
2150 printf("Hydrogen bond thermodynamics at T = %g K\n",temp
);
2151 tmp
= (sn2
*sc2
-sqr(scn
));
2152 if ((tmp
> 0) && (sn2
> 0)) {
2153 k
= (sn2
*sck
-scn
*snk
)/tmp
;
2154 kp
= (k
*scn
-snk
)/sn2
;
2157 for(i
=i0
; (i
<n
); i
++) {
2158 chi2
+= sqr(k
*ct
[i
]-kp
*nt
[i
]-kt
[i
]);
2160 chi22
= compute_weighted_rates(n
,t
,ct
,nt
,kt
,sigma_ct
,sigma_nt
,
2162 &sigma_k
,&sigma_kp
,fit_start
);
2163 Q
= quality_of_fit(chi2
,2);
2164 ddg
= BOLTZ
*temp
*sigma_k
/k
;
2165 printf("Fitting paramaters chi^2 = %10g, Quality of fit = %10g\n",
2167 printf("The Rate and Delta G are followed by an error estimate\n");
2168 printf("----------------------------------------------------------\n"
2169 "Type Rate (1/ps) Sigma Time (ps) DG (kJ/mol) Sigma\n");
2170 printf("Forward %10.3f %6.2f %8.3f %10.3f %6.2f\n",
2171 k
,sigma_k
,1/k
,calc_dg(1/k
,temp
),ddg
);
2172 ddg
= BOLTZ
*temp
*sigma_kp
/kp
;
2173 printf("Backward %10.3f %6.2f %8.3f %10.3f %6.2f\n",
2174 kp
,sigma_kp
,1/kp
,calc_dg(1/kp
,temp
),ddg
);
2178 for(i
=i0
; (i
<n
); i
++) {
2179 chi2
+= sqr(k
*ct
[i
]-kp
*nt
[i
]-kt
[i
]);
2181 printf("Fitting parameters chi^2 = %10g\nQ = %10g\n",
2183 printf("--------------------------------------------------\n"
2184 "Type Rate (1/ps) Time (ps) DG (kJ/mol) Chi^2\n");
2185 printf("Forward %10.3f %8.3f %10.3f %10g\n",
2186 k
,1/k
,calc_dg(1/k
,temp
),chi2
);
2187 printf("Backward %10.3f %8.3f %10.3f\n",
2188 kp
,1/kp
,calc_dg(1/kp
,temp
));
2193 printf("One-way %10.3f %s%8.3f %10.3f\n",
2194 kow
,bError
? " " : "",1/kow
,calc_dg(1/kow
,temp
));
2197 printf(" - Numerical problems computing HB thermodynamics:\n"
2198 "sc2 = %g sn2 = %g sk2 = %g sck = %g snk = %g scn = %g\n",
2199 sc2
,sn2
,sk2
,sck
,snk
,scn
);
2200 /* Determine integral of the correlation function */
2201 tau_hb
= evaluate_integral(n
,t
,ct
,NULL
,(t
[n
-1]-t
[0])/2,&dtau
);
2202 printf("Integral %10.3f %s%8.3f %10.3f\n",1/tau_hb
,
2203 bError
? " " : "",tau_hb
,calc_dg(tau_hb
,temp
));
2205 for(i
=0; (i
<n
-2); i
++) {
2206 if ((ct
[i
] > e_1
) && (ct
[i
+1] <= e_1
)) {
2211 /* Determine tau_relax from linear interpolation */
2212 tau_rlx
= t
[i
]-t
[0] + (e_1
-ct
[i
])*(t
[i
+1]-t
[i
])/(ct
[i
+1]-ct
[i
]);
2213 printf("Relaxation %10.3f %8.3f %s%10.3f\n",1/tau_rlx
,
2214 tau_rlx
,bError
? " " : "",
2215 calc_dg(tau_rlx
,temp
));
2219 printf("Correlation functions too short to compute thermodynamics\n");
2222 void compute_derivative(int nn
,real x
[],real y
[],real dydx
[])
2226 /* Compute k(t) = dc(t)/dt */
2227 for(j
=1; (j
<nn
-1); j
++)
2228 dydx
[j
] = (y
[j
+1]-y
[j
-1])/(x
[j
+1]-x
[j
-1]);
2229 /* Extrapolate endpoints */
2230 dydx
[0] = 2*dydx
[1] - dydx
[2];
2231 dydx
[nn
-1] = 2*dydx
[nn
-2] - dydx
[nn
-3];
2234 static void parallel_print(int *data
, int nThreads
)
2236 /* This prints the donors on which each tread is currently working. */
2239 fprintf(stderr
, "\r");
2240 for (i
=0; i
<nThreads
; i
++)
2241 fprintf(stderr
, "%-7i",data
[i
]);
2244 static void normalizeACF(real
*ct
, real
*gt
, int len
)
2246 real ct_fac
, gt_fac
;
2249 /* Xu and Berne use the same normalization constant */
2252 gt_fac
= (gt
!=NULL
&& gt
[0]!=0) ? 1.0/gt
[0] : 0;
2253 printf("Normalization for c(t) = %g for gh(t) = %g\n",ct_fac
,gt_fac
);
2254 for (i
=0; i
<len
; i
++)
2262 /* Added argument bContact in do_hbac(...). Also
2263 * added support for -contact in the actual code.
2264 * - Erik Marklund, May 31, 2006 */
2265 /* Changed contact code and added argument R2
2266 * - Erik Marklund, June 29, 2006
2268 static void do_hbac(const char *fn
,t_hbdata
*hb
,real aver_nhb
,real aver_dist
,
2269 int nDump
,bool bMerge
,bool bContact
, real fit_start
,
2270 real temp
,bool R2
,real smooth_tail_start
, const output_env_t oenv
,
2271 t_gemParams
*params
, const char *gemType
, int nThreads
,
2272 const int NN
, const bool bBallistic
, const bool bGemFit
)
2275 int i
,j
,k
,m
,n
,o
,nd
,ihb
,idist
,n2
,nn
,iter
;
2276 static char *legNN
[] = { "Ac(t)",
2278 static char **legGem
;
2281 snew(legGem
[i
], 128);
2282 sprintf(legGem
[0], "Ac\\s%s\\v{}\\z{}(t)", gemType
);
2283 sprintf(legGem
[1], "Ac'(t)");
2284 sprintf(legGem
[2], "Ac\\s%s,fit\\v{}\\z{}(t)", gemType
);
2286 static char *legLuzar
[] = { "Ac\\sfin sys\\v{}\\z{}(t)",
2288 "Cc\\scontact,hb\\v{}\\z{}(t)",
2289 "-dAc\\sfs\\v{}\\z{}/dt" };
2293 real
*rhbex
=NULL
,*ht
,*gt
,*ght
,*dght
,*kt
;
2294 real
*ct
,*p_ct
,tail
,tail2
,dtail
,ct_fac
,ght_fac
,*cct
;
2295 const real tol
= 1e-3;
2296 int nframes
= hb
->nframes
,nf
;
2297 unsigned int **h
,**g
;
2298 int nh
,nhbonds
,nhydro
,ngh
;
2300 PSTYPE p
, *pfound
= NULL
, np
;
2302 int *ptimes
=NULL
, *poff
=NULL
, anhb
, n0
, mMax
=INT_MIN
;
2303 real
**rHbExGem
= NULL
;
2307 double *ctdouble
, *timedouble
, *fittedct
;
2308 double fittolerance
=0.1;
2310 enum {AC_NONE
, AC_NN
, AC_GEM
, AC_LUZAR
};
2314 int *dondata
=NULL
, thisThread
;
2317 printf("Doing autocorrelation ");
2319 /* Decide what kind of ACF calculations to do. */
2320 if (NN
> NN_NONE
&& NN
< NN_NR
) {
2321 #ifdef HAVE_NN_LOOPS
2323 printf("using the energy estimate.\n");
2326 printf("Can't do the NN-loop. Yet.\n");
2328 } else if (hb
->bGem
) {
2330 printf("according to the reversible geminate recombination model by Omer Markowitch.\n");
2333 printf("according to the theory of Luzar and Chandler.\n");
2337 /* build hbexist matrix in reals for autocorr */
2338 /* Allocate memory for computing ACF (rhbex) and aggregating the ACF (ct) */
2340 while (n2
< nframes
)
2345 if (acType
!= AC_NN
||
2352 snew(h
,hb
->maxhydro
);
2353 snew(g
,hb
->maxhydro
);
2356 /* Dump hbonds for debugging */
2357 dump_ac(hb
,bMerge
||bContact
,nDump
);
2359 /* Total number of hbonds analyzed here */
2364 /* ------------------------------------------------
2365 * I got tired of waiting for the acf calculations
2366 * and parallelized it with openMP
2367 * set environment variable CFLAGS = "-fopenmp" when running
2368 * configure and define DOUSEOPENMP to make use of it.
2371 #ifdef HAVE_OPENMP /* ================================================= \
2372 * Set up the OpenMP stuff, |
2373 * like the number of threads and such |
2375 if (acType
!= AC_LUZAR
)
2377 #if (_OPENMP >= 200805) /* =====================\ */
2378 nThreads
= min((nThreads
<= 0) ? INT_MAX
: nThreads
, omp_get_thread_limit());
2380 nThreads
= min((nThreads
<= 0) ? INT_MAX
: nThreads
, omp_get_num_procs());
2381 #endif /* _OPENMP >= 200805 ====================/ */
2383 omp_set_num_threads(nThreads
);
2384 snew(dondata
, nThreads
);
2385 for (i
=0; i
<nThreads
; i
++)
2387 printf("ACF calculations parallelized with OpenMP using %i threads.\n"
2388 "Expect close to linear scaling over this donor-loop.\n", nThreads
);
2390 fprintf(stderr
, "Donors: [thread no]\n");
2393 for (i
=0;i
<nThreads
;i
++) {
2394 snprintf(tmpstr
, 7, "[%i]", i
);
2395 fprintf(stderr
, "%-7s", tmpstr
);
2398 fprintf(stderr
, "\n"); /* | */
2400 #endif /* HAVE_OPENMP ===================================================/ */
2403 /* Build the ACF according to acType */
2408 #ifdef HAVE_NN_LOOPS
2409 /* Here we're using the estimated energy for the hydrogen bonds. */
2411 #ifdef HAVE_OPENMP /* ==================================\ */
2412 #pragma omp parallel \
2413 private(i, j, k, nh, E, rhbex, thisThread), \
2417 thisThread
= omp_get_thread_num();
2419 #endif /* ==============================================/ */
2422 memset(rhbex
, 0, n2
*sizeof(real
)); /* Trust no-one, not even malloc()! */
2424 #ifdef HAVE_OPENMP /* ################################################## \
2429 #pragma omp for schedule (dynamic)
2431 for (i
=0; i
<hb
->d
.nrd
; i
++) /* loop over donors */
2433 #ifdef HAVE_OPENMP /* ====== Write some output ======\ */
2434 #pragma omp critical
2436 dondata
[thisThread
] = i
;
2437 parallel_print(dondata
, nThreads
);
2440 fprintf(stderr
, "\r %i", i
);
2441 #endif /* ===========================================/ */
2443 for (j
=0; j
<hb
->a
.nra
; j
++) /* loop over acceptors */
2445 for (nh
=0; nh
<hb
->d
.nhydro
[i
]; nh
++) /* loop over donors' hydrogens */
2447 E
= hb
->hbE
.E
[i
][j
][nh
];
2450 for (k
=0; k
<nframes
; k
++)
2452 if (E
[k
] != NONSENSE_E
)
2453 rhbex
[k
] = (real
)E
[k
];
2456 low_do_autocorr(NULL
,oenv
,NULL
,nframes
,1,-1,&(rhbex
),hb
->time
[1]-hb
->time
[0],
2457 eacNormal
,1,FALSE
,bNorm
,FALSE
,0,-1,0,1);
2459 #pragma omp critical
2462 for(k
=0; (k
<nn
); k
++)
2473 } /* End of parallel block # */
2474 /* ##############################################################/ */
2477 normalizeACF(ct
, NULL
, nn
);
2479 snew(timedouble
, nn
);
2480 for (j
=0; j
<nn
; j
++)
2482 timedouble
[j
]=(double)(hb
->time
[j
]);
2483 ctdouble
[j
]=(double)(ct
[j
]);
2486 /* Remove ballistic term */
2487 if (params
->ballistic
/params
->tDelta
>= params
->nExpFit
*2+1)
2488 takeAwayBallistic(ctdouble
, timedouble
, nn
, params
->ballistic
, params
->nExpFit
, params
->bDt
);
2490 printf("\nNumber of data points is less than the number of parameters to fit\n."
2491 "The system is underdetermined, hence no ballistic term can be found.\n\n");
2493 fp
= xvgropen(fn
, "Hydrogen Bond Autocorrelation","Time (ps)","C(t)");
2494 xvgr_legend(fp
,asize(legNN
),legNN
);
2496 for(j
=0; (j
<nn
); j
++)
2497 fprintf(fp
,"%10g %10g %10g\n",
2498 hb
->time
[j
]-hb
->time
[0],
2505 #endif /* HAVE_NN_LOOPS */
2506 break; /* case AC_NN */
2510 memset(ct
,0,2*n2
*sizeof(real
));
2512 fprintf(stderr
, "Donor:\n");
2515 #define __ACDATA p_ct
2518 #ifdef HAVE_OPENMP /* =========================================\
2520 #pragma omp parallel default(none) \
2521 private(i, k, nh, hbh, pHist, h, g, n0, nf, np, j, m, \
2522 pfound, poff, rHbExGem, p, ihb, mMax, \
2524 shared(hb, dondata, ct, nn, nThreads, n2, stderr, bNorm, \
2525 nframes, bMerge, bContact)
2526 { /* ########## THE START OF THE ENORMOUS PARALLELIZED BLOCK! ########## */
2529 thisThread
= omp_get_thread_num();
2530 snew(h
,hb
->maxhydro
);
2531 snew(g
,hb
->maxhydro
);
2538 memset(p_ct
,0,2*n2
*sizeof(real
));
2540 /* I'm using a chunk size of 1, since I expect \
2541 * the overhead to be really small compared \
2542 * to the actual calculations \ */
2543 #pragma omp for schedule(dynamic,1) nowait /* \ */
2544 #endif /* HAVE_OPENMP =========================================/ */
2546 for (i
=0; i
<hb
->d
.nrd
; i
++) {
2548 #pragma omp critical
2550 dondata
[thisThread
] = i
;
2551 parallel_print(dondata
, nThreads
);
2554 fprintf(stderr
, "\r %i", i
);
2557 for (k
=0; k
<hb
->a
.nra
; k
++) {
2558 for (nh
=0; nh
< ((bMerge
|| bContact
) ? 1 : hb
->d
.nhydro
[i
]); nh
++) {
2559 hbh
= hb
->hbmap
[i
][k
];
2561 /* Note that if hb->per->gemtype==gemDD, then distances will be stored in
2562 * hb->hbmap[d][a].h array anyway, because the contact flag will be set.
2563 * hence, it's only with the gemAD mode that hb->hbmap[d][a].g will be used. */
2564 pHist
= &(hb
->per
->pHist
[i
][k
]);
2565 if (ISHB(hbh
->history
[nh
]) && pHist
->len
!= 0) {
2567 /* No need for a critical section */
2568 /* #ifdef HAVE_OPENMP */
2569 /* #pragma omp critical */
2573 g
[nh
] = hb
->per
->gemtype
==gemAD
? hbh
->g
[nh
] : NULL
;
2577 /* count the number of periodic shifts encountered and store
2578 * them in separate arrays. */
2580 for (j
=0; j
<pHist
->len
; j
++)
2583 for (m
=0; m
<=np
; m
++) {
2584 if (m
== np
) { /* p not recognized in list. Add it and set up new array. */
2586 if (np
>hb
->per
->nper
)
2587 gmx_fatal(FARGS
, "Too many pshifts. Something's utterly wrong here.");
2588 if (m
>=mMax
) { /* Extend the arrays.
2589 * Doing it like this, using mMax to keep track of the sizes,
2590 * eleviates the need for freeing and re-allocating the arrays
2591 * when taking on the next donor-acceptor pair */
2593 srenew(pfound
,np
); /* The list of found periodic shifts. */
2594 srenew(rHbExGem
,np
); /* The hb existence functions (-aver_hb). */
2595 snew(rHbExGem
[m
],2*n2
);
2599 /* This shouldn't have to be critical, right? */
2600 /* #ifdef HAVE_OPENMP */
2601 /* #pragma omp critical */
2604 if (rHbExGem
!= NULL
&& rHbExGem
[m
] != NULL
) {
2605 /* This must be done, as this array was most likey
2606 * used to store stuff in some previous iteration. */
2607 memset(rHbExGem
[m
], 0, (sizeof(real
)) * (2*n2
));
2610 fprintf(stderr
, "rHbExGem not initialized! m = %i\n", m
);
2619 } /* m: Loop over found shifts */
2620 } /* j: Loop over shifts */
2622 /* Now unpack and disentangle the existence funtions. */
2623 for (j
=0; j
<nf
; j
++) {
2629 * pfound: list of periodic shifts found for this pair.
2630 * poff: list of frame offsets; that is, the first
2631 * frame a hbond has a particular periodic shift. */
2632 p
= getPshift(*pHist
, j
+n0
);
2635 for (m
=0; m
<np
; m
++)
2640 gmx_fatal(FARGS
,"Shift not found, but must be there.");
2643 ihb
= is_hb(h
[nh
],j
) || ((hb
->per
->gemtype
!=gemAD
|| j
==0) ? FALSE
: is_hb(g
[nh
],j
));
2647 poff
[m
] = j
; /* Here's where the first hbond with shift p is,
2648 * relative to the start of h[0].*/
2650 gmx_fatal(FARGS
, "j<poff[m]");
2651 rHbExGem
[m
][j
-poff
[m
]] += 1;
2656 /* Now, build ac. */
2657 for (m
=0; m
<np
; m
++) {
2658 if (rHbExGem
[m
][0]>0/* && n0+poff[n]<nn */) {
2659 low_do_autocorr(NULL
,oenv
,NULL
,nframes
,1,-1,&(rHbExGem
[m
]),hb
->time
[1]-hb
->time
[0],
2660 eacNormal
,1,FALSE
,bNorm
,FALSE
,0,-1,0,1);
2661 for(j
=0; (j
<nn
); j
++)
2662 __ACDATA
[j
] += rHbExGem
[m
][j
];
2664 } /* Building of ac. */
2667 } /* hydrogen loop */
2668 } /* acceptor loop */
2671 for (m
=0; m
<=mMax
; m
++) {
2680 #ifdef HAVE_OPENMP /* =======================================\ */
2681 #pragma omp critical
2683 for (i
=0; i
<nn
; i
++)
2688 } /* ########## THE END OF THE ENORMOUS PARALLELIZED BLOCK ########## */
2690 #endif /* HAVE_OPENMP =======================================/ */
2692 normalizeACF(ct
, NULL
, nn
);
2694 fprintf(stderr
, "\n\nACF successfully calculated.\n");
2696 /* Use this part to fit to geminate recombination - JCP 129, 84505 (2008) */
2699 snew(timedouble
, nn
);
2703 timedouble
[j
]=(double)(hb
->time
[j
]);
2704 ctdouble
[j
]=(double)(ct
[j
]);
2707 /* Remove ballistic term */
2709 if (params
->ballistic
/params
->tDelta
>= params
->nExpFit
*2+1)
2710 takeAwayBallistic(ctdouble
, timedouble
, nn
, params
->ballistic
, params
->nExpFit
, params
->bDt
);
2712 printf("\nNumber of data points is less than the number of parameters to fit\n."
2713 "The system is underdetermined, hence no ballistic term can be found.\n\n");
2716 fitGemRecomb(ctdouble
, timedouble
, &fittedct
, nn
, params
);
2720 fp
= xvgropen(fn
, "Contact Autocorrelation","Time (ps)","C(t)",oenv
);
2722 fp
= xvgropen(fn
, "Hydrogen Bond Autocorrelation","Time (ps)","C(t)",oenv
);
2723 xvgr_legend(fp
,asize(legGem
),legGem
,oenv
);
2725 for(j
=0; (j
<nn
); j
++)
2726 fprintf(fp
,"%10g %10g %10g %10g\n",
2727 hb
->time
[j
]-hb
->time
[0],ct
[j
],ctdouble
[j
],fittedct
[j
]);
2735 break; /* case AC_GEM */
2748 for(i
=0; (i
<hb
->d
.nrd
); i
++) {
2749 for(k
=0; (k
<hb
->a
.nra
); k
++) {
2751 hbh
= hb
->hbmap
[i
][k
];
2754 if (bMerge
|| bContact
) {
2755 if (ISHB(hbh
->history
[0])) {
2762 for(m
=0; (m
<hb
->maxhydro
); m
++)
2763 if (bContact
? ISDIST(hbh
->history
[m
]) : ISHB(hbh
->history
[m
])) {
2764 g
[nhydro
] = hbh
->g
[m
];
2765 h
[nhydro
] = hbh
->h
[m
];
2771 for(nh
=0; (nh
<nhydro
); nh
++) {
2772 int nrint
= bContact
? hb
->nrdist
: hb
->nrhb
;
2773 if ((((nhbonds
+1) % 10) == 0) || (nhbonds
+1 == nrint
))
2774 fprintf(stderr
,"\rACF %d/%d",nhbonds
+1,nrint
);
2776 for(j
=0; (j
<nframes
); j
++) {
2777 /* Changed '<' into '<=' below, just like I did in
2778 the hbm-output-loop in the gmx_hbond() block.
2779 - Erik Marklund, May 31, 2006 */
2781 ihb
= is_hb(h
[nh
],j
);
2782 idist
= is_hb(g
[nh
],j
);
2787 rhbex
[j
] = ihb
-aver_nhb
;
2788 /* For contacts: if a second cut-off is provided, use it,
2789 * otherwise use g(t) = 1-h(t) */
2790 if (!R2
&& bContact
)
2793 gt
[j
] = idist
*(1-ihb
);
2799 /* The autocorrelation function is normalized after summation only */
2800 low_do_autocorr(NULL
,oenv
,NULL
,nframes
,1,-1,&rhbex
,hb
->time
[1]-hb
->time
[0],
2801 eacNormal
,1,FALSE
,bNorm
,FALSE
,0,-1,0,1);
2803 /* Cross correlation analysis for thermodynamics */
2804 for(j
=nframes
; (j
<n2
); j
++) {
2809 cross_corr(n2
,ht
,gt
,dght
);
2811 for(j
=0; (j
<nn
); j
++) {
2819 fprintf(stderr
,"\n");
2822 normalizeACF(ct
, gt
, nn
);
2824 /* Determine tail value for statistics */
2827 for(j
=nn
/2; (j
<nn
); j
++) {
2829 tail2
+= ct
[j
]*ct
[j
];
2831 tail
/= (nn
- nn
/2);
2832 tail2
/= (nn
- nn
/2);
2833 dtail
= sqrt(tail2
-tail
*tail
);
2835 /* Check whether the ACF is long enough */
2837 printf("\nWARNING: Correlation function is probably not long enough\n"
2838 "because the standard deviation in the tail of C(t) > %g\n"
2839 "Tail value (average C(t) over second half of acf): %g +/- %g\n",
2842 for(j
=0; (j
<nn
); j
++) {
2844 ct
[j
] = (cct
[j
]-tail
)/(1-tail
);
2846 /* Compute negative derivative k(t) = -dc(t)/dt */
2847 compute_derivative(nn
,hb
->time
,ct
,kt
);
2848 for(j
=0; (j
<nn
); j
++)
2853 fp
= xvgropen(fn
, "Contact Autocorrelation","Time (ps)","C(t)",oenv
);
2855 fp
= xvgropen(fn
, "Hydrogen Bond Autocorrelation","Time (ps)","C(t)",oenv
);
2856 xvgr_legend(fp
,asize(legLuzar
),legLuzar
, oenv
);
2859 for(j
=0; (j
<nn
); j
++)
2860 fprintf(fp
,"%10g %10g %10g %10g %10g\n",
2861 hb
->time
[j
]-hb
->time
[0],ct
[j
],cct
[j
],ght
[j
],kt
[j
]);
2864 analyse_corr(nn
,hb
->time
,ct
,ght
,kt
,NULL
,NULL
,NULL
,
2865 fit_start
,temp
,smooth_tail_start
,oenv
);
2867 do_view(oenv
,fn
,NULL
);
2879 break; /* case AC_LUZAR */
2882 gmx_fatal(FARGS
, "Unrecognized type of ACF-calulation. acType = %i.", acType
);
2883 } /* switch (acType) */
2886 static void init_hbframe(t_hbdata
*hb
,int nframes
,real t
)
2890 hb
->time
[nframes
] = t
;
2891 hb
->nhb
[nframes
] = 0;
2892 hb
->ndist
[nframes
] = 0;
2893 for (i
=0; (i
<max_hx
); i
++)
2894 hb
->nhx
[nframes
][i
]=0;
2895 /* Loop invalidated */
2896 if (hb
->bHBmap
&& 0)
2897 for (i
=0; (i
<hb
->d
.nrd
); i
++)
2898 for (j
=0; (j
<hb
->a
.nra
); j
++)
2899 for (m
=0; (m
<hb
->maxhydro
); m
++)
2900 if (hb
->hbmap
[i
][j
] && hb
->hbmap
[i
][j
]->h
[m
])
2901 set_hb(hb
,i
,m
,j
,nframes
,HB_NO
);
2902 /*set_hb(hb->hbmap[i][j]->h[m],nframes-hb->hbmap[i][j]->n0,HB_NO);*/
2905 static void analyse_donor_props(const char *fn
,t_hbdata
*hb
,int nframes
,real t
,
2906 const output_env_t oenv
)
2908 static FILE *fp
= NULL
;
2909 char *leg
[] = { "Nbound", "Nfree" };
2910 int i
,j
,k
,nbound
,nb
,nhtot
;
2915 fp
= xvgropen(fn
,"Donor properties","Time (ps)","Number",oenv
);
2916 xvgr_legend(fp
,asize(leg
),leg
,oenv
);
2920 for(i
=0; (i
<hb
->d
.nrd
); i
++) {
2921 for(k
=0; (k
<hb
->d
.nhydro
[i
]); k
++) {
2924 for(j
=0; (j
<hb
->a
.nra
) && (nb
== 0); j
++) {
2925 if (hb
->hbmap
[i
][j
] && hb
->hbmap
[i
][j
]->h
[k
] &&
2926 is_hb(hb
->hbmap
[i
][j
]->h
[k
],nframes
))
2932 fprintf(fp
,"%10.3e %6d %6d\n",t
,nbound
,nhtot
-nbound
);
2935 static void dump_hbmap(t_hbdata
*hb
,
2936 int nfile
,t_filenm fnm
[],bool bTwo
,bool bInsert
,
2937 bool bContact
, int isize
[],int *index
[],char *grpnames
[],
2941 int ddd
,hhh
,aaa
,i
,j
,k
,m
,grp
;
2942 char ds
[32],hs
[32],as
[32];
2945 fp
= opt2FILE("-hbn",nfile
,fnm
,"w");
2946 if (opt2bSet("-g",nfile
,fnm
)) {
2947 fplog
= ffopen(opt2fn("-g",nfile
,fnm
),"w");
2949 fprintf(fplog
,"# %10s %12s %12s\n","Donor","Hydrogen","Acceptor");
2951 fprintf(fplog
,"# %10s %12s %12s\n","Donor","Hydrogen","Acceptor");
2955 for (grp
=gr0
; grp
<=(bTwo
?gr1
:gr0
); grp
++) {
2956 fprintf(fp
,"[ %s ]",grpnames
[grp
]);
2957 for (i
=0; i
<isize
[grp
]; i
++) {
2958 fprintf(fp
,(i
%15)?" ":"\n");
2959 fprintf(fp
," %4u",index
[grp
][i
]+1);
2963 Added -contact support below.
2964 - Erik Marklund, May 29, 2006
2967 fprintf(fp
,"[ donors_hydrogens_%s ]\n",grpnames
[grp
]);
2968 for (i
=0; (i
<hb
->d
.nrd
); i
++) {
2969 if (hb
->d
.grp
[i
] == grp
) {
2970 for(j
=0; (j
<hb
->d
.nhydro
[i
]); j
++)
2971 fprintf(fp
," %4u %4u",hb
->d
.don
[i
]+1,
2972 hb
->d
.hydro
[i
][j
]+1);
2977 fprintf(fp
,"[ acceptors_%s ]",grpnames
[grp
]);
2978 for (i
=0; (i
<hb
->a
.nra
); i
++) {
2979 if (hb
->a
.grp
[i
] == grp
) {
2980 fprintf(fp
,(i
%15 && !first
)?" ":"\n");
2981 fprintf(fp
," %4u",hb
->a
.acc
[i
]+1);
2989 fprintf(fp
,bContact
? "[ contacts_%s-%s ]\n" :
2990 "[ hbonds_%s-%s ]\n",grpnames
[0],grpnames
[1]);
2992 fprintf(fp
,bContact
? "[ contacts_%s ]" : "[ hbonds_%s ]\n",grpnames
[0]);
2994 for(i
=0; (i
<hb
->d
.nrd
); i
++) {
2996 for(k
=0; (k
<hb
->a
.nra
); k
++) {
2998 for(m
=0; (m
<hb
->d
.nhydro
[i
]); m
++) {
2999 if (hb
->hbmap
[i
][k
] && ISHB(hb
->hbmap
[i
][k
]->history
[m
])) {
3000 sprintf(ds
,"%s",mkatomname(atoms
,ddd
));
3001 sprintf(as
,"%s",mkatomname(atoms
,aaa
));
3003 fprintf(fp
," %6u %6u\n",ddd
+1,aaa
+1);
3005 fprintf(fplog
,"%12s %12s\n",ds
,as
);
3007 hhh
= hb
->d
.hydro
[i
][m
];
3008 sprintf(hs
,"%s",mkatomname(atoms
,hhh
));
3009 fprintf(fp
," %6u %6u %6u\n",ddd
+1,hhh
+1,aaa
+1);
3011 fprintf(fplog
,"%12s %12s %12s\n",ds
,hs
,as
);
3019 fprintf(fp
,"[ insert_%s->%s-%s ]",
3020 grpnames
[2],grpnames
[0],grpnames
[1]);
3022 fprintf(fp
,"[ insert_%s->%s ]",grpnames
[2],grpnames
[0]);
3025 /* for(i=0; (i<hb->nrhb); i++) {
3026 if (hb->hb[i].bInsert) {
3027 fprintf(fp,(j%15)?" ":"\n");
3028 fprintf(fp,"%4d",i+1);
3040 /* sync_hbdata() updates the parallel t_hbdata p_hb using hb as template.
3041 * It mimics add_frames() and init_frame() to some extent. */
3042 static void sync_hbdata(t_hbdata
*hb
, t_hbdata
*p_hb
,
3043 int nframes
, real t
)
3046 if (nframes
>= p_hb
->max_frames
)
3048 p_hb
->max_frames
+= 4096;
3049 srenew(p_hb
->nhb
, p_hb
->max_frames
);
3050 srenew(p_hb
->ndist
, p_hb
->max_frames
);
3051 srenew(p_hb
->n_bound
, p_hb
->max_frames
);
3052 srenew(p_hb
->nhx
, p_hb
->max_frames
);
3054 srenew(p_hb
->danr
, p_hb
->max_frames
);
3055 memset(&(p_hb
->nhb
[nframes
]), 0, sizeof(int) * (p_hb
->max_frames
-nframes
));
3056 memset(&(p_hb
->ndist
[nframes
]), 0, sizeof(int) * (p_hb
->max_frames
-nframes
));
3057 p_hb
->nhb
[nframes
] = 0;
3058 p_hb
->ndist
[nframes
] = 0;
3061 p_hb
->nframes
= nframes
;
3064 /* p_hb->nhx[nframes][i] */
3066 memset(&(p_hb
->nhx
[nframes
]), 0 ,sizeof(int)*max_hx
); /* zero the helix count for this frame */
3068 /* hb->per will remain constant througout the frame loop,
3069 * even though the data its members point to will change,
3070 * hence no need for re-syncing. */
3074 int gmx_hbond(int argc
,char *argv
[])
3076 const char *desc
[] = {
3077 "g_hbond computes and analyzes hydrogen bonds. Hydrogen bonds are",
3078 "determined based on cutoffs for the angle Acceptor - Donor - Hydrogen",
3079 "(zero is extended) and the distance Hydrogen - Acceptor.",
3080 "OH and NH groups are regarded as donors, O is an acceptor always,",
3081 "N is an acceptor by default, but this can be switched using",
3082 "[TT]-nitacc[tt]. Dummy hydrogen atoms are assumed to be connected",
3083 "to the first preceding non-hydrogen atom.[PAR]",
3085 "You need to specify two groups for analysis, which must be either",
3086 "identical or non-overlapping. All hydrogen bonds between the two",
3087 "groups are analyzed.[PAR]",
3089 "If you set -shell, you will be asked for an additional index group",
3090 "which should contain exactly one atom. In this case, only hydrogen",
3091 "bonds between atoms within the shell distance from the one atom are",
3094 /* "It is also possible to analyse specific hydrogen bonds with",
3095 "[TT]-sel[tt]. This index file must contain a group of atom triplets",
3096 "Donor Hydrogen Acceptor, in the following way:[PAR]",
3104 "Note that the triplets need not be on separate lines.",
3105 "Each atom triplet specifies a hydrogen bond to be analyzed,",
3106 "note also that no check is made for the types of atoms.[PAR]",
3108 "[TT]-ins[tt] turns on computing solvent insertion into hydrogen bonds.",
3109 "In this case an additional group must be selected, specifying the",
3110 "solvent molecules.[PAR]",
3112 "[BB]Output:[bb][BR]",
3113 "[TT]-num[tt]: number of hydrogen bonds as a function of time.[BR]",
3114 "[TT]-ac[tt]: average over all autocorrelations of the existence",
3115 "functions (either 0 or 1) of all hydrogen bonds.[BR]",
3116 "[TT]-dist[tt]: distance distribution of all hydrogen bonds.[BR]",
3117 "[TT]-ang[tt]: angle distribution of all hydrogen bonds.[BR]",
3118 "[TT]-hx[tt]: the number of n-n+i hydrogen bonds as a function of time",
3119 "where n and n+i stand for residue numbers and i ranges from 0 to 6.",
3120 "This includes the n-n+3, n-n+4 and n-n+5 hydrogen bonds associated",
3121 "with helices in proteins.[BR]",
3122 "[TT]-hbn[tt]: all selected groups, donors, hydrogens and acceptors",
3123 "for selected groups, all hydrogen bonded atoms from all groups and",
3124 "all solvent atoms involved in insertion.[BR]",
3125 "[TT]-hbm[tt]: existence matrix for all hydrogen bonds over all",
3126 "frames, this also contains information on solvent insertion",
3127 "into hydrogen bonds. Ordering is identical to that in [TT]-hbn[tt]",
3129 "[TT]-dan[tt]: write out the number of donors and acceptors analyzed for",
3130 "each timeframe. This is especially usefull when using [TT]-shell[tt].[BR]",
3131 "[TT]-nhbdist[tt]: compute the number of HBonds per hydrogen in order to",
3132 "compare results to Raman Spectroscopy.",
3134 "Note: options [TT]-ac[tt], [TT]-life[tt], [TT]-hbn[tt] and [TT]-hbm[tt]",
3135 "require an amount of memory proportional to the total numbers of donors",
3136 "times the total number of acceptors in the selected group(s)."
3139 static real acut
=30, abin
=1, rcut
=0.35, r2cut
=0, rbin
=0.005, rshell
=-1;
3140 static real maxnhb
=0,fit_start
=1,temp
=298.15,smooth_tail_start
=-1, D
=-1;
3141 static bool bNitAcc
=TRUE
,bInsert
=FALSE
,bDA
=TRUE
,bMerge
=TRUE
;
3143 static int nThreads
= 0, nBalExp
=4;
3145 static bool bContact
=FALSE
, bBallistic
=FALSE
, bBallisticDt
=FALSE
, bGemFit
=FALSE
;
3146 static real logAfterTime
= 10, gemBallistic
= 0.2; /* ps */
3147 static char *NNtype
[] = {NULL
, "none", "binary", "oneOverR3", "dipole", NULL
};
3151 { "-ins", FALSE
, etBOOL
, {&bInsert
},
3152 "Analyze solvent insertion" },
3153 { "-a", FALSE
, etREAL
, {&acut
},
3154 "Cutoff angle (degrees, Acceptor - Donor - Hydrogen)" },
3155 { "-r", FALSE
, etREAL
, {&rcut
},
3156 "Cutoff radius (nm, X - Acceptor, see next option)" },
3157 { "-da", FALSE
, etBOOL
, {&bDA
},
3158 "Use distance Donor-Acceptor (if TRUE) or Hydrogen-Acceptor (FALSE)" },
3159 { "-r2", FALSE
, etREAL
, {&r2cut
},
3160 "Second cutoff radius. Mainly useful with -contact and -ac"},
3161 { "-abin", FALSE
, etREAL
, {&abin
},
3162 "Binwidth angle distribution (degrees)" },
3163 { "-rbin", FALSE
, etREAL
, {&rbin
},
3164 "Binwidth distance distribution (nm)" },
3165 { "-nitacc",FALSE
, etBOOL
, {&bNitAcc
},
3166 "Regard nitrogen atoms as acceptors" },
3167 { "-contact",FALSE
,etBOOL
, {&bContact
},
3168 "Do not look for hydrogen bonds, but merely for contacts within the cut-off distance" },
3169 { "-shell", FALSE
, etREAL
, {&rshell
},
3170 "when > 0, only calculate hydrogen bonds within # nm shell around "
3172 { "-fitstart", FALSE
, etREAL
, {&fit_start
},
3173 "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" },
3174 { "-temp", FALSE
, etREAL
, {&temp
},
3175 "Temperature (K) for computing the Gibbs energy corresponding to HB breaking and reforming" },
3176 { "-smooth",FALSE
, etREAL
, {&smooth_tail_start
},
3177 "If >= 0, the tail of the ACF will be smoothed by fitting it to an exponential function: y = A exp(-x/tau)" },
3178 { "-dump", FALSE
, etINT
, {&nDump
},
3179 "Dump the first N hydrogen bond ACFs in a single xvg file for debugging" },
3180 { "-max_hb",FALSE
, etREAL
, {&maxnhb
},
3181 "Theoretical maximum number of hydrogen bonds used for normalizing HB autocorrelation function. Can be useful in case the program estimates it wrongly" },
3182 { "-merge", FALSE
, etBOOL
, {&bMerge
},
3183 "H-bonds between the same donor and acceptor, but with different hydrogen are treated as a single H-bond. Mainly important for the ACF." },
3184 { "-geminate", FALSE
, etENUM
, {gemType
},
3185 "Use reversible geminate recombination for the kinetics/thermodynamics calclations. See Markovitch et al., J. Chem. Phys 129, 084505 (2008) for details."},
3186 { "-diff", FALSE
, etREAL
, {&D
},
3187 "Dffusion coefficient to use in the rev. gem. recomb. kinetic model. If non-positive, then it will be fitted to the ACF along with ka and kd."},
3189 { "-nthreads", FALSE
, etINT
, {&nThreads
},
3190 "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 processors (before OpenMP v.3 ) or environment variable OMP_THREAD_LIMIT (OpenMP v.3)"},
3192 { "-NN", FALSE
, etENUM
, {NNtype
},
3193 "HIDDENDo a full all vs all loop and estimsate the interaction energy instead of having a binary existence function for hydrogen bonds. NOT FULLY TESTED YET! DON'T USE IT!"},
3194 { "-gemfit", FALSE
, etBOOL
, {&bGemFit
},
3195 "With -gemainate != none: fit ka and kd to the ACF"},
3196 { "-gemlogstart", FALSE
, etREAL
, {&logAfterTime
},
3197 "HIDDENWith -gemfit: After this time (ps) the data points fitted to will be equidistant in log-time."},
3198 { "-ballistic", FALSE
, etBOOL
, {&bBallistic
},
3199 "Calculate and remove ultrafast \"ballistic\" component in the ACF."},
3200 { "-ballisticlen", FALSE
, etREAL
, {&gemBallistic
},
3201 "HIDDENFitting interval for the ultrafast \"ballistic\" component in ACF."},
3202 { "-nbalexp", FALSE
, etINT
, {&nBalExp
},
3203 "HIDDENNumber of exponentials to fit when removing the ballistic component."},
3204 { "-ballisticDt", FALSE
, etBOOL
, {&bBallisticDt
},
3205 "HIDDENIf TRUE, finding of the fastest ballistic component will be based on the time derivative at t=0, "
3206 "while if FALSE, it will be based on the exponent alone (like in Markovitch 2008)."}
3208 const char *bugs
[] = {
3209 "The option [TT]-sel[tt] that used to work on selected hbonds is out of order, and therefore not available for the time being."
3212 { efTRX
, "-f", NULL
, ffREAD
},
3213 { efTPX
, NULL
, NULL
, ffREAD
},
3214 { efNDX
, NULL
, NULL
, ffOPTRD
},
3215 /* { efNDX, "-sel", "select", ffOPTRD },*/
3216 { efXVG
, "-num", "hbnum", ffWRITE
},
3217 { efLOG
, "-g", "hbond", ffOPTWR
},
3218 { efXVG
, "-ac", "hbac", ffOPTWR
},
3219 { efXVG
, "-dist","hbdist", ffOPTWR
},
3220 { efXVG
, "-ang", "hbang", ffOPTWR
},
3221 { efXVG
, "-hx", "hbhelix",ffOPTWR
},
3222 { efNDX
, "-hbn", "hbond", ffOPTWR
},
3223 { efXPM
, "-hbm", "hbmap", ffOPTWR
},
3224 { efXVG
, "-don", "donor", ffOPTWR
},
3225 { efXVG
, "-dan", "danum", ffOPTWR
},
3226 { efXVG
, "-life","hblife", ffOPTWR
},
3227 { efXVG
, "-nhbdist", "nhbdist",ffOPTWR
}
3230 #define NFILE asize(fnm)
3232 char hbmap
[HB_NR
]={ ' ', 'o', '-', '*' };
3233 char *hbdesc
[HB_NR
]={ "None", "Present", "Inserted", "Present & Inserted" };
3234 t_rgb hbrgb
[HB_NR
]={ {1,1,1},{1,0,0}, {0,0,1}, {1,0,1} };
3236 int status
, trrStatus
=1;
3240 int npargs
,natoms
,nframes
=0,shatom
;
3246 real t
,ccut
,dist
,ang
;
3247 double max_nhb
,aver_nhb
,aver_dist
;
3248 int h
,i
,j
,k
,l
,start
,end
,id
,ja
,ogrp
,nsel
;
3250 int xj
,yj
,zj
,aj
,xjj
,yjj
,zjj
;
3251 int xk
,yk
,zk
,ak
,xkk
,ykk
,zkk
;
3252 bool bSelected
,bHBmap
,bStop
,bTwo
,was
,bBox
,bTric
;
3254 int grp
,nabin
,nrbin
,bin
,resdist
,ihb
;
3257 FILE *fp
,*fpins
=NULL
,*fpnhb
=NULL
;
3259 t_ncell
*icell
,*jcell
,*kcell
;
3261 unsigned char *datable
;
3266 int ii
, jj
, hh
, actual_nThreads
, threadNr
;
3267 bool bGem
, bNN
, bParallel
;
3268 t_gemParams
*params
;
3270 CopyRight(stdout
,argv
[0]);
3273 ppa
= add_acf_pargs(&npargs
,pa
);
3275 parse_common_args(&argc
,argv
,PCA_CAN_TIME
| PCA_BE_NICE
,NFILE
,fnm
,npargs
,
3276 ppa
,asize(desc
),desc
,asize(bugs
),bugs
,&oenv
);
3278 /* NN-loop? If so, what estimator to use ?*/
3280 while (NN
< NN_NR
&& strcasecmp(NNtype
[0], NNtype
[NN
])!=0)
3283 gmx_fatal(FARGS
, "Invalid NN-loop type.");
3286 for (i
=2; bNN
==FALSE
&& i
<NN_NR
; i
++)
3287 bNN
= bNN
|| NN
== i
;
3289 if (NN
> NN_NONE
&& bMerge
)
3292 /* geminate recombination? If so, which flavor? */
3294 while (gemmode
< gemNR
&& strcasecmp(gemType
[0], gemType
[gemmode
])!=0)
3296 if (gemmode
== gemNR
)
3297 gmx_fatal(FARGS
, "Invalid recombination type.");
3300 for (i
=2; bGem
==FALSE
&& i
<gemNR
; i
++)
3301 bGem
= bGem
|| gemmode
== i
;
3304 printf("Geminate recombination: %s\n" ,gemType
[gemmode
]);
3306 printf("Note that some aspects of reversible geminate recombination won't work without gsl.\n");
3309 if (gemmode
!= gemDD
) {
3310 printf("Turning off -contact option...\n");
3314 if (gemmode
== gemDD
) {
3315 printf("Turning on -contact option...\n");
3320 if (gemmode
== gemAA
) {
3321 printf("Turning off -merge option...\n");
3325 if (gemmode
!= gemAA
) {
3326 printf("Turning on -merge option...\n");
3331 printf("No geminate recombination.\n");
3334 bSelected
= opt2bSet("-sel",NFILE
,fnm
);
3335 ccut
= cos(acut
*DEG2RAD
);
3339 gmx_fatal(FARGS
,"Can not analyze selected contacts: turn off -sel");
3341 gmx_fatal(FARGS
,"Can not analyze inserted contacts: turn off -ins");
3343 gmx_fatal(FARGS
,"Can not analyze contact between H and A: turn off -noda");
3348 printf("NO GSL! Can't find and take away ballistic term in ACF without GSL\n.");
3351 /* Initiate main data structure! */
3352 bHBmap
= (opt2bSet("-ac",NFILE
,fnm
) ||
3353 opt2bSet("-life",NFILE
,fnm
) ||
3354 opt2bSet("-hbn",NFILE
,fnm
) ||
3355 opt2bSet("-hbm",NFILE
,fnm
) ||
3359 printf("Compiled with OpenMP (%i)\n", _OPENMP
);
3362 /* if (bContact && bGem) */
3363 /* gmx_fatal(FARGS, "Can't do reversible geminate recombination with -contact yet."); */
3365 if (opt2bSet("-nhbdist",NFILE
,fnm
)) {
3366 char *leg
[MAXHH
+1] = { "0 HBs", "1 HB", "2 HBs", "3 HBs", "Total" };
3367 fpnhb
= xvgropen(opt2fn("-nhbdist",NFILE
,fnm
),
3368 "Number of donor-H with N HBs","Time (ps)","N",oenv
);
3369 xvgr_legend(fpnhb
,asize(leg
),leg
,oenv
);
3372 hb
= mk_hbdata(bHBmap
,opt2bSet("-dan",NFILE
,fnm
),bMerge
|| bContact
, bGem
, gemmode
);
3375 read_tpx_top(ftp2fn(efTPX
,NFILE
,fnm
),&ir
,box
,&natoms
,NULL
,NULL
,NULL
,&top
);
3377 snew(grpnames
,grNR
);
3380 /* Make Donor-Acceptor table */
3381 snew(datable
, top
.atoms
.nr
);
3382 gen_datable(index
[0],isize
[0],datable
,top
.atoms
.nr
);
3385 /* analyze selected hydrogen bonds */
3386 printf("Select group with selected atoms:\n");
3387 get_index(&(top
.atoms
),opt2fn("-sel",NFILE
,fnm
),
3388 1,&nsel
,index
,grpnames
);
3390 gmx_fatal(FARGS
,"Number of atoms in group '%s' not a multiple of 3\n"
3391 "and therefore cannot contain triplets of "
3392 "Donor-Hydrogen-Acceptor",grpnames
[0]);
3395 for(i
=0; (i
<nsel
); i
+=3) {
3396 int dd
= index
[0][i
];
3397 /* int */ hh
= index
[0][i
+1];
3398 int aa
= index
[0][i
+2];
3399 add_dh (&hb
->d
,dd
,hh
,i
,datable
);
3400 add_acc(&hb
->a
,aa
,i
);
3401 /* Should this be here ? */
3402 snew(hb
->d
.dptr
,top
.atoms
.nr
);
3403 snew(hb
->a
.aptr
,top
.atoms
.nr
);
3404 add_hbond(hb
,dd
,aa
,hh
,gr0
,gr0
,0,FALSE
,bMerge
,0,bContact
,peri
);
3406 printf("Analyzing %d selected hydrogen bonds from '%s'\n",
3407 isize
[0],grpnames
[0]);
3410 /* analyze all hydrogen bonds: get group(s) */
3411 printf("Specify 2 groups to analyze:\n");
3412 get_index(&(top
.atoms
),ftp2fn_null(efNDX
,NFILE
,fnm
),
3413 2,isize
,index
,grpnames
);
3415 /* check if we have two identical or two non-overlapping groups */
3416 bTwo
= isize
[0] != isize
[1];
3417 for (i
=0; (i
<isize
[0]) && !bTwo
; i
++)
3418 bTwo
= index
[0][i
] != index
[1][i
];
3420 printf("Checking for overlap in atoms between %s and %s\n",
3421 grpnames
[0],grpnames
[1]);
3422 for (i
=0; i
<isize
[1];i
++)
3423 if (ISINGRP(datable
[index
[1][i
]]))
3424 gmx_fatal(FARGS
,"Partial overlap between groups '%s' and '%s'",
3425 grpnames
[0],grpnames
[1]);
3427 printf("Checking for overlap in atoms between %s and %s\n",
3428 grpnames[0],grpnames[1]);
3429 for (i=0; i<isize[0]; i++)
3430 for (j=0; j<isize[1]; j++)
3431 if (index[0][i] == index[1][j])
3432 gmx_fatal(FARGS,"Partial overlap between groups '%s' and '%s'",
3433 grpnames[0],grpnames[1]);
3437 printf("Calculating %s "
3438 "between %s (%d atoms) and %s (%d atoms)\n",
3439 bContact
? "contacts" : "hydrogen bonds",
3440 grpnames
[0],isize
[0],grpnames
[1],isize
[1]);
3442 fprintf(stderr
,"Calculating %s in %s (%d atoms)\n",
3443 bContact
?"contacts":"hydrogen bonds",grpnames
[0],isize
[0]);
3447 printf("Specify group for insertion analysis:\n");
3448 get_index(&(top
.atoms
),ftp2fn_null(efNDX
,NFILE
,fnm
),
3449 1,&(isize
[grI
]),&(index
[grI
]),&(grpnames
[grI
]));
3450 printf("Checking for overlap...\n");
3451 for (i
=0; i
<isize
[grI
]; i
++)
3452 for (grp
=0; grp
<(bTwo
?2:1); grp
++)
3453 for (j
=0; j
<isize
[grp
]; j
++)
3454 if (index
[grI
][i
] == index
[grp
][j
])
3455 gmx_fatal(FARGS
,"Partial overlap between groups '%s' and '%s'",
3456 grpnames
[grp
],grpnames
[grI
]);
3457 fpins
=ffopen("insert.dat","w");
3458 fprintf(fpins
,"%4s: %15s -> %15s (%7s) - %15s (%7s)\n",
3459 "time","insert","donor","distang","acceptor","distang");
3462 /* search donors and acceptors in groups */
3463 snew(datable
, top
.atoms
.nr
);
3464 for (i
=0; (i
<grNR
); i
++)
3465 if ( ((i
==gr0
) && !bSelected
) ||
3466 ((i
==gr1
) && bTwo
) ||
3467 ((i
==grI
) && bInsert
) ) {
3468 gen_datable(index
[i
],isize
[i
],datable
,top
.atoms
.nr
);
3470 search_acceptors(&top
,isize
[i
],index
[i
],&hb
->a
,i
,
3471 bNitAcc
,TRUE
,(bTwo
&& (i
==gr0
)) || !bTwo
, datable
);
3472 search_donors (&top
,isize
[i
],index
[i
],&hb
->d
,i
,
3473 TRUE
,(bTwo
&& (i
==gr1
)) || !bTwo
, datable
);
3476 search_acceptors(&top
,isize
[i
],index
[i
],&hb
->a
,i
,bNitAcc
,FALSE
,TRUE
, datable
);
3477 search_donors (&top
,isize
[i
],index
[i
],&hb
->d
,i
,FALSE
,TRUE
, datable
);
3480 clear_datable_grp(datable
,top
.atoms
.nr
);
3483 printf("Found %d donors and %d acceptors\n",hb
->d
.nrd
,hb
->a
.nra
);
3485 snew(donors[gr0D], dons[gr0D].nrd);*/
3488 printf("Making hbmap structure...");
3489 /* Generate hbond data structure */
3490 mk_hbmap(hb
,bTwo
,bInsert
);
3494 #ifdef HAVE_NN_LOOPS
3500 printf("Making per structure...");
3501 /* Generate hbond data structure */
3508 if (hb
->d
.nrd
+ hb
->a
.nra
== 0) {
3509 printf("No Donors or Acceptors found\n");
3513 if (hb
->d
.nrd
== 0) {
3514 printf("No Donors found\n");
3517 if (hb
->a
.nra
== 0) {
3518 printf("No Acceptors found\n");
3523 gmx_fatal(FARGS
,"Nothing to be done");
3530 /* get index group with atom for shell */
3532 printf("Select atom for shell (1 atom):\n");
3533 get_index(&(top
.atoms
),ftp2fn_null(efNDX
,NFILE
,fnm
),
3534 1,&shisz
,&shidx
,&shgrpnm
);
3536 printf("group contains %d atoms, should be 1 (one)\n",shisz
);
3537 } while(shisz
!= 1);
3539 printf("Will calculate hydrogen bonds within a shell "
3540 "of %g nm around atom %i\n",rshell
,shatom
+1);
3543 /* Analyze trajectory */
3544 natoms
=read_first_x(oenv
,&status
,ftp2fn(efTRX
,NFILE
,fnm
),&t
,&x
,box
);
3545 if ( natoms
> top
.atoms
.nr
)
3546 gmx_fatal(FARGS
,"Topology (%d atoms) does not match trajectory (%d atoms)",
3547 top
.atoms
.nr
,natoms
);
3549 bBox
= ir
.ePBC
!=epbcNONE
;
3550 grid
= init_grid(bBox
, box
, (rcut
>r2cut
)?rcut
:r2cut
, ngrid
);
3553 snew(adist
,nabin
+1);
3554 snew(rdist
,nrbin
+1);
3557 gmx_fatal(FARGS
, "Can't do geminate recombination without periodic box.");
3562 #define __ADIST adist
3563 #define __RDIST rdist
3565 #else /* HAVE_OPENMP ================================================== \
3566 * Set up the OpenMP stuff, |
3567 * like the number of threads and such |
3568 * Also start the parallel loop. |
3570 #define __ADIST p_adist[threadNr]
3571 #define __RDIST p_rdist[threadNr]
3572 #define __HBDATA p_hb[threadNr]
3574 bParallel
= !bSelected
&& !bInsert
;
3578 #if (_OPENMP > 200805)
3579 actual_nThreads
= min((nThreads
<= 0) ? INT_MAX
: nThreads
, omp_get_thread_limit());
3581 actual_nThreads
= min((nThreads
<= 0) ? INT_MAX
: nThreads
, omp_get_num_procs());
3583 omp_set_num_threads(actual_nThreads
);
3584 printf("Frame loop parallelized with OpenMP using %i threads.\n", actual_nThreads
);
3589 actual_nThreads
= 1;
3592 t_hbdata
**p_hb
; /* one per thread, then merge after the frame loop */
3593 int **p_adist
, **p_rdist
; /* a histogram for each thread. */
3594 snew(p_hb
, actual_nThreads
);
3595 snew(p_adist
, actual_nThreads
);
3596 snew(p_rdist
, actual_nThreads
);
3597 for (i
=0; i
<actual_nThreads
; i
++)
3600 snew(p_adist
[i
], nabin
+1);
3601 snew(p_rdist
[i
], nrbin
+1);
3603 p_hb
[i
]->max_frames
= 0;
3604 p_hb
[i
]->nhb
= NULL
;
3605 p_hb
[i
]->ndist
= NULL
;
3606 p_hb
[i
]->n_bound
= NULL
;
3607 p_hb
[i
]->time
= NULL
;
3608 p_hb
[i
]->nhx
= NULL
;
3610 p_hb
[i
]->bHBmap
= hb
->bHBmap
;
3611 p_hb
[i
]->bDAnr
= hb
->bDAnr
;
3612 p_hb
[i
]->bGem
= hb
->bGem
;
3613 p_hb
[i
]->wordlen
= hb
->wordlen
;
3614 p_hb
[i
]->nframes
= hb
->nframes
;
3615 p_hb
[i
]->maxhydro
= hb
->maxhydro
;
3616 p_hb
[i
]->danr
= hb
->danr
;
3619 p_hb
[i
]->hbmap
= hb
->hbmap
;
3620 p_hb
[i
]->time
= hb
->time
; /* This may need re-syncing at every frame. */
3621 p_hb
[i
]->per
= hb
->per
;
3623 #ifdef HAVE_NN_LOOPS
3624 p_hb
[i
]->hbE
= hb
->hbE
;
3628 p_hb
[i
]->nrdist
= 0;
3631 /* Make a thread pool here,
3632 * instead of forking anew at every frame. */
3634 #pragma omp parallel \
3635 private(i, j, h, ii, jj, hh, E, \
3636 xi, yi, zi, xj, yj, zj, threadNr, \
3637 dist, ang, peri, icell, jcell, \
3638 grp, ogrp, ai, aj, xjj, yjj, zjj, \
3639 xk, yk, zk, ihb, id, resdist, \
3640 xkk, ykk, zkk, kcell, ak, k, bTric) \
3642 shared(hb, p_hb, p_adist, p_rdist, actual_nThreads, \
3643 x, bBox, box, hbox, rcut, r2cut, rshell, \
3644 shatom, ngrid, grid, nframes, t, \
3645 bParallel, bNN, index, bMerge, bContact, \
3646 bTwo, bDA,ccut, abin, rbin, top, \
3647 bInsert, bSelected, bDebug, stderr, nsel, \
3648 bGem, oenv, fnm, fpnhb, trrStatus, natoms, \
3649 status, nabin, nrbin, adist, rdist, debug)
3650 { /* Start of parallel region */
3651 threadNr
= omp_get_thread_num();
3652 #endif /* HAVE_OPENMP ================================================= */
3655 bTric
= bBox
&& TRICLINIC(box
);
3658 sync_hbdata(hb
, p_hb
[threadNr
], nframes
, t
);
3662 build_grid(hb
,x
,x
[shatom
], bBox
,box
,hbox
, (rcut
>r2cut
)?rcut
:r2cut
,
3663 rshell
, ngrid
,grid
);
3664 reset_nhbonds(&(hb
->d
));
3666 if (debug
&& bDebug
)
3667 dump_grid(debug
, ngrid
, grid
);
3669 add_frames(hb
,nframes
);
3670 init_hbframe(hb
,nframes
,t
);
3673 count_da_grid(ngrid
, grid
, hb
->danr
[nframes
]);
3677 p_hb
[threadNr
]->time
= hb
->time
; /* This pointer may have changed. */
3681 #ifdef HAVE_NN_LOOPS /* Unlock this feature when testing */
3682 /* Loop over all atom pairs and estimate interaction energy */
3683 #ifdef HAVE_OPENMP /* ------- */
3685 #endif /* HAVE_OPENMP ------- */
3687 addFramesNN(hb
, nframes
);
3689 #ifdef HAVE_OPENMP /* ---------------- */
3691 #pragma omp for schedule(dynamic)
3692 #endif /* HAVE_OPENMP ---------------- */
3693 for (i
=0; i
<hb
->d
.nrd
; i
++)
3695 for(j
=0;j
<hb
->a
.nra
; j
++)
3698 h
< (bContact
? 1 : hb
->d
.nhydro
[i
]);
3701 if (i
==hb
->d
.nrd
|| j
==hb
->a
.nra
)
3702 gmx_fatal(FARGS
, "out of bounds");
3704 /* Get the real atom ids */
3707 hh
= hb
->d
.hydro
[i
][h
];
3709 /* Estimate the energy from the geometry */
3710 E
= calcHbEnergy(ii
, jj
, hh
, x
, NN
, box
, hbox
, &(hb
->d
));
3711 /* Store the energy */
3712 storeHbEnergy(hb
, i
, j
, h
, E
, nframes
);
3716 #endif /* HAVE_NN_LOOPS */
3726 /* Do not parallelize this just yet. */
3728 for(ii
=0; (ii
<nsel
); ii
++) {
3729 int dd
= index
[0][i
];
3730 /* int */ hh
= index
[0][i
+1];
3731 int aa
= index
[0][i
+2];
3732 ihb
= is_hbond(hb
,ii
,ii
,dd
,aa
,rcut
,r2cut
,ccut
,x
,bBox
,box
,
3733 hbox
,&dist
,&ang
,bDA
,&h
,bContact
,bMerge
,&peri
);
3736 /* add to index if not already there */
3738 add_hbond(hb
,dd
,aa
,hh
,ii
,ii
,nframes
,FALSE
,bMerge
,ihb
,bContact
,peri
);
3742 } /* if (bSelected) */
3750 calcBoxProjection(box
, hb
->per
->P
);
3752 /* loop over all gridcells (xi,yi,zi) */
3753 /* Removed confusing macro, DvdS 27/12/98 */
3756 /* The outer grid loop will have to do for now. */
3757 #pragma omp for schedule(dynamic)
3759 for(xi
=0; (xi
<ngrid
[XX
]); xi
++)
3760 for(yi
=0; (yi
<ngrid
[YY
]); yi
++)
3761 for(zi
=0; (zi
<ngrid
[ZZ
]); zi
++) {
3763 /* loop over donor groups gr0 (always) and gr1 (if necessary) */
3764 for (grp
=gr0
; (grp
<= (bTwo
?gr1
:gr0
)); grp
++) {
3765 icell
=&(grid
[zi
][yi
][xi
].d
[grp
]);
3772 /* loop over all hydrogen atoms from group (grp)
3773 * in this gridcell (icell)
3775 for (ai
=0; (ai
<icell
->nr
); ai
++) {
3776 i
= icell
->atoms
[ai
];
3778 /* loop over all adjacent gridcells (xj,yj,zj) */
3779 /* This is a macro!!! */
3780 LOOPGRIDINNER(xj
,yj
,zj
,xjj
,yjj
,zjj
,xi
,yi
,zi
,ngrid
,bTric
) {
3781 jcell
=&(grid
[zj
][yj
][xj
].a
[ogrp
]);
3782 /* loop over acceptor atoms from other group (ogrp)
3783 * in this adjacent gridcell (jcell)
3785 for (aj
=0; (aj
<jcell
->nr
); aj
++) {
3786 j
= jcell
->atoms
[aj
];
3788 /* check if this once was a h-bond */
3790 ihb
= is_hbond(__HBDATA
,grp
,ogrp
,i
,j
,rcut
,r2cut
,ccut
,x
,bBox
,box
,
3791 hbox
,&dist
,&ang
,bDA
,&h
,bContact
,bMerge
,&peri
);
3794 /* add to index if not already there */
3796 add_hbond(__HBDATA
,i
,j
,h
,grp
,ogrp
,nframes
,FALSE
,bMerge
,ihb
,bContact
,peri
);
3798 /* make angle and distance distributions */
3799 if (ihb
== hbHB
&& !bContact
) {
3801 gmx_fatal(FARGS
,"distance is higher than what is allowed for an hbond: %f",dist
);
3803 __ADIST
[(int)( ang
/abin
)]++;
3804 __RDIST
[(int)(dist
/rbin
)]++;
3807 if ((id
= donor_index(&hb
->d
,grp
,i
)) == NOTSET
)
3808 gmx_fatal(FARGS
,"Invalid donor %d",i
);
3809 if ((ia
= acceptor_index(&hb
->a
,ogrp
,j
)) == NOTSET
)
3810 gmx_fatal(FARGS
,"Invalid acceptor %d",j
);
3811 resdist
=abs(top
.atoms
.atom
[i
].resind
-
3812 top
.atoms
.atom
[j
].resind
);
3813 if (resdist
>= max_hx
)
3815 __HBDATA
->nhx
[nframes
][resdist
]++;
3819 if (bInsert
&& bSelected
&& MASTER_THREAD_ONLY(threadNr
)) {
3820 /* this has been a h-bond, or we are analyzing
3821 selected bonds: check for inserted */
3823 real ins_d_dist
, ins_d_ang
, ins_a_dist
, ins_a_ang
;
3824 int ins_d_k
=0,ins_a_k
=0;
3827 ins_d_dist
=ins_d_ang
=ins_a_dist
=ins_a_ang
=1e6
;
3829 /* loop over gridcells adjacent to i (xk,yk,zk) */
3830 LOOPGRIDINNER(xk
,yk
,zk
,xkk
,ykk
,zkk
,xi
,yi
,zi
,ngrid
,bTric
){
3831 kcell
=&(grid
[zk
][yk
][xk
].a
[grI
]);
3832 /* loop over acceptor atoms from ins group
3833 in this adjacent gridcell (kcell) */
3834 for (ak
=0; (ak
<kcell
->nr
); ak
++) {
3836 ihb
= is_hbond(hb
,grp
,grI
,i
,k
,rcut
,r2cut
,ccut
,x
,
3837 bBox
,box
,hbox
,&dist
,&ang
,bDA
,&h
,
3838 bContact
,bMerge
,&peri
);
3840 if (dist
< ins_d_dist
) {
3850 /* loop over gridcells adjacent to j (xk,yk,zk) */
3851 LOOPGRIDINNER(xk
,yk
,zk
,xkk
,ykk
,zkk
,xj
,yj
,zj
,ngrid
,bTric
){
3852 kcell
=&grid
[zk
][yk
][xk
].d
[grI
];
3853 /* loop over hydrogen atoms from ins group
3854 in this adjacent gridcell (kcell) */
3855 for (ak
=0; ak
<kcell
->nr
; ak
++) {
3856 k
= kcell
->atoms
[ak
];
3857 ihb
= is_hbond(hb
,grI
,ogrp
,k
,j
,rcut
,r2cut
,ccut
,x
,
3858 bBox
,box
,hbox
,&dist
,&ang
,bDA
,&h
,
3859 bContact
,bMerge
,&peri
);
3861 if (dist
<ins_a_dist
) {
3873 ihb
= is_hbond(hb
,grI
,grI
,ins_d_k
,ins_a_k
,rcut
,r2cut
,ccut
,x
,
3874 bBox
,box
,hbox
,&dist
,&ang
,bDA
,&h
,bContact
,bMerge
,&peri
);
3875 if (ins_d
&& ins_a
&& ihb
) {
3876 /* add to hbond index if not already there */
3877 add_hbond(hb
,ins_d_k
,ins_a_k
,h
,grI
,ogrp
,
3878 nframes
,TRUE
,bMerge
,ihb
,bContact
,peri
);
3880 /* print insertion info to file */
3882 "%4g: %4u:%3.3s%4d%3.3s -> "
3883 "%4u:%3.3s%4d%3.3s (%4.2f,%2.0f) - "
3884 "%4u:%3.3s%4d%3.3s (%4.2f,%2.0f)\n",t,
3886 *top.atoms.resname[top.atoms.atom[a[grIA][ins_d_k]].resnr],
3887 top.atoms.atom[a[grIA][ins_d_k]].resnr+1,
3888 *top.atoms.atomname[a[grIA][ins_d_k]],
3890 *top.atoms.resname[top.atoms.atom[a[grp+grD][i]].resnr],
3891 top.atoms.atom[a[grp+grD][i]].resnr+1,
3892 *top.atoms.atomname[a[grp+grD][i]],
3893 ins_d_dist,ins_d_ang*RAD2DEG,
3895 *top.atoms.resname[top.atoms.atom[a[ogrp+grA][j]].resnr],
3896 top.atoms.atom[a[ogrp+grA][j]].resnr+1,
3897 *top.atoms.atomname[a[ogrp+grA][j]],
3898 ins_a_dist,ins_a_ang*RAD2DEG);*/
3901 } /* if (bInsert && bSelected), omp single */
3908 } /* for xi,yi,zi */
3909 } /* if (bSelected) {...} else */
3911 #ifdef HAVE_OPENMP /* ---------------------------- */
3912 /* Better wait for all threads to finnish using x[] before updating it. */
3914 #pragma omp barrier /* */
3915 #pragma omp critical /* */
3917 /* Sum up histograms and counts from p_hb[] into hb */
3919 hb
->nhb
[k
] += p_hb
[threadNr
]->nhb
[k
];
3920 hb
->ndist
[k
] += p_hb
[threadNr
]->ndist
[k
];
3921 for (j
=0; j
<max_hx
; j
++) /**/
3922 hb
->nhx
[k
][j
] += p_hb
[threadNr
]->nhx
[k
][j
];
3926 /* Here are a handful of single constructs
3927 * to share the workload a bit. The most
3928 * important one is of course the last one,
3929 * where there's a potential bottleneck in form
3931 #pragma omp single /* ++++++++++++++++, */
3932 #endif /* HAVE_OPENMP ----------------+------------*/
3934 analyse_donor_props(opt2fn_null("-don",NFILE
,fnm
),hb
,k
,t
,oenv
);
3936 #ifdef HAVE_OPENMP /* + */
3937 #pragma omp single /* +++ +++ */
3941 do_nhb_dist(fpnhb
,hb
,t
);
3943 } /* if (bNN) {...} else + */
3944 #ifdef HAVE_OPENMP /* + */
3945 #pragma omp single /* +++ +++ */
3948 trrStatus
= (read_next_x(oenv
,status
,&t
,natoms
,x
,box
));
3951 #ifdef HAVE_OPENMP /* ++++++++++++++++´ */
3954 } while (trrStatus
);
3957 #pragma omp critical
3959 hb
->nrhb
+= p_hb
[threadNr
]->nrhb
;
3960 hb
->nrdist
+= p_hb
[threadNr
]->nrdist
;
3962 /* Free parallel datastructures */
3963 sfree(p_hb
[threadNr
]->nhb
);
3964 sfree(p_hb
[threadNr
]->ndist
);
3965 sfree(p_hb
[threadNr
]->nhx
);
3968 for (i
=0; i
<nabin
; i
++)
3969 for (j
=0; j
<actual_nThreads
; j
++)
3971 adist
[i
] += p_adist
[j
][i
];
3973 for (i
=0; i
<=nrbin
; i
++)
3974 for (j
=0; j
<actual_nThreads
; j
++)
3975 rdist
[i
] += p_rdist
[j
][i
];
3977 sfree(p_adist
[threadNr
]);
3978 sfree(p_rdist
[threadNr
]);
3979 } /* End of parallel region */
3985 free_grid(ngrid
,&grid
);
3993 /* Compute maximum possible number of different hbonds */
3997 max_nhb
= 0.5*(hb
->d
.nrd
*hb
->a
.nra
);
3999 /* Added support for -contact below.
4000 * - Erik Marklund, May 29-31, 2006 */
4001 /* Changed contact code.
4002 * - Erik Marklund, June 29, 2006 */
4003 if (bHBmap
&& !bNN
) {
4005 printf("No %s found!!\n", bContact
? "contacts" : "hydrogen bonds");
4007 printf("Found %d different %s in trajectory\n"
4008 "Found %d different atom-pairs within %s distance\n",
4009 hb
->nrhb
, bContact
?"contacts":"hydrogen bonds",
4010 hb
->nrdist
,(r2cut
>0)?"second cut-off":"hydrogen bonding");
4012 /*Control the pHist.*/
4015 merge_hb(hb
,bTwo
,bContact
);
4017 if (opt2bSet("-hbn",NFILE
,fnm
))
4018 dump_hbmap(hb
,NFILE
,fnm
,bTwo
,bInsert
,bContact
,isize
,index
,grpnames
,&top
.atoms
);
4020 /* Moved the call to merge_hb() to a line BEFORE dump_hbmap
4021 * to make the -hbn and -hmb output match eachother.
4022 * - Erik Marklund, May 30, 2006 */
4025 /* Print out number of hbonds and distances */
4028 fp
= xvgropen(opt2fn("-num",NFILE
,fnm
),bContact
? "Contacts" :
4029 "Hydrogen Bonds","Time","Number",oenv
);
4031 snew(leg
[0],STRLEN
);
4032 snew(leg
[1],STRLEN
);
4033 sprintf(leg
[0],"%s",bContact
?"Contacts":"Hydrogen bonds");
4034 sprintf(leg
[1],"Pairs within %g nm",(r2cut
>0)?r2cut
:rcut
);
4035 xvgr_legend(fp
,2,leg
,oenv
);
4039 for(i
=0; (i
<nframes
); i
++) {
4040 fprintf(fp
,"%10g %10d %10d\n",hb
->time
[i
],hb
->nhb
[i
],hb
->ndist
[i
]);
4041 aver_nhb
+= hb
->nhb
[i
];
4042 aver_dist
+= hb
->ndist
[i
];
4045 aver_nhb
/= nframes
;
4046 aver_dist
/= nframes
;
4047 /* Print HB distance distribution */
4048 if (opt2bSet("-dist",NFILE
,fnm
)) {
4052 for(i
=0; i
<nrbin
; i
++)
4055 fp
= xvgropen(opt2fn("-dist",NFILE
,fnm
),
4056 "Hydrogen Bond Distribution",
4057 "Hydrogen - Acceptor Distance (nm)","",oenv
);
4058 for(i
=0; i
<nrbin
; i
++)
4059 fprintf(fp
,"%10g %10g\n",(i
+0.5)*rbin
,rdist
[i
]/(rbin
*(real
)sum
));
4063 /* Print HB angle distribution */
4064 if (opt2bSet("-ang",NFILE
,fnm
)) {
4068 for(i
=0; i
<nabin
; i
++)
4071 fp
= xvgropen(opt2fn("-ang",NFILE
,fnm
),
4072 "Hydrogen Bond Distribution",
4073 "Donor - Hydrogen - Acceptor Angle (\\SO\\N)","",oenv
);
4074 for(i
=0; i
<nabin
; i
++)
4075 fprintf(fp
,"%10g %10g\n",(i
+0.5)*abin
,adist
[i
]/(abin
*(real
)sum
));
4079 /* Print HB in alpha-helix */
4080 if (opt2bSet("-hx",NFILE
,fnm
)) {
4081 fp
= xvgropen(opt2fn("-hx",NFILE
,fnm
),
4082 "Hydrogen Bonds","Time(ps)","Count",oenv
);
4083 xvgr_legend(fp
,NRHXTYPES
,hxtypenames
,oenv
);
4084 for(i
=0; i
<nframes
; i
++) {
4085 fprintf(fp
,"%10g",hb
->time
[i
]);
4086 for (j
=0; j
<max_hx
; j
++)
4087 fprintf(fp
," %6d",hb
->nhx
[i
][j
]);
4093 printf("Average number of %s per timeframe %.3f out of %g possible\n",
4094 bContact
? "contacts" : "hbonds",
4095 bContact
? aver_dist
: aver_nhb
, max_nhb
);
4097 /* Do Autocorrelation etc. */
4100 Added support for -contact in ac and hbm calculations below.
4101 - Erik Marklund, May 29, 2006
4105 if (opt2bSet("-ac",NFILE
,fnm
) || opt2bSet("-life",NFILE
,fnm
))
4106 please_cite(stdout
,"Spoel2006b");
4107 if (opt2bSet("-ac",NFILE
,fnm
)) {
4109 params
= init_gemParams(rcut
, D
, hb
->time
, logAfterTime
, hb
->nframes
/2, gemBallistic
, nBalExp
, bBallisticDt
);
4111 gmx_fatal(FARGS
, "Could not initiate t_gemParams params.");
4113 char *gemstring
=NULL
;
4114 gemstring
= strdup(gemType
[hb
->per
->gemtype
]);
4115 do_hbac(opt2fn("-ac",NFILE
,fnm
),hb
,aver_nhb
/max_nhb
,aver_dist
,nDump
,
4116 bMerge
,bContact
,fit_start
,temp
,r2cut
>0,smooth_tail_start
,oenv
,
4117 params
, gemstring
, nThreads
, NN
, bBallistic
, bGemFit
);
4119 if (opt2bSet("-life",NFILE
,fnm
))
4120 do_hblife(opt2fn("-life",NFILE
,fnm
),hb
,bMerge
,bContact
,oenv
);
4121 if (opt2bSet("-hbm",NFILE
,fnm
)) {
4126 mat
.ny
=(bContact
? hb
->nrdist
: hb
->nrhb
);
4128 snew(mat
.matrix
,mat
.nx
);
4129 for(x
=0; (x
<mat
.nx
); x
++)
4130 snew(mat
.matrix
[x
],mat
.ny
);
4132 for(id
=0; (id
<hb
->d
.nrd
); id
++)
4133 for(ia
=0; (ia
<hb
->a
.nra
); ia
++) {
4134 for(hh
=0; (hh
<hb
->maxhydro
); hh
++) {
4135 if (hb
->hbmap
[id
][ia
]) {
4136 if (ISHB(hb
->hbmap
[id
][ia
]->history
[hh
])) {
4137 /* Changed '<' into '<=' in the for-statement below.
4138 * It fixed the previously undiscovered bug that caused
4139 * the last occurance of an hbond/contact to not be
4140 * set in mat.matrix. Have a look at any old -hbm-output
4141 * and you will notice that the last column is allways empty.
4142 * - Erik Marklund May 30, 2006
4144 for(x
=0; (x
<=hb
->hbmap
[id
][ia
]->nframes
); x
++) {
4145 int nn0
= hb
->hbmap
[id
][ia
]->n0
;
4146 range_check(y
,0,mat
.ny
);
4147 mat
.matrix
[x
+nn0
][y
] = is_hb(hb
->hbmap
[id
][ia
]->h
[hh
],x
);
4154 mat
.axis_x
=hb
->time
;
4155 snew(mat
.axis_y
,mat
.ny
);
4156 for(j
=0; j
<mat
.ny
; j
++)
4158 sprintf(mat
.title
,bContact
? "Contact Existence Map":
4159 "Hydrogen Bond Existence Map");
4160 sprintf(mat
.legend
,bContact
? "Contacts" : "Hydrogen Bonds");
4161 sprintf(mat
.label_x
,"Time (ps)");
4162 sprintf(mat
.label_y
, bContact
? "Contact Index" : "Hydrogen Bond Index");
4168 snew(mat
.map
,mat
.nmap
);
4169 for(i
=0; i
<mat
.nmap
; i
++) {
4170 mat
.map
[i
].code
.c1
=hbmap
[i
];
4171 mat
.map
[i
].desc
=hbdesc
[i
];
4172 mat
.map
[i
].rgb
=hbrgb
[i
];
4174 fp
= opt2FILE("-hbm",NFILE
,fnm
,"w");
4175 write_xpm_m(fp
, mat
);
4177 for(x
=0; x
<mat
.nx
; x
++)
4178 sfree(mat
.matrix
[x
]);
4186 fprintf(stderr
, "There were %i periodic shifts\n", hb
->per
->nper
);
4187 fprintf(stderr
, "Freeing pHist for all donors...\n");
4188 for (i
=0; i
<hb
->d
.nrd
; i
++) {
4189 fprintf(stderr
, "\r%i",i
);
4190 if (hb
->per
->pHist
[i
] != NULL
) {
4191 for (j
=0; j
<hb
->a
.nra
; j
++)
4192 clearPshift(&(hb
->per
->pHist
[i
][j
]));
4193 sfree(hb
->per
->pHist
[i
]);
4196 sfree(hb
->per
->pHist
);
4197 sfree(hb
->per
->p2i
);
4199 fprintf(stderr
, "...done.\n");
4202 #ifdef HAVE_NN_LOOPS
4212 #define USE_THIS_GROUP(j) ( (j == gr0) || (bTwo && (j == gr1)) || (bInsert && (j == grI)) )
4214 fp
= xvgropen(opt2fn("-dan",NFILE
,fnm
),
4215 "Donors and Acceptors","Time(ps)","Count",oenv
);
4216 nleg
= (bTwo
?2:1)*2 + (bInsert
?2:0);
4217 snew(legnames
,nleg
);
4219 for(j
=0; j
<grNR
; j
++)
4220 if ( USE_THIS_GROUP(j
) ) {
4221 sprintf(buf
,"Donors %s",grpnames
[j
]);
4222 legnames
[i
++] = strdup(buf
);
4223 sprintf(buf
,"Acceptors %s",grpnames
[j
]);
4224 legnames
[i
++] = strdup(buf
);
4227 gmx_incons("number of legend entries");
4228 xvgr_legend(fp
,nleg
,legnames
,oenv
);
4229 for(i
=0; i
<nframes
; i
++) {
4230 fprintf(fp
,"%10g",hb
->time
[i
]);
4231 for (j
=0; (j
<grNR
); j
++)
4232 if ( USE_THIS_GROUP(j
) )
4233 fprintf(fp
," %6d",hb
->danr
[i
][j
]);