2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2013,2014,2015,2016, 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.
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.
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.
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.
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.
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.
47 #include "gromacs/fileio/gmxfio.h"
48 #include "gromacs/fileio/warninp.h"
49 #include "gromacs/utility/binaryinformation.h"
50 #include "gromacs/utility/cstringutil.h"
51 #include "gromacs/utility/exceptions.h"
52 #include "gromacs/utility/fatalerror.h"
53 #include "gromacs/utility/futil.h"
54 #include "gromacs/utility/keyvaluetreebuilder.h"
55 #include "gromacs/utility/programcontext.h"
56 #include "gromacs/utility/qsort_threadsafe.h"
57 #include "gromacs/utility/smalloc.h"
59 t_inpfile
*read_inpfile(const char *fn
, int *ninp
,
63 char buf
[STRLEN
], lbuf
[STRLEN
], rbuf
[STRLEN
], warn_buf
[STRLEN
];
65 t_inpfile
*inp
= NULL
;
71 fprintf(debug
, "Reading MDP file %s\n", fn
);
74 in
= gmx_ffopen(fn
, "r");
79 ptr
= fgets2(buf
, STRLEN
-1, in
);
81 set_warning_line(wi
, fn
, lc
);
84 // TODO This parsing should be using strip_comment, trim,
85 // strchr, etc. rather than re-inventing wheels.
88 if ((cptr
= std::strchr(buf
, COMMENTSIGN
)) != NULL
)
95 for (j
= 0; (buf
[j
] != '=') && (buf
[j
] != '\0'); j
++)
105 fprintf(debug
, "No = on line %d in file %s, ignored\n", lc
, fn
);
111 for (i
= 0; (i
< j
); i
++)
121 fprintf(debug
, "Empty left hand side on line %d in file %s, ignored\n", lc
, fn
);
126 for (i
= j
+1, k
= 0; (buf
[i
] != '\0'); i
++, k
++)
136 fprintf(debug
, "Empty right hand side on line %d in file %s, ignored\n", lc
, fn
);
141 /* Now finally something sensible; check for duplicates */
142 int found_index
= search_einp(nin
, inp
, lbuf
);
144 if (found_index
== -1)
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
= gmx_strdup(lbuf
);
153 inp
[nin
-1].value
= gmx_strdup(rbuf
);
158 "Parameter \"%s\" doubly defined\n",
160 warning_error(wi
, warn_buf
);
173 fprintf(debug
, "Done reading MDP file, there were %d entries in there\n",
182 gmx::KeyValueTreeObject
flatKeyValueTreeFromInpFile(int ninp
, t_inpfile inp
[])
184 gmx::KeyValueTreeBuilder builder
;
185 auto root
= builder
.rootObject();
186 for (int i
= 0; i
< ninp
; ++i
)
188 const char *value
= inp
[i
].value
;
189 root
.addValue
<std::string
>(inp
[i
].name
, value
!= nullptr ? value
: "");
191 return builder
.build();
195 static int inp_comp(const void *a
, const void *b
)
197 return (reinterpret_cast<const t_inpfile
*>(a
))->count
- (reinterpret_cast<const t_inpfile
*>(b
))->count
;
200 static void sort_inp(int ninp
, t_inpfile inp
[])
205 for (i
= 0; (i
< ninp
); i
++)
207 mm
= std::max(mm
, inp
[i
].count
);
209 for (i
= 0; (i
< ninp
); i
++)
211 if (inp
[i
].count
== 0)
216 gmx_qsort(inp
, ninp
, static_cast<size_t>(sizeof(inp
[0])), inp_comp
);
219 void write_inpfile(const char *fn
, int ninp
, t_inpfile inp
[], gmx_bool bHaltOnUnknown
,
224 char warn_buf
[STRLEN
];
227 out
= gmx_fio_fopen(fn
, "w");
228 nice_header(out
, fn
);
231 gmx::BinaryInformationSettings settings
;
232 settings
.generatedByHeader(true);
233 settings
.linePrefix(";\t");
234 gmx::printBinaryInformation(out
, gmx::getProgramContext(), settings
);
236 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
;
238 for (i
= 0; (i
< ninp
); i
++)
242 if (inp
[i
].name
[0] == ';' || (strlen(inp
[i
].name
) > 2 && inp
[i
].name
[1] == ';'))
244 fprintf(out
, "%-24s\n", inp
[i
].name
);
248 fprintf(out
, "%-24s = %s\n", inp
[i
].name
, inp
[i
].value
? inp
[i
].value
: "");
251 else if (!inp
[i
].bObsolete
)
253 sprintf(warn_buf
, "Unknown left-hand '%s' in parameter file\n",
257 warning_error(wi
, warn_buf
);
261 warning(wi
, warn_buf
);
267 check_warning_error(wi
, FARGS
);
270 void replace_inp_entry(int ninp
, t_inpfile
*inp
, const char *old_entry
, const char *new_entry
)
274 for (i
= 0; (i
< ninp
); i
++)
276 if (gmx_strcasecmp_min(old_entry
, inp
[i
].name
) == 0)
280 fprintf(stderr
, "Replacing old mdp entry '%s' by '%s'\n",
281 inp
[i
].name
, new_entry
);
283 inp
[i
].name
= gmx_strdup(new_entry
);
287 fprintf(stderr
, "Ignoring obsolete mdp entry '%s'\n",
289 inp
[i
].bObsolete
= TRUE
;
295 int search_einp(int ninp
, const t_inpfile
*inp
, const char *name
)
303 for (i
= 0; i
< ninp
; i
++)
305 if (gmx_strcasecmp_min(name
, inp
[i
].name
) == 0)
313 void mark_einp_set(int ninp
, t_inpfile
*inp
, const char *name
)
315 int i
= search_einp(ninp
, inp
, name
);
318 inp
[i
].count
= inp
[0].inp_count
++;
323 static int get_einp(int *ninp
, t_inpfile
**inp
, const char *name
)
326 int notfound
= FALSE
;
328 i
= search_einp(*ninp
, *inp
, name
);
333 srenew(*inp
, (*ninp
));
334 (*inp
)[i
].name
= gmx_strdup(name
);
335 (*inp
)[i
].bSet
= TRUE
;
337 (*inp
)[i
].count
= (*inp
)[0].inp_count
++;
338 (*inp
)[i
].bSet
= TRUE
;
341 fprintf(debug
, "Inp %d = %s\n", (*inp
)[i
].count
, (*inp
)[i
].name
);
344 /*if (i == (*ninp)-1)*/
355 /* Note that sanitizing the trailing part of (*inp)[ii].value was the responsibility of read_inpfile() */
356 int get_eint(int *ninp
, t_inpfile
**inp
, const char *name
, int def
,
359 char buf
[32], *ptr
, warn_buf
[STRLEN
];
363 ii
= get_einp(ninp
, inp
, name
);
367 sprintf(buf
, "%d", def
);
368 (*inp
)[(*ninp
)-1].value
= gmx_strdup(buf
);
374 ret
= std::strtol((*inp
)[ii
].value
, &ptr
, 10);
377 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
);
378 warning_error(wi
, warn_buf
);
385 /* Note that sanitizing the trailing part of (*inp)[ii].value was the responsibility of read_inpfile() */
386 gmx_int64_t
get_eint64(int *ninp
, t_inpfile
**inp
,
387 const char *name
, gmx_int64_t def
,
390 char buf
[32], *ptr
, warn_buf
[STRLEN
];
394 ii
= get_einp(ninp
, inp
, name
);
398 sprintf(buf
, "%" GMX_PRId64
, def
);
399 (*inp
)[(*ninp
)-1].value
= gmx_strdup(buf
);
405 ret
= str_to_int64_t((*inp
)[ii
].value
, &ptr
);
408 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
);
409 warning_error(wi
, warn_buf
);
416 /* Note that sanitizing the trailing part of (*inp)[ii].value was the responsibility of read_inpfile() */
417 double get_ereal(int *ninp
, t_inpfile
**inp
, const char *name
, double def
,
420 char buf
[32], *ptr
, warn_buf
[STRLEN
];
424 ii
= get_einp(ninp
, inp
, name
);
428 sprintf(buf
, "%g", def
);
429 (*inp
)[(*ninp
)-1].value
= gmx_strdup(buf
);
435 ret
= strtod((*inp
)[ii
].value
, &ptr
);
438 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
);
439 warning_error(wi
, warn_buf
);
446 /* Note that sanitizing the trailing part of (*inp)[ii].value was the responsibility of read_inpfile() */
447 const char *get_estr(int *ninp
, t_inpfile
**inp
, const char *name
, const char *def
)
452 ii
= get_einp(ninp
, inp
, name
);
458 sprintf(buf
, "%s", def
);
459 (*inp
)[(*ninp
)-1].value
= gmx_strdup(buf
);
463 (*inp
)[(*ninp
)-1].value
= NULL
;
470 return (*inp
)[ii
].value
;
474 /* Note that sanitizing the trailing part of (*inp)[ii].value was the responsibility of read_inpfile() */
475 int get_eeenum(int *ninp
, t_inpfile
**inp
, const char *name
, const char **defs
,
482 ii
= get_einp(ninp
, inp
, name
);
486 (*inp
)[(*ninp
)-1].value
= gmx_strdup(defs
[0]);
491 for (i
= 0; (defs
[i
] != NULL
); i
++)
493 if (gmx_strcasecmp_min(defs
[i
], (*inp
)[ii
].value
) == 0)
501 n
+= sprintf(buf
, "Invalid enum '%s' for variable %s, using '%s'\n",
502 (*inp
)[ii
].value
, name
, defs
[0]);
503 n
+= sprintf(buf
+n
, "Next time use one of:");
507 n
+= sprintf(buf
+n
, " '%s'", defs
[j
]);
512 warning_error(wi
, buf
);
516 fprintf(stderr
, "%s\n", buf
);
519 (*inp
)[ii
].value
= gmx_strdup(defs
[0]);
527 int get_eenum(int *ninp
, t_inpfile
**inp
, const char *name
, const char **defs
)
529 return get_eeenum(ninp
, inp
, name
, defs
, NULL
);