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     {
72         fprintf(debug, "Reading MDP file %s\n", fn);
73     }
74
75     in = ffopen(fn, "r");
76
77     nin = lc  = 0;
78     do
79     {
80         ptr = fgets2(buf, STRLEN-1, in);
81         lc++;
82         set_warning_line(wi, fn, lc);
83         if (ptr)
84         {
85             /* Strip comment */
86             if ((cptr = strchr(buf, COMMENTSIGN)) != NULL)
87             {
88                 *cptr = '\0';
89             }
90             /* Strip spaces */
91             trim(buf);
92
93             for (j = 0; (buf[j] != '=') && (buf[j] != '\0'); j++)
94             {
95                 ;
96             }
97             if (buf[j] == '\0')
98             {
99                 if (j > 0)
100                 {
101                     if (debug)
102                     {
103                         fprintf(debug, "No = on line %d in file %s, ignored\n", lc, fn);
104                     }
105                 }
106             }
107             else
108             {
109                 for (i = 0; (i < j); i++)
110                 {
111                     lbuf[i] = buf[i];
112                 }
113                 lbuf[i] = '\0';
114                 trim(lbuf);
115                 if (lbuf[0] == '\0')
116                 {
117                     if (debug)
118                     {
119                         fprintf(debug, "Empty left hand side on line %d in file %s, ignored\n", lc, fn);
120                     }
121                 }
122                 else
123                 {
124                     for (i = j+1, k = 0; (buf[i] != '\0'); i++, k++)
125                     {
126                         rbuf[k] = buf[i];
127                     }
128                     rbuf[k] = '\0';
129                     trim(rbuf);
130                     if (rbuf[0] == '\0')
131                     {
132                         if (debug)
133                         {
134                             fprintf(debug, "Empty right hand side on line %d in file %s, ignored\n", lc, fn);
135                         }
136                     }
137                     else
138                     {
139                         /* Now finally something sensible */
140                         int found_index;
141
142                         /* first check whether we hit the 'multiple_entries' option */
143                         if (gmx_strcasecmp_min(eMultentOpt_names[eMultentOptName], lbuf) == 0)
144                         {
145                             /* we now check whether to allow overrides from here or not */
146                             if (gmx_strcasecmp_min(eMultentOpt_names[eMultentOptNo], rbuf) == 0)
147                             {
148                                 allow_override = FALSE;
149                             }
150                             else if (gmx_strcasecmp_min(eMultentOpt_names[eMultentOptLast], rbuf) == 0)
151                             {
152                                 allow_override = TRUE;
153                             }
154                             else
155                             {
156                                 sprintf(warn_buf,
157                                         "Parameter \"%s\" should either be %s or %s\n",
158                                         lbuf,
159                                         eMultentOpt_names[eMultentOptNo],
160                                         eMultentOpt_names[eMultentOptLast]);
161                                 warning_error(wi, warn_buf);
162                             }
163                         }
164                         else
165                         {
166                             /* it is a regular option; check for duplicates */
167                             found_index = search_einp(nin, inp, lbuf);
168
169                             if (found_index == -1)
170                             {
171                                 /* add a new item */
172                                 srenew(inp, ++nin);
173                                 inp[nin-1].inp_count  = 1;
174                                 inp[nin-1].count      = 0;
175                                 inp[nin-1].bObsolete  = FALSE;
176                                 inp[nin-1].bSet       = FALSE;
177                                 inp[nin-1].name       = strdup(lbuf);
178                                 inp[nin-1].value      = strdup(rbuf);
179                             }
180                             else
181                             {
182                                 if (!allow_override)
183                                 {
184                                     sprintf(warn_buf,
185                                             "Parameter \"%s\" doubly defined (and multiple assignments not allowed)\n",
186                                             lbuf);
187                                     warning_error(wi, warn_buf);
188                                 }
189                                 else
190                                 {
191                                     /* override */
192                                     sfree(inp[found_index].value);
193                                     inp[found_index].value = strdup(rbuf);
194                                     sprintf(warn_buf,
195                                             "Overriding existing parameter \"%s\" with value \"%s\"\n",
196                                             lbuf, rbuf);
197                                     warning_note(wi, warn_buf);
198                                 }
199                             }
200                         }
201                     }
202                 }
203             }
204         }
205     }
206     while (ptr);
207
208     ffclose(in);
209
210     if (debug)
211     {
212         fprintf(debug, "Done reading MDP file, there were %d entries in there\n",
213                 nin);
214     }
215
216     *ninp = nin;
217
218     return inp;
219 }
220
221
222
223
224 static int inp_comp(const void *a, const void *b)
225 {
226     return ((t_inpfile *)a)->count - ((t_inpfile *)b)->count;
227 }
228
229 static void sort_inp(int ninp, t_inpfile inp[])
230 {
231     int i, mm;
232
233     mm = -1;
234     for (i = 0; (i < ninp); i++)
235     {
236         mm = max(mm, inp[i].count);
237     }
238     for (i = 0; (i < ninp); i++)
239     {
240         if (inp[i].count == 0)
241         {
242             inp[i].count = mm++;
243         }
244     }
245     qsort(inp, ninp, (size_t)sizeof(inp[0]), inp_comp);
246 }
247
248 void write_inpfile(const char *fn, int ninp, t_inpfile inp[], gmx_bool bHaltOnUnknown,
249                    warninp_t wi)
250 {
251     FILE *out;
252     int   i;
253     char  warn_buf[STRLEN];
254
255     sort_inp(ninp, inp);
256     out = gmx_fio_fopen(fn, "w");
257     nice_header(out, fn);
258     for (i = 0; (i < ninp); i++)
259     {
260         if (inp[i].bSet)
261         {
262             if (inp[i].name[0] == ';' || (strlen(inp[i].name) > 2 && inp[i].name[1] == ';'))
263             {
264                 fprintf(out, "%-24s\n", inp[i].name);
265             }
266             else
267             {
268                 fprintf(out, "%-24s = %s\n", inp[i].name, inp[i].value ? inp[i].value : "");
269             }
270         }
271         else if (!inp[i].bObsolete)
272         {
273             sprintf(warn_buf, "Unknown left-hand '%s' in parameter file\n",
274                     inp[i].name);
275             if (bHaltOnUnknown)
276             {
277                 warning_error(wi, warn_buf);
278             }
279             else
280             {
281                 warning(wi, warn_buf);
282             }
283         }
284     }
285     gmx_fio_fclose(out);
286
287     check_warning_error(wi, FARGS);
288 }
289
290 void replace_inp_entry(int ninp, t_inpfile *inp, const char *old_entry, const char *new_entry)
291 {
292     int  i;
293
294     for (i = 0; (i < ninp); i++)
295     {
296         if (gmx_strcasecmp_min(old_entry, inp[i].name) == 0)
297         {
298             if (new_entry)
299             {
300                 fprintf(stderr, "Replacing old mdp entry '%s' by '%s'\n",
301                         inp[i].name, new_entry);
302                 sfree(inp[i].name);
303                 inp[i].name = strdup(new_entry);
304             }
305             else
306             {
307                 fprintf(stderr, "Ignoring obsolete mdp entry '%s'\n",
308                         inp[i].name);
309                 inp[i].bObsolete = TRUE;
310             }
311         }
312     }
313 }
314
315 static int search_einp(int ninp, const t_inpfile *inp, const char *name)
316 {
317     int i;
318
319     if (inp == NULL)
320     {
321         return -1;
322     }
323     for (i = 0; i < ninp; i++)
324     {
325         if (gmx_strcasecmp_min(name, inp[i].name) == 0)
326         {
327             return i;
328         }
329     }
330     return -1;
331 }
332
333 static int get_einp(int *ninp, t_inpfile **inp, const char *name)
334 {
335     int    i;
336     int    notfound = FALSE;
337     char   warn_buf[STRLEN];
338
339 /*  if (inp==NULL)
340     return -1;
341    for(i=0; (i<(*ninp)); i++)
342     if (gmx_strcasecmp_min(name,(*inp)[i].name) == 0)
343       break;
344    if (i == (*ninp)) {*/
345     i = search_einp(*ninp, *inp, name);
346     if (i == -1)
347     {
348         notfound = TRUE;
349         i        = (*ninp)++;
350         srenew(*inp, (*ninp));
351         (*inp)[i].name = strdup(name);
352         (*inp)[i].bSet = TRUE;
353     }
354     (*inp)[i].count = (*inp)[0].inp_count++;
355     (*inp)[i].bSet  = TRUE;
356     if (debug)
357     {
358         fprintf(debug, "Inp %d = %s\n", (*inp)[i].count, (*inp)[i].name);
359     }
360
361     /*if (i == (*ninp)-1)*/
362     if (notfound)
363     {
364         return -1;
365     }
366     else
367     {
368         return i;
369     }
370 }
371
372 int get_eint(int *ninp, t_inpfile **inp, const char *name, int def,
373              warninp_t wi)
374 {
375     char buf[32], *ptr, warn_buf[STRLEN];
376     int  ii;
377     int  ret;
378
379     ii = get_einp(ninp, inp, name);
380
381     if (ii == -1)
382     {
383         sprintf(buf, "%d", def);
384         (*inp)[(*ninp)-1].value = strdup(buf);
385
386         return def;
387     }
388     else
389     {
390         ret = strtol((*inp)[ii].value, &ptr, 10);
391         if (ptr == (*inp)[ii].value)
392         {
393             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);
394             warning_error(wi, warn_buf);
395         }
396
397         return ret;
398     }
399 }
400
401 gmx_large_int_t get_egmx_large_int(int *ninp, t_inpfile **inp,
402                                    const char *name, gmx_large_int_t def,
403                                    warninp_t wi)
404 {
405     char            buf[32], *ptr, warn_buf[STRLEN];
406     int             ii;
407     gmx_large_int_t ret;
408
409     ii = get_einp(ninp, inp, name);
410
411     if (ii == -1)
412     {
413         sprintf(buf, gmx_large_int_pfmt, def);
414         (*inp)[(*ninp)-1].value = strdup(buf);
415
416         return def;
417     }
418     else
419     {
420         ret = str_to_large_int_t((*inp)[ii].value, &ptr);
421         if (ptr == (*inp)[ii].value)
422         {
423             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);
424             warning_error(wi, warn_buf);
425         }
426
427         return ret;
428     }
429 }
430
431 double get_ereal(int *ninp, t_inpfile **inp, const char *name, double def,
432                  warninp_t wi)
433 {
434     char   buf[32], *ptr, warn_buf[STRLEN];
435     int    ii;
436     double ret;
437
438     ii = get_einp(ninp, inp, name);
439
440     if (ii == -1)
441     {
442         sprintf(buf, "%g", def);
443         (*inp)[(*ninp)-1].value = strdup(buf);
444
445         return def;
446     }
447     else
448     {
449         ret = strtod((*inp)[ii].value, &ptr);
450         if (ptr == (*inp)[ii].value)
451         {
452             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);
453             warning_error(wi, warn_buf);
454         }
455
456         return ret;
457     }
458 }
459
460 const char *get_estr(int *ninp, t_inpfile **inp, const char *name, const char *def)
461 {
462     char buf[32];
463     int  ii;
464
465     ii = get_einp(ninp, inp, name);
466
467     if (ii == -1)
468     {
469         if (def)
470         {
471             sprintf(buf, "%s", def);
472             (*inp)[(*ninp)-1].value = strdup(buf);
473         }
474         else
475         {
476             (*inp)[(*ninp)-1].value = NULL;
477         }
478
479         return def;
480     }
481     else
482     {
483         return (*inp)[ii].value;
484     }
485 }
486
487 int get_eeenum(int *ninp, t_inpfile **inp, const char *name, const char **defs,
488                warninp_t wi)
489 {
490     int  ii, i, j;
491     int  n = 0;
492     char buf[STRLEN];
493
494     ii = get_einp(ninp, inp, name);
495
496     if (ii == -1)
497     {
498         (*inp)[(*ninp)-1].value = strdup(defs[0]);
499
500         return 0;
501     }
502
503     for (i = 0; (defs[i] != NULL); i++)
504     {
505         if (gmx_strcasecmp_min(defs[i], (*inp)[ii].value) == 0)
506         {
507             break;
508         }
509     }
510
511     if (defs[i] == NULL)
512     {
513         n += sprintf(buf, "Invalid enum '%s' for variable %s, using '%s'\n",
514                      (*inp)[ii].value, name, defs[0]);
515         n += sprintf(buf+n, "Next time use one of:");
516         j  = 0;
517         while (defs[j])
518         {
519             n += sprintf(buf+n, " '%s'", defs[j]);
520             j++;
521         }
522         if (wi != NULL)
523         {
524             warning_error(wi, buf);
525         }
526         else
527         {
528             fprintf(stderr, "%s\n", buf);
529         }
530
531         (*inp)[ii].value = strdup(defs[0]);
532
533         return 0;
534     }
535
536     return i;
537 }
538
539 int get_eenum(int *ninp, t_inpfile **inp, const char *name, const char **defs)
540 {
541     int dum = 0;
542
543     return get_eeenum(ninp, inp, name, defs, NULL);
544 }