added Verlet scheme and NxN non-bonded functionality
[gromacs.git] / src / tools / gmx_sham.c
blob6b8479cf53f6cb0b4800466a2143c6d19849c552
1 /*
2 *
3 * This source code is part of
4 *
5 * G R O M A C S
6 *
7 * GROningen MAchine for Chemical Simulations
8 *
9 * VERSION 3.2.0
10 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12 * Copyright (c) 2001-2004, The GROMACS development team,
13 * check out http://www.gromacs.org for more information.
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * If you want to redistribute modifications, please consider that
21 * scientific software is very special. Version control is crucial -
22 * bugs must be traceable. We will be happy to consider code for
23 * inclusion in the official distribution, but derived work must not
24 * be called official GROMACS. Details are found in the README & COPYING
25 * files - if they are missing, get the official version at www.gromacs.org.
27 * To help us fund GROMACS development, we humbly ask that you cite
28 * the papers on the package - you can find them in the top README file.
30 * For more info, check our website at http://www.gromacs.org
32 * And Hey:
33 * Green Red Orange Magenta Azure Cyan Skyblue
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38 #include <math.h>
39 #include <string.h>
40 #include "statutil.h"
41 #include "sysstuff.h"
42 #include "typedefs.h"
43 #include "smalloc.h"
44 #include "macros.h"
45 #include "gmx_fatal.h"
46 #include "vec.h"
47 #include "copyrite.h"
48 #include "futil.h"
49 #include "readinp.h"
50 #include "statutil.h"
51 #include "txtdump.h"
52 #include "gstat.h"
53 #include "xvgr.h"
54 #include "physics.h"
55 #include "pdbio.h"
56 #include "matio.h"
57 #include "gmx_ana.h"
60 static int index2(int *ibox,int x,int y)
62 return (ibox[1]*x+y);
65 static int index3(int *ibox,int x,int y,int z)
67 return (ibox[2]*(ibox[1]*x+y)+z);
70 static gmx_large_int_t indexn(int ndim, const int *ibox, const int *nxyz)
72 gmx_large_int_t d, dd;
73 int k, kk;
75 /* Compute index in 1-D array */
76 d = 0;
77 for(k=0; (k<ndim); k++) {
78 dd = nxyz[k];
79 for(kk=k+1; (kk<ndim); kk++)
80 dd = dd*ibox[kk];
81 d += dd;
83 return d;
86 typedef struct{
87 int Nx; /* x grid points in unit cell */
88 int Ny; /* y grid points in unit cell */
89 int Nz; /* z grid points in unit cell */
90 int dmin[3]; /* starting point x,y,z*/
91 int dmax[3]; /* ending point x,y,z */
92 real cell[6]; /* usual cell parameters */
93 real * ed; /* data */
94 } XplorMap;
96 static void lo_write_xplor(XplorMap * map,const char * file)
98 FILE * fp;
99 int z,i,j,n;
101 fp = ffopen(file,"w");
102 /* The REMARKS part is the worst part of the XPLOR format
103 * and may cause problems with some programs
105 fprintf(fp,"\n 2 !NTITLE\n") ;
106 fprintf(fp," REMARKS Energy Landscape from GROMACS\n") ;
107 fprintf(fp," REMARKS DATE: 2004-12-21 \n") ;
108 fprintf(fp," %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
109 map->Nx, map->dmin[0], map->dmax[0],
110 map->Ny, map->dmin[1], map->dmax[1],
111 map->Nz, map->dmin[2], map->dmax[2]);
112 fprintf(fp,"%12.5E%12.5E%12.5E%12.5E%12.5E%12.5E\n",
113 map->cell[0],map->cell[1],map->cell[2],
114 map->cell[3],map->cell[4],map->cell[5]);
115 fprintf(fp, "ZYX\n") ;
117 z = map->dmin[2];
118 for (n = 0; n < map->Nz; n++, z++) {
119 fprintf(fp, "%8d\n", z) ;
120 for (i = 0; i < map->Nx*map->Ny; i += 6) {
121 for (j = 0; j < 6; j++)
122 if (i+j < map->Nx*map->Ny)
123 fprintf(fp, "%12.5E", map->ed[n*map->Nx*map->Ny+i+j]);
124 fprintf(fp, "\n") ;
127 fprintf(fp, " -9999\n") ;
128 ffclose(fp) ;
131 static void write_xplor(const char *file,real *data,int *ibox,real dmin[],real dmax[])
133 XplorMap *xm;
134 int i,j,k,n;
136 snew(xm,1);
137 xm->Nx = ibox[XX];
138 xm->Ny = ibox[YY];
139 xm->Nz = ibox[ZZ];
140 snew(xm->ed,xm->Nx*xm->Ny*xm->Nz);
141 n=0;
142 for(k=0; (k<xm->Nz); k++)
143 for(j=0; (j<xm->Ny); j++)
144 for(i=0; (i<xm->Nx); i++)
145 xm->ed[n++] = data[index3(ibox,i,j,k)];
146 xm->cell[0] = dmax[XX]-dmin[XX];
147 xm->cell[1] = dmax[YY]-dmin[YY];
148 xm->cell[2] = dmax[ZZ]-dmin[ZZ];
149 xm->cell[3] = xm->cell[4] = xm->cell[5] = 90;
151 clear_ivec(xm->dmin);
152 xm->dmax[XX] = ibox[XX]-1;
153 xm->dmax[YY] = ibox[YY]-1;
154 xm->dmax[ZZ] = ibox[ZZ]-1;
156 lo_write_xplor(xm,file);
158 sfree(xm->ed);
159 sfree(xm);
162 static void normalize_p_e(int len,double *P,int *nbin,real *E,real pmin)
164 int i;
165 double Ptot=0;
167 for(i=0; (i<len); i++) {
168 Ptot += P[i];
169 if (nbin[i] > 0)
170 E[i] = E[i]/nbin[i];
172 printf("Ptot = %g\n",Ptot);
173 for(i=0; (i<len); i++) {
174 P[i] = P[i]/Ptot;
175 /* Have to check for pmin after normalizing to prevent "stretching"
176 * the energies.
178 if (P[i] < pmin)
179 P[i] = 0;
183 typedef struct {
184 gmx_large_int_t index;
185 real ener;
186 } t_minimum;
188 static int comp_minima(const void *a,const void *b)
190 t_minimum *ma = (t_minimum *) a;
191 t_minimum *mb = (t_minimum *) b;
193 if (ma->ener < mb->ener)
194 return -1;
195 else if (ma->ener > mb->ener)
196 return 1;
197 else
198 return 0;
201 static inline
202 void print_minimum(FILE *fp, int num, const t_minimum *min)
204 fprintf(fp,
205 "Minimum %d at index " gmx_large_int_pfmt " energy %10.3f\n",
206 num, min->index, min->ener);
209 static inline
210 void add_minimum(FILE *fp, int num, const t_minimum *min, t_minimum *mm)
212 print_minimum(fp, num, min);
213 mm[num].index = min->index;
214 mm[num].ener = min->ener;
217 static inline
218 gmx_bool is_local_minimum_from_below(const t_minimum *this_min,
219 int dimension_index,
220 int dimension_min,
221 int neighbour_index,
222 real *W)
224 return ((dimension_index == dimension_min) ||
225 ((dimension_index > dimension_min) &&
226 (this_min->ener < W[neighbour_index])));
227 /* Note over/underflow within W cannot occur. */
230 static inline
231 gmx_bool is_local_minimum_from_above(const t_minimum *this_min,
232 int dimension_index,
233 int dimension_max,
234 int neighbour_index,
235 real *W)
237 return ((dimension_index == dimension_max) ||
238 ((dimension_index < dimension_max) &&
239 (this_min->ener < W[neighbour_index])));
240 /* Note over/underflow within W cannot occur. */
243 static void pick_minima(const char *logfile,int *ibox,int ndim,int len,real W[])
245 FILE *fp;
246 int i,j,k,nmin;
247 t_minimum *mm, this_min;
248 int *this_point;
249 int loopmax, loopcounter;
251 snew(mm,len);
252 nmin = 0;
253 fp = ffopen(logfile,"w");
254 /* Loop over each element in the array of dimenion ndim seeking
255 * minima with respect to every dimension. Specialized loops for
256 * speed with ndim == 2 and ndim == 3. */
257 switch(ndim)
259 case 0:
260 /* This is probably impossible to reach anyway. */
261 break;
262 case 2:
263 for(i=0; (i<ibox[0]); i++) {
264 for(j=0; (j<ibox[1]); j++) {
265 /* Get the index of this point in the flat array */
266 this_min.index = index2(ibox,i,j);
267 this_min.ener = W[this_min.index];
268 if (is_local_minimum_from_below(&this_min, i, 0, index2(ibox,i-1,j ), W) &&
269 is_local_minimum_from_above(&this_min, i, ibox[0]-1, index2(ibox,i+1,j ), W) &&
270 is_local_minimum_from_below(&this_min, j, 0, index2(ibox,i ,j-1), W) &&
271 is_local_minimum_from_above(&this_min, j, ibox[1]-1, index2(ibox,i ,j+1), W))
273 add_minimum(fp, nmin, &this_min, mm);
274 nmin++;
278 break;
279 case 3:
280 for(i=0; (i<ibox[0]); i++) {
281 for(j=0; (j<ibox[1]); j++) {
282 for(k=0; (k<ibox[2]); k++) {
283 /* Get the index of this point in the flat array */
284 this_min.index = index3(ibox,i,j,k);
285 this_min.ener = W[this_min.index];
286 if (is_local_minimum_from_below(&this_min, i, 0, index3(ibox,i-1,j ,k ), W) &&
287 is_local_minimum_from_above(&this_min, i, ibox[0]-1, index3(ibox,i+1,j ,k ), W) &&
288 is_local_minimum_from_below(&this_min, j, 0, index3(ibox,i ,j-1,k ), W) &&
289 is_local_minimum_from_above(&this_min, j, ibox[1]-1, index3(ibox,i ,j+1,k ), W) &&
290 is_local_minimum_from_below(&this_min, k, 0, index3(ibox,i ,j ,k-1), W) &&
291 is_local_minimum_from_above(&this_min, k, ibox[2]-1, index3(ibox,i ,j ,k+1), W))
293 add_minimum(fp, nmin, &this_min, mm);
294 nmin++;
299 break;
300 default:
301 /* Note this treats ndim == 1 and ndim > 3 */
303 /* Set up an ndim-dimensional vector to loop over the points
304 * on the grid. (0,0,0, ... 0) is an acceptable place to
305 * start. */
306 snew(this_point, ndim);
308 /* Determine the number of points of the ndim-dimensional
309 * grid. */
310 loopmax = ibox[0];
311 for (i = 1; i < ndim; i++)
313 loopmax *= ibox[i];
316 loopcounter = 0;
317 while (loopmax > loopcounter)
319 gmx_bool bMin = TRUE;
321 /* Get the index of this_point in the flat array */
322 this_min.index = indexn(ndim, ibox, this_point);
323 this_min.ener = W[this_min.index];
325 /* Is this_point a minimum from above and below in each
326 * dimension? */
327 for (i = 0; bMin && (i < ndim); i++)
329 /* Save the index of this_point within the curent
330 * dimension so we can change that index in the
331 * this_point array for use with indexn(). */
332 int index = this_point[i];
333 this_point[i]--;
334 bMin = bMin &&
335 is_local_minimum_from_below(&this_min, index, 0, indexn(ndim, ibox, this_point), W);
336 this_point[i] += 2;
337 bMin = bMin &&
338 is_local_minimum_from_above(&this_min, index, ibox[i]-1, indexn(ndim, ibox, this_point), W);
339 this_point[i]--;
341 if (bMin)
343 add_minimum(fp, nmin, &this_min, mm);
344 nmin++;
347 /* update global loop counter */
348 loopcounter++;
350 /* Avoid underflow of this_point[i] */
351 if (loopmax > loopcounter)
353 /* update this_point non-recursively */
354 i = ndim-1;
355 this_point[i]++;
356 while (ibox[i] == this_point[i])
358 this_point[i] = 0;
359 i--;
360 /* this_point[i] cannot underflow because
361 * loopmax > loopcounter. */
362 this_point[i]++;
367 sfree(this_point);
368 break;
370 qsort(mm,nmin,sizeof(mm[0]),comp_minima);
371 fprintf(fp,"Minima sorted after energy\n");
372 for(i=0; (i<nmin); i++)
374 print_minimum(fp, i, &mm[i]);
376 ffclose(fp);
377 sfree(mm);
380 static void do_sham(const char *fn,const char *ndx,
381 const char *xpmP,const char *xpm,const char *xpm2,
382 const char *xpm3,const char *xpm4,const char *pdb,
383 const char *logf,
384 int n,int neig,real **eig,
385 gmx_bool bGE,int nenerT,real **enerT,
386 int nmap,real *mapindex,real **map,
387 real Tref,
388 real pmax,real gmax,
389 real *emin,real *emax,int nlevels,real pmin,
390 const char *mname,gmx_bool bSham,int *idim,int *ibox,
391 gmx_bool bXmin,real *xmin,gmx_bool bXmax,real *xmax)
393 FILE *fp;
394 real *min_eig,*max_eig;
395 real *axis_x,*axis_y,*axis_z,*axis=NULL;
396 double *P;
397 real **PP,*W,*E,**WW,**EE,*S,**SS,*M,**MM,*bE;
398 rvec xxx;
399 char *buf;
400 double *bfac,efac,bref,Pmax,Wmin,Wmax,Winf,Emin,Emax,Einf,Smin,Smax,Sinf,Mmin,Mmax,Minf;
401 real *delta;
402 int i,j,k,imin,len,index,d,*nbin,*bindex,bi;
403 int *nxyz,maxbox;
404 t_blocka *b;
405 gmx_bool bOutside;
406 unsigned int flags;
407 t_rgb rlo = { 0, 0, 0 };
408 t_rgb rhi = { 1, 1, 1 };
410 /* Determine extremes for the eigenvectors */
411 snew(min_eig,neig);
412 snew(max_eig,neig);
413 snew(nxyz,neig);
414 snew(bfac,neig);
415 snew(delta,neig);
417 for(i=0; (i<neig); i++) {
418 /* Check for input constraints */
419 min_eig[i] = max_eig[i] = eig[i][0];
420 for(j=0; (j<n); j++) {
421 min_eig[i] = min(min_eig[i],eig[i][j]);
422 max_eig[i] = max(max_eig[i],eig[i][j]);
423 delta[i] = (max_eig[i]-min_eig[i])/(2.0*ibox[i]);
425 /* Add some extra space, half a bin on each side, unless the
426 * user has set the limits.
428 if (bXmax) {
429 if (max_eig[i] > xmax[i]) {
430 gmx_warning("Your xmax[%d] value %f is smaller than the largest data point %f",i,xmax[i],max_eig[i]);
432 max_eig[i] = xmax[i];
434 else
435 max_eig[i] += delta[i];
437 if (bXmin) {
438 if (min_eig[i] < xmin[i]) {
439 gmx_warning("Your xmin[%d] value %f is larger than the smallest data point %f",i,xmin[i],min_eig[i]);
441 min_eig[i] = xmin[i];
443 else
444 min_eig[i] -= delta[i];
445 bfac[i] = ibox[i]/(max_eig[i]-min_eig[i]);
447 /* Do the binning */
448 bref = 1/(BOLTZ*Tref);
449 snew(bE,n);
450 if (bGE || nenerT==2) {
451 Emin = 1e8;
452 for(j=0; (j<n); j++) {
453 if (bGE)
454 bE[j] = bref*enerT[0][j];
455 else
456 bE[j] = (bref - 1/(BOLTZ*enerT[1][j]))*enerT[0][j];
457 Emin = min(Emin,bE[j]);
460 else
461 Emin = 0;
462 len=1;
463 for(i=0; (i<neig); i++)
464 len=len*ibox[i];
465 printf("There are %d bins in the %d-dimensional histogram. Beta-Emin = %g\n",
466 len,neig,Emin);
467 snew(P,len);
468 snew(W,len);
469 snew(E,len);
470 snew(S,len);
471 snew(M,len);
472 snew(nbin,len);
473 snew(bindex,n);
476 /* Loop over projections */
477 for(j=0; (j<n); j++) {
478 /* Loop over dimensions */
479 bOutside = FALSE;
480 for(i=0; (i<neig); i++) {
481 nxyz[i] = bfac[i]*(eig[i][j]-min_eig[i]);
482 if (nxyz[i] < 0 || nxyz[i] >= ibox[i])
483 bOutside = TRUE;
485 if (!bOutside) {
486 index = indexn(neig,ibox,nxyz);
487 range_check(index,0,len);
488 /* Compute the exponential factor */
489 if (enerT)
490 efac = exp(-bE[j]+Emin);
491 else
492 efac = 1;
493 /* Apply the bin volume correction for a multi-dimensional distance */
494 for(i=0; i<neig; i++) {
495 if (idim[i] == 2)
496 efac /= eig[i][j];
497 else if (idim[i] == 3)
498 efac /= sqr(eig[i][j]);
499 else if (idim[i] == -1)
500 efac /= sin(DEG2RAD*eig[i][j]);
502 /* Update the probability */
503 P[index] += efac;
504 /* Update the energy */
505 if (enerT)
506 E[index] += enerT[0][j];
507 /* Statistics: which "structure" in which bin */
508 nbin[index]++;
509 bindex[j]=index;
512 /* Normalize probability */
513 normalize_p_e(len,P,nbin,E,pmin);
514 Pmax = 0;
515 /* Compute boundaries for the Free energy */
516 Wmin = 1e8;
517 imin = -1;
518 Wmax = -1e8;
519 /* Recompute Emin: it may have changed due to averaging */
520 Emin = 1e8;
521 Emax = -1e8;
522 for(i=0; (i<len); i++) {
523 if (P[i] != 0) {
524 Pmax = max(P[i],Pmax);
525 W[i] = -BOLTZ*Tref*log(P[i]);
526 if (W[i] < Wmin) {
527 Wmin = W[i];
528 imin = i;
530 Emin = min(E[i],Emin);
531 Emax = max(E[i],Emax);
532 Wmax = max(W[i],Wmax);
535 if (pmax > 0) {
536 Pmax = pmax;
538 if (gmax > 0) {
539 Wmax = gmax;
540 } else {
541 Wmax -= Wmin;
543 Winf = Wmax+1;
544 Einf = Emax+1;
545 Smin = Emin-Wmax;
546 Smax = Emax-Smin;
547 Sinf = Smax+1;
548 /* Write out the free energy as a function of bin index */
549 fp = ffopen(fn,"w");
550 for(i=0; (i<len); i++)
551 if (P[i] != 0) {
552 W[i] -= Wmin;
553 S[i] = E[i]-W[i]-Smin;
554 fprintf(fp,"%5d %10.5e %10.5e %10.5e\n",i,W[i],E[i],S[i]);
556 else {
557 W[i] = Winf;
558 E[i] = Einf;
559 S[i] = Sinf;
561 ffclose(fp);
562 /* Organize the structures in the bins */
563 snew(b,1);
564 snew(b->index,len+1);
565 snew(b->a,n);
566 b->index[0] = 0;
567 for(i=0; (i<len); i++) {
568 b->index[i+1] = b->index[i]+nbin[i];
569 nbin[i] = 0;
571 for(i=0; (i<n); i++) {
572 bi = bindex[i];
573 b->a[b->index[bi]+nbin[bi]] = i;
574 nbin[bi]++;
576 /* Consistency check */
577 /* This no longer applies when we allow the plot to be smaller
578 than the sampled space.
579 for(i=0; (i<len); i++) {
580 if (nbin[i] != (b->index[i+1] - b->index[i]))
581 gmx_fatal(FARGS,"nbin[%d] = %d, should be %d",i,nbin[i],
582 b->index[i+1] - b->index[i]);
585 /* Write the index file */
586 fp = ffopen(ndx,"w");
587 for(i=0; (i<len); i++) {
588 if (nbin[i] > 0) {
589 fprintf(fp,"[ %d ]\n",i);
590 for(j=b->index[i]; (j<b->index[i+1]); j++)
591 fprintf(fp,"%d\n",b->a[j]+1);
594 ffclose(fp);
595 snew(axis_x,ibox[0]+1);
596 snew(axis_y,ibox[1]+1);
597 snew(axis_z,ibox[2]+1);
598 maxbox = max(ibox[0],max(ibox[1],ibox[2]));
599 snew(PP,maxbox*maxbox);
600 snew(WW,maxbox*maxbox);
601 snew(EE,maxbox*maxbox);
602 snew(SS,maxbox*maxbox);
603 for(i=0; (i<min(neig,3)); i++) {
604 switch (i) {
605 case 0: axis = axis_x; break;
606 case 1: axis = axis_y; break;
607 case 2: axis = axis_z; break;
608 default: break;
610 for(j=0; j<=ibox[i]; j++)
611 axis[j] = min_eig[i] + j/bfac[i];
613 if (map) {
614 snew(M,len);
615 snew(MM,maxbox*maxbox);
616 for(i=0; (i<ibox[0]); i++)
617 MM[i] = &(M[i*ibox[1]]);
618 Mmin = 1e8;
619 Mmax = -1e8;
620 for(i=0; (i<nmap); i++) {
621 Mmin = min(Mmin,map[0][i]);
622 Mmax = max(Mmax,map[0][i]);
624 Minf = Mmax*1.05;
625 for(i=0; (i<len); i++)
626 M[i] = Minf;
627 for(i=0; (i<nmap); i++) {
628 index = gmx_nint(mapindex[i]);
629 if (index >= len)
630 gmx_fatal(FARGS,"Number of bins in file from -mdata option does not correspond to current analysis");
632 if (P[index] != 0)
633 M[index] = map[0][i];
636 else {
637 MM = NULL;
638 Minf = NOTSET;
640 pick_minima(logf,ibox,neig,len,W);
641 if (gmax <= 0)
642 gmax = Winf;
643 flags = MAT_SPATIAL_X | MAT_SPATIAL_Y;
644 if (neig == 2) {
645 /* Dump to XPM file */
646 snew(PP,ibox[0]);
647 for(i=0; (i<ibox[0]); i++) {
648 snew(PP[i],ibox[1]);
649 for(j=0; j<ibox[1]; j++) {
650 PP[i][j] = P[i*ibox[1]+j];
652 WW[i] = &(W[i*ibox[1]]);
653 EE[i] = &(E[i*ibox[1]]);
654 SS[i] = &(S[i*ibox[1]]);
656 fp = ffopen(xpmP,"w");
657 write_xpm(fp,flags,"Probability Distribution","","PC1","PC2",
658 ibox[0],ibox[1],axis_x,axis_y,PP,0,Pmax,rlo,rhi,&nlevels);
659 ffclose(fp);
660 fp = ffopen(xpm,"w");
661 write_xpm(fp,flags,"Gibbs Energy Landscape","G (kJ/mol)","PC1","PC2",
662 ibox[0],ibox[1],axis_x,axis_y,WW,0,gmax,rlo,rhi,&nlevels);
663 ffclose(fp);
664 fp = ffopen(xpm2,"w");
665 write_xpm(fp,flags,"Enthalpy Landscape","H (kJ/mol)","PC1","PC2",
666 ibox[0],ibox[1],axis_x,axis_y,EE,
667 emin ? *emin : Emin,emax ? *emax : Einf,rlo,rhi,&nlevels);
668 ffclose(fp);
669 fp = ffopen(xpm3,"w");
670 write_xpm(fp,flags,"Entropy Landscape","TDS (kJ/mol)","PC1","PC2",
671 ibox[0],ibox[1],axis_x,axis_y,SS,0,Sinf,rlo,rhi,&nlevels);
672 ffclose(fp);
673 if (map) {
674 fp = ffopen(xpm4,"w");
675 write_xpm(fp,flags,"Custom Landscape",mname,"PC1","PC2",
676 ibox[0],ibox[1],axis_x,axis_y,MM,0,Minf,rlo,rhi,&nlevels);
677 ffclose(fp);
680 else if (neig == 3) {
681 /* Dump to PDB file */
682 fp = ffopen(pdb,"w");
683 for(i=0; (i<ibox[0]); i++) {
684 xxx[XX] = 3*(i+0.5-ibox[0]/2);
685 for(j=0; (j<ibox[1]); j++) {
686 xxx[YY] = 3*(j+0.5-ibox[1]/2);
687 for(k=0; (k<ibox[2]); k++) {
688 xxx[ZZ] = 3*(k+0.5-ibox[2]/2);
689 index = index3(ibox,i,j,k);
690 if (P[index] > 0)
691 fprintf(fp,"%-6s%5u %-4.4s%3.3s %4d %8.3f%8.3f%8.3f%6.2f%6.2f\n",
692 "ATOM",(index+1) %10000,"H","H",(index+1)%10000,
693 xxx[XX],xxx[YY],xxx[ZZ],1.0,W[index]);
697 ffclose(fp);
698 write_xplor("out.xplor",W,ibox,min_eig,max_eig);
699 if (map)
700 write_xplor("user.xplor",M,ibox,min_eig,max_eig);
701 nxyz[XX] = imin/(ibox[1]*ibox[2]);
702 nxyz[YY] = (imin-nxyz[XX]*ibox[1]*ibox[2])/ibox[2];
703 nxyz[ZZ] = imin % ibox[2];
704 for(i=0; (i<ibox[0]); i++) {
705 snew(WW[i],maxbox);
706 for(j=0; (j<ibox[1]); j++)
707 WW[i][j] = W[index3(ibox,i,j,nxyz[ZZ])];
709 snew(buf,strlen(xpm)+4);
710 sprintf(buf,"%s",xpm);
711 sprintf(&buf[strlen(xpm)-4],"12.xpm");
712 fp = ffopen(buf,"w");
713 write_xpm(fp,flags,"Gibbs Energy Landscape","W (kJ/mol)","PC1","PC2",
714 ibox[0],ibox[1],axis_x,axis_y,WW,0,gmax,rlo,rhi,&nlevels);
715 ffclose(fp);
716 for(i=0; (i<ibox[0]); i++) {
717 for(j=0; (j<ibox[2]); j++)
718 WW[i][j] = W[index3(ibox,i,nxyz[YY],j)];
720 sprintf(&buf[strlen(xpm)-4],"13.xpm");
721 fp = ffopen(buf,"w");
722 write_xpm(fp,flags,"SHAM Energy Landscape","kJ/mol","PC1","PC3",
723 ibox[0],ibox[2],axis_x,axis_z,WW,0,gmax,rlo,rhi,&nlevels);
724 ffclose(fp);
725 for(i=0; (i<ibox[1]); i++) {
726 for(j=0; (j<ibox[2]); j++)
727 WW[i][j] = W[index3(ibox,nxyz[XX],i,j)];
729 sprintf(&buf[strlen(xpm)-4],"23.xpm");
730 fp = ffopen(buf,"w");
731 write_xpm(fp,flags,"SHAM Energy Landscape","kJ/mol","PC2","PC3",
732 ibox[1],ibox[2],axis_y,axis_z,WW,0,gmax,rlo,rhi,&nlevels);
733 ffclose(fp);
734 sfree(buf);
736 if (map) {
737 sfree(MM);
738 sfree(M);
742 static void ehisto(const char *fh,int n,real **enerT, const output_env_t oenv)
744 FILE *fp;
745 int i,j,k,nbin,blength;
746 int *bindex;
747 real *T,bmin,bmax,bwidth;
748 int **histo;
750 bmin = 1e8;
751 bmax = -1e8;
752 snew(bindex,n);
753 snew(T,n);
754 nbin = 0;
755 for(j=1; (j<n); j++) {
756 for(k=0; (k<nbin); k++) {
757 if (T[k] == enerT[1][j]) {
758 bindex[j] = k;
759 break;
762 if (k == nbin) {
763 bindex[j] = nbin;
764 T[nbin] = enerT[1][j];
765 nbin++;
767 bmin = min(enerT[0][j],bmin);
768 bmax = max(enerT[0][j],bmax);
770 bwidth = 1.0;
771 blength = (bmax - bmin)/bwidth + 2;
772 snew(histo,nbin);
773 for(i=0; (i<nbin); i++) {
774 snew(histo[i],blength);
776 for(j=0; (j<n); j++) {
777 k = (enerT[0][j]-bmin)/bwidth;
778 histo[bindex[j]][k]++;
780 fp = xvgropen(fh,"Energy distribution","E (kJ/mol)","",oenv);
781 for(j=0; (j<blength); j++) {
782 fprintf(fp,"%8.3f",bmin+j*bwidth);
783 for(k=0; (k<nbin); k++) {
784 fprintf(fp," %6d",histo[k][j]);
786 fprintf(fp,"\n");
788 ffclose(fp);
791 int gmx_sham(int argc,char *argv[])
793 const char *desc[] = {
794 "[TT]g_sham[tt] makes multi-dimensional free-energy, enthalpy and entropy plots.",
795 "[TT]g_sham[tt] reads one or more [TT].xvg[tt] files and analyzes data sets.",
796 "The basic purpose of [TT]g_sham[tt] is to plot Gibbs free energy landscapes",
797 "(option [TT]-ls[tt])",
798 "by Bolzmann inverting multi-dimensional histograms (option [TT]-lp[tt]),",
799 "but it can also",
800 "make enthalpy (option [TT]-lsh[tt]) and entropy (option [TT]-lss[tt])",
801 "plots. The histograms can be made for any quantities the user supplies.",
802 "A line in the input file may start with a time",
803 "(see option [TT]-time[tt]) and any number of [IT]y[it]-values may follow.",
804 "Multiple sets can also be",
805 "read when they are separated by & (option [TT]-n[tt]),",
806 "in this case only one [IT]y[it]-value is read from each line.",
807 "All lines starting with # and @ are skipped.",
808 "[PAR]",
809 "Option [TT]-ge[tt] can be used to supply a file with free energies",
810 "when the ensemble is not a Boltzmann ensemble, but needs to be biased",
811 "by this free energy. One free energy value is required for each",
812 "(multi-dimensional) data point in the [TT]-f[tt] input.",
813 "[PAR]",
814 "Option [TT]-ene[tt] can be used to supply a file with energies.",
815 "These energies are used as a weighting function in the single",
816 "histogram analysis method by Kumar et al. When temperatures",
817 "are supplied (as a second column in the file), an experimental",
818 "weighting scheme is applied. In addition the vales",
819 "are used for making enthalpy and entropy plots.",
820 "[PAR]",
821 "With option [TT]-dim[tt], dimensions can be gives for distances.",
822 "When a distance is 2- or 3-dimensional, the circumference or surface",
823 "sampled by two particles increases with increasing distance.",
824 "Depending on what one would like to show, one can choose to correct",
825 "the histogram and free-energy for this volume effect.",
826 "The probability is normalized by r and r^2 for dimensions of 2 and 3, ",
827 "respectively.",
828 "A value of -1 is used to indicate an angle in degrees between two",
829 "vectors: a sin(angle) normalization will be applied.",
830 "[BB]Note[bb] that for angles between vectors the inner-product or cosine",
831 "is the natural quantity to use, as it will produce bins of the same",
832 "volume."
834 static real tb=-1,te=-1,frac=0.5,filtlen=0,binwidth=0.1;
835 static gmx_bool bHaveT=TRUE,bDer=FALSE,bSubAv=TRUE,bAverCorr=FALSE,bXYdy=FALSE;
836 static gmx_bool bEESEF=FALSE,bEENLC=FALSE,bEeFitAc=FALSE,bPower=FALSE;
837 static gmx_bool bShamEner=TRUE,bSham=TRUE;
838 static real Tref=298.15,pmin=0,ttol=0,pmax=0,gmax=0,emin=0,emax=0;
839 static rvec nrdim = {1,1,1};
840 static rvec nrbox = {32,32,32};
841 static rvec xmin = {0,0,0}, xmax={1,1,1};
842 static int nsets_in=1,nb_min=4,resol=10,nlevels=25;
843 static const char *mname="";
844 t_pargs pa[] = {
845 { "-time", FALSE, etBOOL, {&bHaveT},
846 "Expect a time in the input" },
847 { "-b", FALSE, etREAL, {&tb},
848 "First time to read from set" },
849 { "-e", FALSE, etREAL, {&te},
850 "Last time to read from set" },
851 { "-ttol", FALSE, etREAL, {&ttol},
852 "Tolerance on time in appropriate units (usually ps)" },
853 { "-n", FALSE, etINT, {&nsets_in},
854 "Read this number of sets separated by lines containing only an ampersand" },
855 { "-d", FALSE, etBOOL, {&bDer},
856 "Use the derivative" },
857 { "-bw", FALSE, etREAL, {&binwidth},
858 "Binwidth for the distribution" },
859 { "-sham", FALSE, etBOOL, {&bSham},
860 "Turn off energy weighting even if energies are given" },
861 { "-tsham", FALSE, etREAL, {&Tref},
862 "Temperature for single histogram analysis" },
863 { "-pmin", FALSE, etREAL, {&pmin},
864 "Minimum probability. Anything lower than this will be set to zero" },
865 { "-dim", FALSE, etRVEC, {nrdim},
866 "Dimensions for distances, used for volume correction (max 3 values, dimensions > 3 will get the same value as the last)" },
867 { "-ngrid", FALSE, etRVEC, {nrbox},
868 "Number of bins for energy landscapes (max 3 values, dimensions > 3 will get the same value as the last)" },
869 { "-xmin", FALSE, etRVEC, {xmin},
870 "Minimum for the axes in energy landscape (see above for > 3 dimensions)" },
871 { "-xmax", FALSE, etRVEC, {xmax},
872 "Maximum for the axes in energy landscape (see above for > 3 dimensions)" },
873 { "-pmax", FALSE, etREAL, {&pmax},
874 "Maximum probability in output, default is calculate" },
875 { "-gmax", FALSE, etREAL, {&gmax},
876 "Maximum free energy in output, default is calculate" },
877 { "-emin", FALSE, etREAL, {&emin},
878 "Minimum enthalpy in output, default is calculate" },
879 { "-emax", FALSE, etREAL, {&emax},
880 "Maximum enthalpy in output, default is calculate" },
881 { "-nlevels", FALSE, etINT, {&nlevels},
882 "Number of levels for energy landscape" },
883 { "-mname", FALSE, etSTR, {&mname},
884 "Legend label for the custom landscape" },
886 #define NPA asize(pa)
888 FILE *out;
889 int n,e_n,d_n,nlast,s,nset,e_nset,d_nset,i,j=0,*idim,*ibox;
890 real **val,**et_val,**dt_val,*t,*e_t,e_dt,d_dt,*d_t,dt,tot,error;
891 real *rmin,*rmax;
892 double *av,*sig,cum1,cum2,cum3,cum4,db;
893 const char *fn_ge,*fn_ene;
894 output_env_t oenv;
895 gmx_large_int_t num_grid_points;
897 t_filenm fnm[] = {
898 { efXVG, "-f", "graph", ffREAD },
899 { efXVG, "-ge", "gibbs", ffOPTRD },
900 { efXVG, "-ene", "esham", ffOPTRD },
901 { efXVG, "-dist", "ener", ffOPTWR },
902 { efXVG, "-histo","edist", ffOPTWR },
903 { efNDX, "-bin", "bindex", ffOPTWR },
904 { efXPM, "-lp", "prob", ffOPTWR },
905 { efXPM, "-ls", "gibbs", ffOPTWR },
906 { efXPM, "-lsh", "enthalpy", ffOPTWR },
907 { efXPM, "-lss", "entropy", ffOPTWR },
908 { efXPM, "-map", "map", ffOPTWR },
909 { efPDB, "-ls3", "gibbs3", ffOPTWR },
910 { efXVG, "-mdata","mapdata", ffOPTRD },
911 { efLOG, "-g", "shamlog", ffOPTWR }
913 #define NFILE asize(fnm)
915 int npargs;
917 npargs = asize(pa);
919 CopyRight(stderr,argv[0]);
920 parse_common_args(&argc,argv,PCA_CAN_VIEW | PCA_BE_NICE ,
921 NFILE,fnm,npargs,pa,asize(desc),desc,0,NULL,&oenv);
923 val=read_xvg_time(opt2fn("-f",NFILE,fnm),bHaveT,
924 opt2parg_bSet("-b",npargs,pa),tb-ttol,
925 opt2parg_bSet("-e",npargs,pa),te+ttol,
926 nsets_in,&nset,&n,&dt,&t);
927 printf("Read %d sets of %d points, dt = %g\n\n",nset,n,dt);
929 fn_ge = opt2fn_null("-ge",NFILE,fnm);
930 fn_ene = opt2fn_null("-ene",NFILE,fnm);
932 if (fn_ge && fn_ene)
933 gmx_fatal(FARGS,"Can not do free energy and energy corrections at the same time");
935 if (fn_ge || fn_ene) {
936 et_val=read_xvg_time(fn_ge ? fn_ge : fn_ene,bHaveT,
937 opt2parg_bSet("-b",npargs,pa),tb-ttol,
938 opt2parg_bSet("-e",npargs,pa),te+ttol,
939 1,&e_nset,&e_n,&e_dt,&e_t);
940 if (fn_ge) {
941 if (e_nset != 1)
942 gmx_fatal(FARGS,"Can only handle one free energy component in %s",
943 fn_ge);
944 } else {
945 if (e_nset!=1 && e_nset!=2)
946 gmx_fatal(FARGS,"Can only handle one energy component or one energy and one T in %s",
947 fn_ene);
949 if (e_n != n)
950 gmx_fatal(FARGS,"Number of energies (%d) does not match number of entries (%d) in %s",e_n,n,opt2fn("-f",NFILE,fnm));
952 else
953 et_val = NULL;
955 if (opt2fn_null("-mdata",NFILE,fnm) != NULL) {
956 dt_val=read_xvg_time(opt2fn("-mdata",NFILE,fnm),bHaveT,
957 FALSE,tb,FALSE,te,
958 nsets_in,&d_nset,&d_n,&d_dt,&d_t);
959 if (d_nset != 1)
960 gmx_fatal(FARGS,"Can only handle one mapping data column in %s",
961 opt2fn("-mdata",NFILE,fnm));
963 else
964 dt_val = NULL;
966 if (fn_ene && et_val)
967 ehisto(opt2fn("-histo",NFILE,fnm),e_n,et_val,oenv);
969 snew(idim,max(3,nset));
970 snew(ibox,max(3,nset));
971 snew(rmin,max(3,nset));
972 snew(rmax,max(3,nset));
973 for(i=0; (i<min(3,nset)); i++) {
974 idim[i] = nrdim[i];
975 ibox[i] = nrbox[i];
976 rmin[i] = xmin[i];
977 rmax[i] = xmax[i];
979 for(; (i<nset); i++) {
980 idim[i] = nrdim[2];
981 ibox[i] = nrbox[2];
982 rmin[i] = xmin[2];
983 rmax[i] = xmax[2];
986 /* Check that the grid size is manageable. */
987 num_grid_points = ibox[0];
988 for(i = 1; i < nset; i++)
990 gmx_large_int_t result;
991 if (!check_int_multiply_for_overflow(num_grid_points, ibox[i], &result))
993 gmx_fatal(FARGS,
994 "The number of dimensions and grid points is too large for this tool\n"
995 "to handle with what it knows about the architecture upon which it\n"
996 "is running. Use a different machine or consult the GROMACS mailing list.");
998 num_grid_points = result;
1000 /* The number of grid points fits in a gmx_large_int_t. */
1002 do_sham(opt2fn("-dist",NFILE,fnm),opt2fn("-bin",NFILE,fnm),
1003 opt2fn("-lp",NFILE,fnm),
1004 opt2fn("-ls",NFILE,fnm),opt2fn("-lsh",NFILE,fnm),
1005 opt2fn("-lss",NFILE,fnm),opt2fn("-map",NFILE,fnm),
1006 opt2fn("-ls3",NFILE,fnm),opt2fn("-g",NFILE,fnm),
1007 n,nset,val,fn_ge!=NULL,e_nset,et_val,d_n,d_t,dt_val,Tref,
1008 pmax,gmax,
1009 opt2parg_bSet("-emin",NPA,pa) ? &emin : NULL,
1010 opt2parg_bSet("-emax",NPA,pa) ? &emax : NULL,
1011 nlevels,pmin,
1012 mname,bSham,idim,ibox,
1013 opt2parg_bSet("-xmin",NPA,pa),rmin,
1014 opt2parg_bSet("-xmax",NPA,pa),rmax);
1016 thanx(stderr);
1018 return 0;