Parameters.h 15.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// ============================================================================
// ==                                                                        ==
// == AMDiS - Adaptive multidimensional simulations                          ==
// ==                                                                        ==
// ============================================================================
// ==                                                                        ==
// ==  crystal growth group                                                  ==
// ==                                                                        ==
// ==  Stiftung caesar                                                       ==
// ==  Ludwig-Erhard-Allee 2                                                 ==
// ==  53175 Bonn                                                            ==
// ==  germany                                                               ==
// ==                                                                        ==
// ============================================================================
// ==                                                                        ==
// ==  http://www.caesar.de/cg/AMDiS                                         ==
// ==                                                                        ==
// ============================================================================

/** \file Parameters.h */

#ifndef AMDIS_PARAMETERS_H
#define AMDIS_PARAMETERS_H

#include <stdio.h>
#include <string>
#include <list>
#include <fstream>
#include "Global.h"
#include "MemoryManager.h"
#include "Serializable.h"

namespace AMDiS {

  // ============================================================================
  // ===== class Parameters =====================================================
  // ============================================================================

  /** \ingroup Common
   * \brief
   * Many procedures need parameters, for example the maximal number of 
   * iterations for an iterative solver, the tolerance for the error in the 
   * adaptive procedure, etc. It is often very helpful to change the values of 
   * these parameters without recompiling the program by initializing them from 
   * a parameter file.
   * In order to avoid a fixed list of parameters, we use the following concept: 
   * Every parameter consists of two strings: a key string by which the parameter
   * is identified, and a second string containing the parameter values. These 
   * values are stored as ASCII-characters and can be converted to int, double, 
   * etc. according to a format specified by the user. Using this concept, 
   * parameters can be accessed at any point of the program.
   * Usually parameters are initialized from parameter files. Each line of the 
   * file describes either a single parameter: the key definition terminated by 
   * a ':' character followed by the parameter values, or specifies another 
   * parameter file to be included at that point (this can also be done 
   * recursively).
   */
  class Parameters : public Serializable
  {
  public:
    MEMORY_MANAGED(Parameters);

    /** \brief
     * Initializes parameters from a file; filename is a string holding the name 
     * of the file and if values of the argument print and the global variable 
     * msg info are not zero, a list of all defined parameters is printed to the 
     * message stream; if init() can not open the input file, no parameter is 
     * defined.
     * One call of this function should be the first executable statement in the 
     * main program. Several calls of init() are possible. If a key is defined 
     * more than once, parameter values from the latest definition are valid. 
     * Parameter values from previous definition(s) are ignored.
     * If flags are set, the file is first processed by the C-preprocessor with 
     * argument flags, replacing macros by their definitions in the parameter 
     * file and including files specified by \#include"...".
     */
    static void init(int         print, 
78
		     std::string filename, 
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
		     const char *flags=NULL);

    /** \brief
     * Reads all arguments which are provided to the program. The init filenames
     * are ignored. The functions search for the following parameters:
     *
     * -rs filename: The program is restarted with the given serialization.
     *
     * All found parameters are added to the global parameter list with the prefix 
     * argv-> (e.g. argv->rs).
     */
    static void readArgv(int argc, char **argv);

    /** \brief
     * Initializes a parameter identified by key with values vpar; if the 
     * parameter already exists, the old values are replaced by the new one; 
     * if fname is not NULL it contains the name of the calling function.
     * file and line specifies source file and line number of the function
     * call. If one uses the macro \ref ADD_PARAMETER these last three arguments
     * are filled automatically.
     *
     * If p is non zero, the parameter list is printed.
     */
    static void addGlobalParameter(int                p,
103
104
				   const std::string  key,
				   const std::string  par, 
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
				   const char        *fname = NULL, 
				   const char        *file  = NULL, 
				   int                line  = 0);

