Merge release-4-6 into master
[alexxy/gromacs.git] / src / gromacs / gmxlib / readinp.c
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.
14
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.
19  * 
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.
26  * 
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.
29  * 
30  * For more info, check our website at http://www.gromacs.org
31  * 
32  * And Hey:
33  * GROningen Mixture of Alchemy and Childrens' Stories
34  */
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include "typedefs.h"
42 #include "string2.h"
43 #include "futil.h"
44 #include "smalloc.h"
45 #include "readinp.h"
46 #include "macros.h"
47 #include "statutil.h"
48 #include "gmxfio.h"
49 #include "names.h"
50 #include "warninp.h"
51 #include "gmx_fatal.h"
52
53 /* find an entry; return index, or -1 if not found */
54 static int search_einp(int ninp, const t_inpfile *inp, const char *name);
55
56
57 t_inpfile *read_inpfile(const char *fn,int *ninp, 
58                         char **cppopts,
59                         warninp_t wi)
60 {
61   FILE      *in;
62   char      buf[STRLEN],lbuf[STRLEN],rbuf[STRLEN],warn_buf[STRLEN];
63   char      *ptr,*cptr;
64   t_inpfile *inp=NULL;
65   int       nin,lc,i,j,k;
66   /* setting cppopts from command-line options would be cooler */
67   gmx_bool allow_override=FALSE;
68
69     
70   if (debug)
71     fprintf(debug,"Reading MDP file %s\n",fn);
72     
73   in = ffopen(fn, "r");
74
75   nin = lc  = 0;
76   do {
77     ptr = fgets2(buf,STRLEN-1,in);
78     lc++;
79     set_warning_line(wi,fn,lc);
80     if (ptr) {
81       /* Strip comment */
82       if ((cptr=strchr(buf,COMMENTSIGN)) != NULL)
83         *cptr='\0';
84       /* Strip spaces */
85       trim(buf);
86       
87       for(j=0; (buf[j] != '=') && (buf[j] != '\0'); j++)
88         ;
89       if (buf[j] == '\0') {
90         if (j > 0) {
91           if (debug)
92             fprintf(debug,"No = on line %d in file %s, ignored\n",lc,fn);
93         }
94       }
95       else {
96         for(i=0; (i<j); i++)
97           lbuf[i]=buf[i];
98         lbuf[i]='\0';
99         trim(lbuf);
100         if (lbuf[0] == '\0') {
101           if (debug) 
102             fprintf(debug,"Empty left hand side on line %d in file %s, ignored\n",lc,fn);
103         }
104         else {
105           for(i=j+1,k=0; (buf[i] != '\0'); i++,k++)
106             rbuf[k]=buf[i];
107           rbuf[k]='\0';
108           trim(rbuf);
109           if (rbuf[0] == '\0') {
110             if (debug)
111               fprintf(debug,"Empty right hand side on line %d in file %s, ignored\n",lc,fn);
112           }
113           else {
114             /* Now finally something sensible */
115             int found_index;
116             
117             /* first check whether we hit the 'multiple_entries' option */
118             if (gmx_strcasecmp_min(eMultentOpt_names[eMultentOptName], lbuf)==0) 
119             {
120               /* we now check whether to allow overrides from here or not */
121               if (gmx_strcasecmp_min(eMultentOpt_names[eMultentOptNo], rbuf)==0)
122               {
123                 allow_override=FALSE;
124               }
125               else if (gmx_strcasecmp_min(eMultentOpt_names[eMultentOptLast], rbuf)==0)
126               {
127                 allow_override=TRUE;
128               }
129               else
130               {
131                 sprintf(warn_buf,
132                         "Parameter \"%s\" should either be %s or %s\n",
133                         lbuf,
134                         eMultentOpt_names[eMultentOptNo],
135                         eMultentOpt_names[eMultentOptLast]);
136                 warning_error(wi,warn_buf);
137               }
138             }
139             else
140             {
141               /* it is a regular option; check for duplicates */
142               found_index=search_einp(nin, inp, lbuf);
143               
144               if (found_index == -1)
145               {
146                 /* add a new item */
147                 srenew(inp,++nin);
148                 inp[nin-1].inp_count  = 1;
149                 inp[nin-1].count      = 0;
150                 inp[nin-1].bObsolete  = FALSE;
151                 inp[nin-1].bSet       = FALSE;
152                 inp[nin-1].name       = strdup(lbuf);
153                 inp[nin-1].value      = strdup(rbuf);
154               }
155               else
156               {
157                 if (!allow_override)
158                 {
159                   sprintf(warn_buf,
160                           "Parameter \"%s\" doubly defined (and multiple assignments not allowed)\n",
161                           lbuf);
162                   warning_error(wi,warn_buf);
163                 }
164                 else
165                 {
166                   /* override */
167                   sfree(inp[found_index].value);
168                   inp[found_index].value = strdup(rbuf);
169                   sprintf(warn_buf,
170                           "Overriding existing parameter \"%s\" with value \"%s\"\n",
171                           lbuf,rbuf);
172                   warning_note(wi,warn_buf);
173                 }
174               }
175             }
176           }
177         }
178       }
179     }
180   } while (ptr);
181   
182   ffclose(in);
183
184   if (debug) {
185     fprintf(debug,"Done reading MDP file, there were %d entries in there\n",
186             nin);
187   }
188
189   *ninp = nin;
190
191   return inp;
192 }
193
194         
195                   
196
197 static int inp_comp(const void *a,const void *b)
198 {
199   return ((t_inpfile *)a)->count - ((t_inpfile *)b)->count;
200 }
201
202 static void sort_inp(int ninp,t_inpfile inp[])
203 {
204   int i,mm;
205   
206   mm=-1;
207   for(i=0; (i<ninp); i++)
208     mm=max(mm,inp[i].count);
209   for(i=0; (i<ninp); i++) {
210     if (inp[i].count == 0)
211       inp[i].count = mm++;
212   }
213   qsort(inp,ninp,(size_t)sizeof(inp[0]),inp_comp);
214 }
215
216 void write_inpfile(const char *fn,int ninp,t_inpfile inp[],gmx_bool bHaltOnUnknown,
217                    warninp_t wi)
218 {
219   FILE *out;
220   int  i;
221   char warn_buf[STRLEN];
222
223   sort_inp(ninp,inp);  
224   out=gmx_fio_fopen(fn,"w");
225   nice_header(out,fn);
226   for(i=0; (i<ninp); i++) {
227     if (inp[i].bSet) {
228       if(inp[i].name[0]==';' || (strlen(inp[i].name)>2 && inp[i].name[1]==';'))
229         fprintf(out,"%-24s\n",inp[i].name);
230       else
231         fprintf(out,"%-24s = %s\n",inp[i].name,inp[i].value ? inp[i].value : "");
232     } else if (!inp[i].bObsolete) {
233       sprintf(warn_buf,"Unknown left-hand '%s' in parameter file\n",
234               inp[i].name);
235       if (bHaltOnUnknown) {
236         warning_error(wi,warn_buf);
237       } else {
238         warning(wi,warn_buf);
239       }
240     }
241   }
242   gmx_fio_fclose(out);
243
244   check_warning_error(wi,FARGS);
245 }
246
247 void replace_inp_entry(int ninp,t_inpfile *inp,const char *old_entry,const char *new_entry)
248 {
249   int  i;
250   
251   for(i=0; (i<ninp); i++) {
252     if (gmx_strcasecmp_min(old_entry,inp[i].name) == 0) {
253       if (new_entry) {
254         fprintf(stderr,"Replacing old mdp entry '%s' by '%s'\n",
255                 inp[i].name,new_entry);
256         sfree(inp[i].name);
257         inp[i].name = strdup(new_entry);
258       } else {
259         fprintf(stderr,"Ignoring obsolete mdp entry '%s'\n",
260                 inp[i].name);
261         inp[i].bObsolete = TRUE;
262       }
263     }
264   }
265 }
266
267 static int search_einp(int ninp, const t_inpfile *inp, const char *name)
268 {
269   int i;
270   
271   if (inp==NULL)
272     return -1;
273   for(i=0; i<ninp; i++)
274     if (gmx_strcasecmp_min(name,inp[i].name) == 0)
275       return i;
276   return -1;
277 }
278
279 static int get_einp(int *ninp,t_inpfile **inp,const char *name)
280 {
281   int    i;
282   int    notfound=FALSE;
283   char   warn_buf[STRLEN];
284
285 /*  if (inp==NULL)
286     return -1;
287   for(i=0; (i<(*ninp)); i++)
288     if (gmx_strcasecmp_min(name,(*inp)[i].name) == 0)
289       break;
290   if (i == (*ninp)) {*/
291   i=search_einp(*ninp, *inp, name);
292   if (i == -1)
293   {
294     notfound=TRUE;
295     i=(*ninp)++;
296     srenew(*inp,(*ninp));
297     (*inp)[i].name=strdup(name);
298     (*inp)[i].bSet=TRUE;
299   }
300   (*inp)[i].count = (*inp)[0].inp_count++;
301   (*inp)[i].bSet  = TRUE;
302   if (debug) 
303     fprintf(debug,"Inp %d = %s\n",(*inp)[i].count,(*inp)[i].name);
304   
305   /*if (i == (*ninp)-1)*/
306   if (notfound)
307     return -1;
308   else
309     return i;
310 }
311
312 int get_eint(int *ninp,t_inpfile **inp,const char *name,int def,
313              warninp_t wi)
314 {
315   char buf[32],*ptr,warn_buf[STRLEN];
316   int  ii;
317   int  ret;
318   
319   ii=get_einp(ninp,inp,name);
320   
321   if (ii == -1) {
322     sprintf(buf,"%d",def);
323     (*inp)[(*ninp)-1].value=strdup(buf);
324     
325     return def;
326   }
327   else {
328     ret = strtol((*inp)[ii].value,&ptr,10);
329     if (ptr == (*inp)[ii].value) {
330       sprintf(warn_buf,"Right hand side '%s' for parameter '%s' in parameter file is not an integer value\n",(*inp)[ii].value,(*inp)[ii].name);
331       warning_error(wi,warn_buf);
332     }
333
334     return ret;
335   }
336 }
337
338 gmx_large_int_t get_egmx_large_int(int *ninp,t_inpfile **inp,
339                                    const char *name,gmx_large_int_t def,
340                                    warninp_t wi)
341 {
342   char buf[32],*ptr,warn_buf[STRLEN];
343   int  ii;
344   gmx_large_int_t ret;
345   
346   ii=get_einp(ninp,inp,name);
347   
348   if (ii == -1) {
349     sprintf(buf,gmx_large_int_pfmt,def);
350     (*inp)[(*ninp)-1].value=strdup(buf);
351     
352     return def;
353   }
354   else {
355     ret = str_to_large_int_t((*inp)[ii].value,&ptr);
356     if (ptr == (*inp)[ii].value) {
357       sprintf(warn_buf,"Right hand side '%s' for parameter '%s' in parameter file is not an integer value\n",(*inp)[ii].value,(*inp)[ii].name);
358       warning_error(wi,warn_buf);
359     }
360
361     return ret;
362   }
363 }
364
365 double get_ereal(int *ninp,t_inpfile **inp,const char *name,double def,
366                  warninp_t wi)
367 {
368   char buf[32],*ptr,warn_buf[STRLEN];
369   int  ii;
370   double ret;
371   
372   ii=get_einp(ninp,inp,name);
373   
374   if (ii == -1) {
375     sprintf(buf,"%g",def);
376     (*inp)[(*ninp)-1].value=strdup(buf);
377     
378     return def;
379   }
380   else {
381     ret = strtod((*inp)[ii].value,&ptr);
382     if (ptr == (*inp)[ii].value) {
383       sprintf(warn_buf,"Right hand side '%s' for parameter '%s' in parameter file is not a real value\n",(*inp)[ii].value,(*inp)[ii].name);
384       warning_error(wi,warn_buf);
385     }
386
387     return ret;
388   }
389 }
390
391 const char *get_estr(int *ninp,t_inpfile **inp,const char *name,const char *def)
392 {
393   char buf[32];
394   int  ii;
395   
396   ii=get_einp(ninp,inp,name);
397   
398   if (ii == -1) {
399     if (def) {
400       sprintf(buf,"%s",def);
401       (*inp)[(*ninp)-1].value=strdup(buf);
402     }
403     else
404       (*inp)[(*ninp)-1].value=NULL;
405       
406     return def;
407   }
408   else 
409     return (*inp)[ii].value;
410 }
411
412 int get_eeenum(int *ninp,t_inpfile **inp,const char *name,const char **defs,
413                warninp_t wi)
414 {
415   int  ii,i,j;
416   int n=0;
417   char buf[STRLEN];
418   
419   ii=get_einp(ninp,inp,name);
420   
421   if (ii == -1) {
422     (*inp)[(*ninp)-1].value=strdup(defs[0]);
423     
424     return 0;
425   }
426   
427   for(i=0; (defs[i] != NULL); i++)
428     if (gmx_strcasecmp_min(defs[i],(*inp)[ii].value) == 0)
429       break;
430   
431   if (defs[i] == NULL) {
432     n += sprintf(buf,"Invalid enum '%s' for variable %s, using '%s'\n",
433                 (*inp)[ii].value,name,defs[0]);
434     n += sprintf(buf+n,"Next time use one of:");
435     j=0;
436     while (defs[j]) {
437       n += sprintf(buf+n," '%s'",defs[j]);
438       j++;
439     }
440     if (wi != NULL) {
441       warning_error(wi,buf);
442     } else {
443       fprintf(stderr,"%s\n",buf);
444     }
445
446     (*inp)[ii].value = strdup(defs[0]);
447     
448     return 0;
449   }
450   
451   return i;
452 }
453
454 int get_eenum(int *ninp,t_inpfile **inp,const char *name,const char **defs)
455 {
456   int dum=0;
457
458   return get_eeenum(ninp,inp,name,defs,NULL);
459 }
460