Parameters.h 14.2 KB
Newer Older
1 2 3 4 5 6
// ============================================================================
// ==                                                                        ==
// == AMDiS - Adaptive multidimensional simulations                          ==
// ==                                                                        ==
// ============================================================================
// ==                                                                        ==
7
// ==  TU Dresden                                                            ==
8
// ==                                                                        ==
9 10 11
// ==  Institut für Wissenschaftliches Rechnen                               ==
// ==  Zellescher Weg 12-14                                                  ==
// ==  01069 Dresden                                                         ==
12 13 14 15
// ==  germany                                                               ==
// ==                                                                        ==
// ============================================================================
// ==                                                                        ==
16
// ==  https://gforge.zih.tu-dresden.de/projects/amdis/                      ==
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
// ==                                                                        ==
// ============================================================================

/** \file Parameters.h */

#ifndef AMDIS_PARAMETERS_H
#define AMDIS_PARAMETERS_H

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

namespace AMDiS {

  /** \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:
    /** \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"...".
     */
Thomas Witkowski's avatar
Thomas Witkowski committed
70
    static void init(int print, std::string filename, const char *flags = NULL);
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93

    /** \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,
94 95
				   const std::string  key,
				   const std::string  par, 
96 97 98 99 100 101 102 103 104 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
				   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
     */
174 175 176
    static int getGlobalParameter(int flag,
				  const std::string& key,
				  const char *format, 
177 178
				  ...);  

Thomas Witkowski's avatar
Thomas Witkowski committed
179 180
    /// Like getGlobalParameter(flag, key, "%s", param->c_str()).
    static int getGlobalParameter(int flag, const std::string& key, std::string *param);
181

Thomas Witkowski's avatar
Thomas Witkowski committed
182
    /// Prints all defined parameters to the message stream
183 184
    static void printParameters();

Thomas Witkowski's avatar
Thomas Witkowski committed
185 186
    /// Used by macro \ref GET_PARAMETER to generate infos about the calling function.
    static int initFuncName(const char *, const char *, int call_line);
187

Thomas Witkowski's avatar
Thomas Witkowski committed
188 189 190
    /// Returns specified info level
    static int getMsgInfo() 
    { 
191 192
      return (singlett) ? singlett->msgInfo : 0; 
    }
193

Thomas Witkowski's avatar
Thomas Witkowski committed
194 195 196
    /// Returns specified wait value
    static int getMsgWait() 
    { 
197 198
      return (singlett) ? singlett->msgWait : 0; 
    }
199 200 201 202 203 204 205

    /** \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.
     */
206
    static void save(const std::string file, int info);
207

Thomas Witkowski's avatar
Thomas Witkowski committed
208 209 210
    /// Checks whether parameters are initialized. if not, call init()
    static bool initialized() 
    { 
211
      return (singlett != NULL); 
212
    }
213

Thomas Witkowski's avatar
Thomas Witkowski committed
214 215
    static Parameters *getSingleton() 
    { 
216
      return singlett; 
217 218 219
    }

    static void clear();
220

Thomas Witkowski's avatar
Thomas Witkowski committed
221 222
    /// Writes parameters to an output stream.
    void serialize(std::ostream &out); 
223

Thomas Witkowski's avatar
Thomas Witkowski committed
224 225
    /// Reads parameters from an input stream.
    void deserialize(std::istream &in); 
226 227 228 229 230 231 232 233 234 235

  private:
    static Parameters * singlett;

    static const char *param_call_fct;

    static const char *param_call_file;

    static int param_call_line;

Thomas Witkowski's avatar
Thomas Witkowski committed
236
    /// Used internally.
237 238 239
    class param : public Serializable
    {
    public:
240
      param() {}
241

242
      virtual ~param() {}
243

244 245 246 247
      param(const std::string& nkey,
	    const std::string& nparameters, 
	    const std::string& nfilename,
	    const std::string& nfuncName, 
248
	    int line) 
249 250 251 252 253
	: key(nkey),
	  parameters(nparameters),
	  filename(nfilename),
	  funcName(nfuncName),
	  lineNo(line) 
254
      {}
255

256 257 258
      param(const std::string& k) 
        : key(k) 
      {}
259 260 261

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

Thomas Witkowski's avatar
Thomas Witkowski committed
262 263 264
      int operator!=(const class param& aParam) const 
      {
	return !(aParam == *this);
265
      }
266

Thomas Witkowski's avatar
Thomas Witkowski committed
267 268
      /// Writes one parameter to an output stream.
      void serialize(std::ostream &out); 
269

Thomas Witkowski's avatar
Thomas Witkowski committed
270 271
      /// Reads one parameter from an inputput stream.
      void deserialize(std::istream &in); 
272 273

    public:
274 275 276 277
      std::string key;
      std::string parameters;
      std::string filename;
      std::string funcName;
278
      int lineNo;
279 280 281 282
    };

    static const char comment;

283
    std::string buffer;
284

Thomas Witkowski's avatar
Thomas Witkowski committed
285 286
    inline bool isBlankChar(const char s) 
    {
287 288 289
      return (s == ' ' || s == '\t' || s == '\f' || s == '\r'); 
    }

290
    const char *getNextWord(std::string *s) const;
291

Thomas Witkowski's avatar
Thomas Witkowski committed
292
    void read(const std::string& filename,const std::string& maxKey = "");
293

294
    const std::string& getActFile(const std::string& filename);
295

296
    const std::string getKey(const std::string& s, 
Thomas Witkowski's avatar
Thomas Witkowski committed
297 298
			     int nLine, 
			     const std::string& filename);
299

300
    const std::string getPar(const std::string& key, 
Thomas Witkowski's avatar
Thomas Witkowski committed
301 302 303
			     const std::string& s, 
			     int *nl, 
			     const std::string& fn);
304

305 306 307
    void addParam(const std::string& key, 
		  const std::string& parameter,
		  const std::string& actfile, 
Thomas Witkowski's avatar
Thomas Witkowski committed
308
		  int nLine, 
309
		  const std::string& fname);
310

311 312 313 314
    Parameters() 
      : paramInfo(1),
        msgInfo(1),
        msgWait(1)     
315
    {}
316

317
    virtual ~Parameters() {}
318 319 320

    static void initIntern();

321
    int binSearch(const std::string& key, int n_keys);
322 323 324 325 326 327

    void swap(int i, int j);

    void qsort(int left, int right);

  private:
328 329
    std::string cppFlags;
    std::ifstream inputFile;
330
    std::list<std::string> filenames;
331
    size_t maxFiles;
332
    std::string filename;
333 334 335
    int paramInfo;
    int msgInfo;
    int msgWait;
336
    std::vector<param> allParam;
337
   };
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360


  /** \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