    /** \brief
     * Looks for a parameter which matches the identifying key string key and 
     * converts the values of the corresponding string containing the parameter 
     * values according to the control string format. Pointers to variable(s) of 
     * suitable types are placed in the unnamed argument list (compare the syntax
     * of scanf()). The first argument flag defines the level of information 
     * during the initialization of parameters with a range of 0 to 4: no to full
     * information. The return value is the number of successfully matched and 
     * assigned input items.
     * If there is no parameter key matching key, getGlobalParameter() returns 
     * without an initialization. The return value is zero. It will also return 
     * without an initialization and return value zero if no parameter has been 
     * defined by init parameters().
     * In the case that a parameter matching the key is found, 
     * getGlobalParameter() acts like a simplified version of sscanf(). The input
     * string is the string containing the parameter values. The function reads 
     * characters from this string, interprets them according to a format, and 
     * stores the results in its arguments. It expects, as arguments, a control 
     * string, format (described below) and a set of pointer arguments indicating
     *  where the converted input should be stored. If there are insufficient 
     * arguments for the format, the behavior is undefined. If the format is 
     * exhausted while arguments remain, the excess arguments are simply ignored.
     * The return value is the number of converted arguments.
     *
     * The control string must only contain the following characters used as 
     * conversion specification: \%s, \%c, \%d, \%e, \%f, \%g, \%U, \%S, or \%*. 
     * All other characters are ignored. In contrast to scanf(), a numerical 
     * value for a field width is not allowed. For each element of the control 
     * string the next word of the parameter string is converted as follows:
     * 
     * -\%s: a character string is expected; the corresponding argument should 
     *       be a character pointer pointing to an array of characters large 
     *       enough to accept the string and a terminating `\0', which will be 
     *       added automatically; the string is one single word of the parameter 
     *       string; as mentioned above strings enclosed in single or double 
     *       quotes are not supported at the moment;
     *
     * -\%c: matches a single character; the corresponding argument should be a 
     *       pointer to a char variable; if the corresponding word of the 
     *       parameter string consists of more than one character, the rest of 
     *       the word is ignored; no space character is possible as argument;
     *
     * -\%d: matches an decimal integer, whose format is the same as expected for
     *       the subject sequence of the atoi() function; the corresponding 
     *       argument should be a pointer to an int variable;
     *
     * -\%e,%f,%g: matches an optionally signed floating point number, whose 
     *       format is the same as expected for the subject string of the atof()
     *       function; the corresponding argument should be a pointer to a double
     *       variable;
     *
     * -\%U: matches an unsigned decimal integer in the range [0,255], whose 
     *       format is the same as expected for the subject sequence of the 
     *       atoi() function; the corresponding argument should be a pointer to 
     *       an unsigned char variable;
     *
     * -\%S: matches an optionally signed decimal integer in the range 
     *       [-128,127], whose format is the same as expected for the subject 
     *       sequence of the atoi() function; the corresponding argument should 
     *       be a pointer to an signed char variable;
     *
     * -\%*: next word of parameter string should be skipped; there must not be
     *       a corresponding argument.
     *
     * getGlobalParameter() will always finish its work, successfully or not. 
     * It may fail if a misspelled key is handed over or there are not so many 
     * parameter values as format specifiers (the remaining variables are not 
     * initialized!). If flag is zero, getGlobalParameter() works silently; no 
     * error message is produced. Otherwise the key and the initialized values 
     * and error messages are printed. The second way to influence messages 
     * produced by get parameter() namely by is a parameter parameter information
     * specified in a parameter file.
     * \see GET_PARAMETER
     */
    static int getGlobalParameter(int                 flag,
184
				  const std::string&  key,
185
186
187
188
189
190
191
				  const char         *format, 
				  ...);  

    /** \brief
     * Like getGlobalParameter(flag, key, "%s", param->c_str()).
     */
    static int getGlobalParameter(int                 flag, 
192
193
				  const std::string&  key, 
				  std::string        *param);
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223

    /** \brief
     * Prints all defined parameters to the message stream
     */
    static void printParameters();

    /** \brief
     * Used by macro \ref GET_PARAMETER to generate infos about the calling
     * function.
     */
    static int initFuncName(const char *, 
			    const char *, 
			    int call_line);

    /** \brief
     * Returns specified info level
     */
    static int getMsgInfo() { return (singlett)?singlett->msgInfo:0; };

    /** \brief
     * Returns specified wait value
     */
    static int getMsgWait() { return (singlett)?singlett->msgWait:0; };

    /** \brief
     * Writes all up to now initialized parameters to file according to the 
     * parameter file format; if the value of info is different from zero, the 
     * location of the initialization is supplied for each parameter as a 
     * comment; no original comment is written, since these are not stored.
     */
224
    static void save(const std::string file, int info);
225
226
227
228

    /** \brief
     * Checks whether parameters are initialized. if not, call init()
     */
229
230
231
    static bool initialized() { 
      return (singlett != NULL); 
    };
232

233
234
235
    static Parameters *getSingleton() { 
      return singlett; 
    };
236
237
238

