ff55b9dc7b26d315d682dc1ffa4dea1117e3ba86
[alexxy/gromacs.git] / src / gromacs / gmxlib / readinp.c
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team.
6  * Copyright (c) 2013,2014, by the GROMACS development team, led by
7  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8  * and including many others, as listed in the AUTHORS file in the
9  * top-level source directory and at http://www.gromacs.org.
10  *
11  * GROMACS is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public License
13  * as published by the Free Software Foundation; either version 2.1
14  * of the License, or (at your option) any later version.
15  *
16  * GROMACS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with GROMACS; if not, see
23  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
25  *
26  * If you want to redistribute modifications to GROMACS, please
27  * consider that scientific software is very special. Version
28  * control is crucial - bugs must be traceable. We will be happy to
29  * consider code for inclusion in the official distribution, but
30  * derived work must not be called official GROMACS. Details are found
31  * in the README & COPYING files - if they are missing, get the
32  * official version at http://www.gromacs.org.
33  *
34  * To help us fund GROMACS development, we humbly ask that you cite
35  * the research papers on the package. Check out http://www.gromacs.org.
36  */
37 #include "gmxpre.h"
38
39 #include "config.h"
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include "gromacs/legacyheaders/typedefs.h"
44 #include "gromacs/utility/cstringutil.h"
45 #include "gromacs/utility/futil.h"
46 #include "gromacs/utility/smalloc.h"
47 #include "gromacs/legacyheaders/readinp.h"
48 #include "gromacs/legacyheaders/macros.h"
49 #include "gromacs/fileio/gmxfio.h"
50 #include "gromacs/legacyheaders/names.h"
51 #include "gromacs/legacyheaders/warninp.h"
52 #include "gromacs/utility/fatalerror.h"
53
54 t_inpfile *read_inpfile(const char *fn, int *ninp,
55                         warninp_t wi)
56 {
57     FILE      *in;
58     char       buf[STRLEN], lbuf[STRLEN], rbuf[STRLEN], warn_buf[STRLEN];
59     char      *ptr, *cptr;
60     t_inpfile *inp = NULL;
61     int        nin, lc, i, j, k;
62     /* setting cppopts from command-line options would be cooler */
63     gmx_bool   allow_override = FALSE;
64
65
66     if (debug)
67     {
68         fprintf(debug, "Reading MDP file %s\n", fn);
69     }
70
71     in = gmx_ffopen(fn, "r");
72
73     nin = lc  = 0;
74     do
75     {
76         ptr = fgets2(buf, STRLEN-1, in);
77         lc++;
78         set_warning_line(wi, fn, lc);
79         if (ptr)
80         {
81             /* Strip comment */
82             if ((cptr = strchr(buf, COMMENTSIGN)) != NULL)
83             {
84                 *cptr = '\0';
85             }
86             /* Strip spaces */
87             trim(buf);
88
89             for (j = 0; (buf[j] != '=') && (buf[j] != '\0'); j++)
90             {
91                 ;
92             }
93             if (buf[j] == '\0')
94             {
95                 if (j > 0)
96                 {
97                     if (debug)
98                     {
99                         fprintf(debug, "No = on line %d in file %s, ignored\n", lc, fn);
100                     }
101                 }
102             }
103             else
104             {
105                 for (i = 0; (i < j); i++)
106                 {
107                     lbuf[i] = buf[i];
108                 }
109                 lbuf[i] = '\0';
110                 trim(lbuf);
111                 if (lbuf[0] == '\0')
112                 {
113                     if (debug)
114                     {
115                         fprintf(debug, "Empty left hand side on line %d in file %s, ignored\n", lc, fn);
116                     }
117                 }
118                 else
119                 {
120                     for (i = j+1, k = 0; (buf[i] != '\0'); i++, k++)
121                     {
122                         rbuf[k] = buf[i];
123                     }
124                     rbuf[k] = '\0';
125                     trim(rbuf);
126                     if (rbuf[0] == '\0')
127                     {
128                         if (debug)
129                         {
130                             fprintf(debug, "Empty right hand side on line %d in file %s, ignored\n", lc, fn);
131                         }
132                     }
133                     else
134                     {
135                         /* Now finally something sensible */
136                         int found_index;
137
138                         /* first check whether we hit the 'multiple_entries' option */
139                         if (gmx_strcasecmp_min(eMultentOpt_names[eMultentOptName], lbuf) == 0)
140                         {
141                             /* we now check whether to allow overrides from here or not */
142                             if (gmx_strcasecmp_min(eMultentOpt_names[eMultentOptNo], rbuf) == 0)
143                             {
144                                 allow_override = FALSE;
145                             }
146                             else if (gmx_strcasecmp_min(eMultentOpt_names[eMultentOptLast], rbuf) == 0)
147                             {
148                                 allow_override = TRUE;
149                             }
150                             else
151                             {
152                                 sprintf(warn_buf,
153                                         "Parameter \"%s\" should either be %s or %s\n",
154                                         lbuf,
155                                         eMultentOpt_names[eMultentOptNo],
156                                         eMultentOpt_names[eMultentOptLast]);
157                                 warning_error(wi, warn_buf);
158                             }
159                         }
160                         else
161                         {
162                             /* it is a regular option; check for duplicates */
163                             found_index = search_einp(nin, inp, lbuf);
164
165                             if (found_index == -1)
166                             {
167                                 /* add a new item */
168                                 srenew(inp, ++nin);
169                                 inp[nin-1].inp_count  = 1;
170                                 inp[nin-1].count      = 0;
171                                 inp[nin-1].bObsolete  = FALSE;
172                                 inp[nin-1].bSet       = FALSE;
173                                 inp[nin-1].name       = gmx_strdup(lbuf);
174                                 inp[nin-1].value      = gmx_strdup(rbuf);
175                             }
176                             else
177                             {
178                                 if (!allow_override)
179                                 {
180                                     sprintf(warn_buf,
181                                             "Parameter \"%s\" doubly defined (and multiple assignments not allowed)\n",
182                                             lbuf);
183                                     warning_error(wi, warn_buf);
184                                 }
185                                 else
186                                 {
187                                     /* override */
188                                     sfree(inp[found_index].value);
189                                     inp[found_index].value = gmx_strdup(rbuf);
190                                     sprintf(warn_buf,
191                                             "Overriding existing parameter \"%s\" with value \"%s\"\n",
192                                             lbuf, rbuf);
193                                     warning_note(wi, warn_buf);
194                                 }
195                             }
196                         }
197                     }
198                 }
199             }
200         }
201     }
202     while (ptr);
203
204     gmx_ffclose(in);
205
206     if (debug)
207     {
208         fprintf(debug, "Done reading MDP file, there were %d entries in there\n",
209                 nin);
210     }
211
212     *ninp = nin;
213
214     return inp;
215 }
216
217
218
219
220 static int inp_comp(const void *a, const void *b)
221 {
222     return ((t_inpfile *)a)->count - ((t_inpfile *)b)->count;
223 }
224
225 static void sort_inp(int ninp, t_inpfile inp[])
226 {
227     int i, mm;
228
229     mm = -1;
230     for (i = 0; (i < ninp); i++)
231     {
232         mm = max(mm, inp[i].count);
233     }
234     for (i = 0; (i < ninp); i++)
235     {
236         if (inp[i].count == 0)
237         {
238             inp[i].count = mm++;
239         }
240     }
241     qsort(inp, ninp, (size_t)sizeof(inp[0]), inp_comp);
242 }
243
244 void write_inpfile(const char *fn, int ninp, t_inpfile inp[], gmx_bool bHaltOnUnknown,
245                    warninp_t wi)
246 {
247     FILE *out;
248     int   i;
249     char  warn_buf[STRLEN];
250
251     sort_inp(ninp, inp);
252     out = gmx_fio_fopen(fn, "w");
253     nice_header(out, fn);
254     for (i = 0; (i < ninp); i++)
255     {
256         if (inp[i].bSet)
257         {
258             if (inp[i].name[0] == ';' || (strlen(inp[i].name) > 2 && inp[i].name[1] == ';'))
259             {
260                 fprintf(out, "%-24s\n", inp[i].name);
261             }
262             else
263             {
264                 fprintf(out, "%-24s = %s\n", inp[i].name, inp[i].value ? inp[i].value : "");
265             }
266         }
267         else if (!inp[i].bObsolete)
268         {
269             sprintf(warn_buf, "Unknown left-hand '%s' in parameter file\n",
270                     inp[i].name);
271             if (bHaltOnUnknown)
272             {
273                 warning_error(wi, warn_buf);
274             }
275             else
276             {
277                 warning(wi, warn_buf);
278             }
279         }
280     }
281     gmx_fio_fclose(out);
282
283     check_warning_error(wi, FARGS);
284 }
285
286 void replace_inp_entry(int ninp, t_inpfile *inp, const char *old_entry, const char *new_entry)
287 {
288     int  i;
289
290     for (i = 0; (i < ninp); i++)
291     {
292         if (gmx_strcasecmp_min(old_entry, inp[i].name) == 0)
293         {
294             if (new_entry)
295             {
296                 fprintf(stderr, "Replacing old mdp entry '%s' by '%s'\n",
297                         inp[i].name, new_entry);
298                 sfree(inp[i].name);
299                 inp[i].name = gmx_strdup(new_entry);
300             }
301             else
302             {
303                 fprintf(stderr, "Ignoring obsolete mdp entry '%s'\n",
304                         inp[i].name);
305                 inp[i].bObsolete = TRUE;
306             }
307         }
308     }
309 }
310
311 int search_einp(int ninp, const t_inpfile *inp, const char *name)
312 {
313     int i;
314
315     if (inp == NULL)
316     {
317         return -1;
318     }
319     for (i = 0; i < ninp; i++)
320     {
321         if (gmx_strcasecmp_min(name, inp[i].name) == 0)
322         {
323             return i;
324         }
325     }
326     return -1;
327 }
328
329 static int get_einp(int *ninp, t_inpfile **inp, const char *name)
330 {
331     int    i;
332     int    notfound = FALSE;
333     char   warn_buf[STRLEN];
334
335 /*  if (inp==NULL)
336     return -1;
337    for(i=0; (i<(*ninp)); i++)
338     if (gmx_strcasecmp_min(name,(*inp)[i].name) == 0)
339       break;
340    if (i == (*ninp)) {*/
341     i = search_einp(*ninp, *inp, name);
342     if (i == -1)
343     {
344         notfound = TRUE;
345         i        = (*ninp)++;
346         srenew(*inp, (*ninp));
347         (*inp)[i].name = gmx_strdup(name);
348         (*inp)[i].bSet = TRUE;
349     }
350     (*inp)[i].count = (*inp)[0].inp_count++;
351     (*inp)[i].bSet  = TRUE;
352     if (debug)
353     {
354         fprintf(debug, "Inp %d = %s\n", (*inp)[i].count, (*inp)[i].name);
355     }
356
357     /*if (i == (*ninp)-1)*/
358     if (notfound)
359     {
360         return -1;
361     }
362     else
363     {
364         return i;
365     }
366 }
367
368 int get_eint(int *ninp, t_inpfile **inp, const char *name, int def,
369              warninp_t wi)
370 {
371     char buf[32], *ptr, warn_buf[STRLEN];
372     int  ii;
373     int  ret;
374
375     ii = get_einp(ninp, inp, name);
376
377     if (ii == -1)
378     {
379         sprintf(buf, "%d", def);
380         (*inp)[(*ninp)-1].value = gmx_strdup(buf);
381
382         return def;
383     }
384     else
385     {
386         ret = strtol((*inp)[ii].value, &ptr, 10);
387         if (ptr == (*inp)[ii].value)
388         {
389             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);
390             warning_error(wi, warn_buf);
391         }
392
393         return ret;
394     }
395 }
396
397 gmx_int64_t get_eint64(int *ninp, t_inpfile **inp,
398                        const char *name, gmx_int64_t def,
399                        warninp_t wi)
400 {
401     char            buf[32], *ptr, warn_buf[STRLEN];
402     int             ii;
403     gmx_int64_t     ret;
404
405     ii = get_einp(ninp, inp, name);
406
407     if (ii == -1)
408     {
409         sprintf(buf, "%"GMX_PRId64, def);
410         (*inp)[(*ninp)-1].value = gmx_strdup(buf);
411
412         return def;
413     }
414     else
415     {
416         ret = str_to_int64_t((*inp)[ii].value, &ptr);
417         if (ptr == (*inp)[ii].value)
418         {
419             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);
420             warning_error(wi, warn_buf);
421         }
422
423         return ret;
424     }
425 }
426
427 double get_ereal(int *ninp, t_inpfile **inp, const char *name, double def,
428                  warninp_t wi)
429 {
430     char   buf[32], *ptr, warn_buf[STRLEN];
431     int    ii;
432     double ret;
433
434     ii = get_einp(ninp, inp, name);
435
436     if (ii == -1)
437     {
438         sprintf(buf, "%g", def);
439         (*inp)[(*ninp)-1].value = gmx_strdup(buf);
440
441         return def;
442     }
443     else
444     {
445         ret = strtod((*inp)[ii].value, &ptr);
446         if (ptr == (*inp)[ii].value)
447         {
448             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);
449             warning_error(wi, warn_buf);
450         }
451
452         return ret;
453     }
454 }
455
456 const char *get_estr(int *ninp, t_inpfile **inp, const char *name, const char *def)
457 {
458     char buf[32];
459     int  ii;
460
461     ii = get_einp(ninp, inp, name);
462
463     if (ii == -1)
464     {
465         if (def)
466         {
467             sprintf(buf, "%s", def);
468             (*inp)[(*ninp)-1].value = gmx_strdup(buf);
469         }
470         else
471         {
472             (*inp)[(*ninp)-1].value = NULL;
473         }
474
475         return def;
476     }
477     else
478     {
479         return (*inp)[ii].value;
480     }
481 }
482
483 int get_eeenum(int *ninp, t_inpfile **inp, const char *name, const char **defs,
484                warninp_t wi)
485 {
486     int  ii, i, j;
487     int  n = 0;
488     char buf[STRLEN];
489
490     ii = get_einp(ninp, inp, name);
491
492     if (ii == -1)
493     {
494         (*inp)[(*ninp)-1].value = gmx_strdup(defs[0]);
495
496         return 0;
497     }
498
499     for (i = 0; (defs[i] != NULL); i++)
500     {
501         if (gmx_strcasecmp_min(defs[i], (*inp)[ii].value) == 0)
502         {
503             break;
504         }
505     }
506
507     if (defs[i] == NULL)
508     {
509         n += sprintf(buf, "Invalid enum '%s' for variable %s, using '%s'\n",
510                      (*inp)[ii].value, name, defs[0]);
511         n += sprintf(buf+n, "Next time use one of:");
512         j  = 0;
513         while (defs[j])
514         {
515             n += sprintf(buf+n, " '%s'", defs[j]);
516             j++;
517         }
518         if (wi != NULL)
519         {
520             warning_error(wi, buf);
521         }
522         else
523         {
524             fprintf(stderr, "%s\n", buf);
525         }
526
527         (*inp)[ii].value = gmx_strdup(defs[0]);
528
529         return 0;
530     }
531
532     return i;
533 }
534
535 int get_eenum(int *ninp, t_inpfile **inp, const char *name, const char **defs)
536 {
537     int dum = 0;
538
539     return get_eeenum(ninp, inp, name, defs, NULL);
540 }