Merge release-4-6 into master
[alexxy/gromacs.git] / src / gromacs / mdlib / ebin.c
1 /* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
2  *
3  * 
4  *                This source code is part of
5  * 
6  *                 G   R   O   M   A   C   S
7  * 
8  *          GROningen MAchine for Chemical Simulations
9  * 
10  *                        VERSION 3.2.0
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-2004, The GROMACS development team,
14  * check out http://www.gromacs.org for more information.
15
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.
20  * 
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.
27  * 
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.
30  * 
31  * For more info, check our website at http://www.gromacs.org
32  * 
33  * And Hey:
34  * GROwing Monsters And Cloning Shrimps
35  */
36 /* This file is completely threadsafe - keep it that way! */
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #include <math.h>
42 #include <string.h>
43 #include "sysstuff.h"
44 #include "smalloc.h"
45 #include "typedefs.h"
46 #include "gmx_fatal.h"
47 #include "string2.h"
48 #include "ebin.h"
49 #include "main.h"
50 #include "maths.h"
51 #include "vec.h"
52 #include "physics.h"
53
54 t_ebin *mk_ebin(void)
55 {
56   t_ebin *eb;
57   
58   snew(eb,1);
59   
60   return eb;
61 }
62
63 int get_ebin_space(t_ebin *eb,int nener,const char *enm[],const char *unit)
64 {
65     int  index;
66     int  i,f;
67     const char *u;
68
69     index = eb->nener;
70     eb->nener += nener;
71     srenew(eb->e,eb->nener);
72     srenew(eb->e_sim,eb->nener);
73     srenew(eb->enm,eb->nener);
74     for(i=index; (i<eb->nener); i++)
75     {
76         eb->e[i].e        = 0;
77         eb->e[i].eav      = 0;
78         eb->e[i].esum     = 0;
79         eb->e_sim[i].e    = 0;
80         eb->e_sim[i].eav  = 0;
81         eb->e_sim[i].esum = 0;
82         eb->enm[i].name = strdup(enm[i-index]);
83         if (unit != NULL)
84         {
85             eb->enm[i].unit = strdup(unit);
86         }
87         else
88         {
89             /* Determine the unit from the longname.
90              * These units should have been defined in ifunc.c
91              * But even better would be if all interactions functions
92              * return energies and all non-interaction function
93              * entries would be removed from the ifunc array.
94              */
95             u = unit_energy;
96             for(f=0; f<F_NRE; f++)
97             {
98                 if (strcmp(eb->enm[i].name,
99                            interaction_function[f].longname) == 0)
100                 {
101                     /* Only the terms in this list are not energies */
102                     switch (f) {
103                     case F_DISRESVIOL: u = unit_length;   break;
104                     case F_ORIRESDEV:  u = "obs";         break;
105                     case F_TEMP:       u = unit_temp_K;   break;
106                     case F_PDISPCORR:
107                     case F_PRES:       u = unit_pres_bar; break;
108                     }
109                 }
110             }
111             eb->enm[i].unit = strdup(u);
112         }
113     }
114     
115     return index;
116 }
117
118 void add_ebin(t_ebin *eb,int index,int nener,real ener[],gmx_bool bSum)
119 {
120     int      i,m;
121     double   e,sum,sigma,invmm,diff;
122     t_energy *eg,*egs;
123     
124     if ((index+nener > eb->nener) || (index < 0))
125     {
126         gmx_fatal(FARGS,"%s-%d: Energies out of range: index=%d nener=%d maxener=%d",
127                   __FILE__,__LINE__,index,nener,eb->nener);
128     }
129     
130     eg = &(eb->e[index]);
131     
132     for(i=0; (i<nener); i++)
133     {
134         eg[i].e      = ener[i];
135     }
136     
137     if (bSum)
138     {
139         egs = &(eb->e_sim[index]);
140         
141         m = eb->nsum;
142         
143         if (m == 0)
144         {
145             for(i=0; (i<nener); i++)
146             {
147                 eg[i].eav    = 0;
148                 eg[i].esum   = ener[i];
149                 egs[i].esum += ener[i];
150             }
151         }
152         else
153         {
154             invmm = (1.0/(double)m)/((double)m+1.0);
155             
156             for(i=0; (i<nener); i++)
157             {
158                 /* Value for this component */
159                 e = ener[i];
160                 
161                 /* first update sigma, then sum */
162                 diff         = eg[i].esum - m*e;
163                 eg[i].eav   += diff*diff*invmm;
164                 eg[i].esum  += e;
165                 egs[i].esum += e;
166             }
167         }
168     }
169 }
170
171 void ebin_increase_count(t_ebin *eb,gmx_bool bSum)
172 {
173     eb->nsteps++;
174     eb->nsteps_sim++;
175
176     if (bSum)
177     {
178         eb->nsum++;
179         eb->nsum_sim++;
180     }
181 }
182
183 void reset_ebin_sums(t_ebin *eb)
184 {
185     eb->nsteps = 0;
186     eb->nsum   = 0;
187     /* The actual sums are cleared when the next frame is stored */
188 }
189
190 void pr_ebin(FILE *fp,t_ebin *eb,int index,int nener,int nperline,
191              int prmode,gmx_bool bPrHead)
192 {
193     int  i,j,i0;
194     real ee=0;
195     int  rc;
196     char buf[30];
197
198     rc = 0;
199
200     if (index < 0)
201     {
202         gmx_fatal(FARGS,"Invalid index in pr_ebin: %d",index);
203     }
204     if (nener == -1)
205     {
206         nener = eb->nener;
207     }
208     else
209     {
210         nener = index + nener;
211     }
212     for(i=index; (i<nener) && rc>=0; ) 
213     {
214         if (bPrHead)
215         {
216             i0=i;
217             for(j=0; (j<nperline) && (i<nener) && rc>=0; j++,i++)
218             {
219                 if (strncmp(eb->enm[i].name,"Pres",4) == 0)
220                 {
221                     /* Print the pressure unit to avoid confusion */
222                     sprintf(buf,"%s (%s)",eb->enm[i].name,unit_pres_bar);
223                     rc = fprintf(fp,"%15s",buf);
224                 }
225                 else
226                 {
227                     rc = fprintf(fp,"%15s",eb->enm[i].name);
228                 }
229             }
230
231             if (rc >= 0)
232             {
233                 rc = fprintf(fp,"\n");
234             }
235
236             i=i0;
237         }
238         for(j=0; (j<nperline) && (i<nener) && rc>=0; j++,i++)
239         {
240             switch (prmode) {
241                 case eprNORMAL: ee = eb->e[i].e; break;
242                 case eprAVER:   ee = eb->e_sim[i].esum/eb->nsum_sim; break;
243                 default: gmx_fatal(FARGS,"Invalid print mode %d in pr_ebin",
244                                    prmode);
245             }
246
247             rc = fprintf(fp,"   %12.5e",ee);
248         }
249         if (rc >= 0)
250         {
251             rc = fprintf(fp,"\n");
252         }
253     }
254     if (rc < 0)
255     { 
256         gmx_fatal(FARGS,"Cannot write to logfile; maybe you are out of disk space?");
257     }
258 }
259
260 #ifdef DEBUGEBIN
261 int main(int argc,char *argv[])
262 {
263 #define NE 12
264 #define NT 7
265 #define NS 5
266
267   t_ebin *eb;
268   int    i;
269   char   buf[25];
270   char   *ce[NE],*ct[NT],*cs[NS];
271   real   e[NE],t[NT],s[NS];
272   int    ie,it,is;
273   
274   eb=mk_ebin();
275   for(i=0; (i<NE); i++) {
276     e[i]=i;
277     sprintf(buf,"e%d",i);
278     ce[i]=strdup(buf);
279   }
280   ie=get_ebin_space(eb,NE,ce);
281   add_ebin(eb,ie,NE,e,0);
282   for(i=0; (i<NS); i++) {
283     s[i]=i;
284     sprintf(buf,"s%d",i);
285     cs[i]=strdup(buf);
286   }
287   is=get_ebin_space(eb,NS,cs);
288   add_ebin(eb,is,NS,s,0);
289   for(i=0; (i<NT); i++) {
290     t[i]=i;
291     sprintf(buf,"t%d",i);
292     ct[i]=strdup(buf);
293   }
294   it=get_ebin_space(eb,NT,ct);
295   add_ebin(eb,it,NT,t,0);
296   
297   printf("Normal:\n");
298   pr_ebin(stdout,eb,0,-1,5,eprNORMAL,1);
299
300   printf("Average:\n");
301   pr_ebin(stdout,eb,ie,NE,5,eprAVER,1);
302   pr_ebin(stdout,eb,is,NS,3,eprAVER,1);
303   pr_ebin(stdout,eb,it,NT,4,eprAVER,1);
304 }
305 #endif