    // ===== Serializable implementation =====

239
    void serialize(std::ostream &out) {
240
241
242
243
244
245
246
247
248
249
      out.write(reinterpret_cast<const char*>(&paramInfo), sizeof(int));
      out.write(reinterpret_cast<const char*>(&msgInfo), sizeof(int));
      out.write(reinterpret_cast<const char*>(&msgWait), sizeof(int));
      int i, size = static_cast<int>(allParam.size());
      out.write(reinterpret_cast<const char*>(&size), sizeof(int));
      for(i = 0; i < size; i++) {
	allParam[i].serialize(out);
      }
    };

250
    void deserialize(std::istream &in) {
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
      in.read(reinterpret_cast<char*>(&paramInfo), sizeof(int));
      in.read(reinterpret_cast<char*>(&msgInfo), sizeof(int));
      in.read(reinterpret_cast<char*>(&msgWait), sizeof(int));
      int i, size;
      in.read(reinterpret_cast<char*>(&size), sizeof(int));
      allParam.resize(size);
      for(i = 0; i < size; i++) {
	allParam[i].deserialize(in);
      }
    };

  private:
    static Parameters * singlett;

    static const char *param_call_fct;

    static const char *param_call_file;

    static int param_call_line;


    /** \brief
     * Used internally.
     */
    class param : public Serializable
    {
    public:
      param() {};

      virtual ~param() {};

282
283
284
285
      param(const std::string& nkey,
	    const std::string& nparameters, 
	    const std::string& nfilename,
	    const std::string& nfuncName, 
286
287
288
289
290
291
292
293
	    int                line) 
	: key(nkey),
	  parameters(nparameters),
	  filename(nfilename),
	  funcName(nfuncName),
	  lineNo(line) 
      {};

294
      param(const std::string& k): key(k) {};
295
296
297
298
299
300
301
302
303

      int operator==(const class param& aParam) const;

      int operator!=(const class param& aParam) const {
	return !(aParam==*this);
      };

      // ===== Serializable implementation =====

304
305
306
307
308
      void serialize(std::ostream &out) {
	out << key << std::endl;
	out << parameters << std::endl;
	out << filename << std::endl;
	out << funcName << std::endl;
309
310
311
	out.write(reinterpret_cast<const char*>(&lineNo), sizeof(int));
      };

312
      void deserialize(std::istream &in) {
313
314
315
316
317
318
319
320
	in >> key; in.get();
	in >> parameters; in.get();
	in >> filename; in.get();
	in >> funcName; in.get();
	in.read(reinterpret_cast<char*>(&lineNo), sizeof(int));
      };

    public:
321
322
323
324
      std::string key;
      std::string parameters;
      std::string filename;
      std::string funcName;
325
326
327
328
329
      int         lineNo;
    };

    static const char comment;

330
    std::string buffer;
331
332

    inline bool isBlankChar(const char s) {return (s==' '||s=='\t'||s =='\f'||s=='\r'); };
333
    const char *getNextWord(std::string *s) const;
334

335
    void read(const std::string& filename,const std::string& maxKey="");
336

337
    const std::string& getActFile(const std::string& filename);
338

339
    const std::string getKey(const std::string& s, 
340
			       int nLine, 
341
			       const std::string& filename);
342

343
344
    const std::string getPar(const std::string& key, 
			       const std::string& s, 
345
			       int *nl, 
346
			       const std::string& fn);
347

348
349
350
    void addParam(const std::string& key, 
		  const std::string& parameter,
		  const std::string& actfile, 
351
		  int  nLine, 
352
		  const std::string& fname);
353

354
355
356
357
358
    Parameters() 
      : paramInfo(1),
        msgInfo(1),
        msgWait(1)     
    {};
359
360
361
362
363

    virtual ~Parameters() {};  

    static void initIntern();

364
    int binSearch(const std::string& key, int n_keys);
365
366
367
368
369
370

    void swap(int i, int j);

    void qsort(int left, int right);

  private:
371
372
373
    std::string cppFlags;
    std::ifstream inputFile;
    std::list< std::string> filenames;
374
    size_t maxFiles;
375
    std::string filename;
376
377
378
    int paramInfo;
    int msgInfo;
    int msgWait;
379
    std::vector<param> allParam;
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
 
  };


  /** \brief
   * Acts as add parameter(flag, key, value) but the function is additionally 
   * supplied with the name of the calling function, source file and line, which
   * results in more detailed messages during parameter definition.
   */
#define ADD_PARAMETER(p, key, param)					\
  Parameters::addGlobalParameter(p, key, param, funcName, __FILE__, __LINE__);

  /** \brief
   * Is a macro and acts in the same way as the function 
   * getGlobalParameter() but the function is additionally supplied with the 
   * name of the calling function, source file and line, which results in more 
   * detailed messages during parameter definition.
   */
#define GET_PARAMETER						\
  Parameters::initFuncName(funcName, __FILE__, __LINE__);	\
    Parameters::getGlobalParameter

}

#endif // AMDIS_PARAMETERS_H