// ============================================================================ // == == // == 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 #include #include #include #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, ::std::string filename, 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, const ::std::string key, const ::std::string par, 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, const ::std::string& key, const char *format, ...); /** \brief * Like getGlobalParameter(flag, key, "%s", param->c_str()). */ static int getGlobalParameter(int flag, const ::std::string& key, ::std::string *param); /** \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. */ static void save(const ::std::string file, int info); /** \brief * Checks whether parameters are initialized. if not, call init() */ static bool initialized() { return (singlett != NULL); }; static Parameters *getSingleton() { return singlett; }; // ===== Serializable implementation ===== void serialize(::std::ostream &out) { out.write(reinterpret_cast(¶mInfo), sizeof(int)); out.write(reinterpret_cast(&msgInfo), sizeof(int)); out.write(reinterpret_cast(&msgWait), sizeof(int)); int i, size = static_cast(allParam.size()); out.write(reinterpret_cast(&size), sizeof(int)); for(i = 0; i < size; i++) { allParam[i].serialize(out); } }; void deserialize(::std::istream &in) { in.read(reinterpret_cast(¶mInfo), sizeof(int)); in.read(reinterpret_cast(&msgInfo), sizeof(int)); in.read(reinterpret_cast(&msgWait), sizeof(int)); int i, size; in.read(reinterpret_cast(&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() {}; param(const ::std::string& nkey, const ::std::string& nparameters, const ::std::string& nfilename, const ::std::string& nfuncName, int line) : key(nkey), parameters(nparameters), filename(nfilename), funcName(nfuncName), lineNo(line) {}; param(const ::std::string& k): key(k) {}; int operator==(const class param& aParam) const; int operator!=(const class param& aParam) const { return !(aParam==*this); }; // ===== Serializable implementation ===== void serialize(::std::ostream &out) { out << key << ::std::endl; out << parameters << ::std::endl; out << filename << ::std::endl; out << funcName << ::std::endl; out.write(reinterpret_cast(&lineNo), sizeof(int)); }; void deserialize(::std::istream &in) { in >> key; in.get(); in >> parameters; in.get(); in >> filename; in.get(); in >> funcName; in.get(); in.read(reinterpret_cast(&lineNo), sizeof(int)); }; public: ::std::string key; ::std::string parameters; ::std::string filename; ::std::string funcName; int lineNo; }; static const char comment; ::std::string buffer; inline bool isBlankChar(const char s) {return (s==' '||s=='\t'||s =='\f'||s=='\r'); }; const char *getNextWord(::std::string *s) const; void read(const ::std::string& filename,const ::std::string& maxKey=""); const ::std::string& getActFile(const ::std::string& filename); const ::std::string getKey(const ::std::string& s, int nLine, const ::std::string& filename); const ::std::string getPar(const ::std::string& key, const ::std::string& s, int *nl, const ::std::string& fn); void addParam(const ::std::string& key, const ::std::string& parameter, const ::std::string& actfile, int nLine, const ::std::string& fname); Parameters() : paramInfo(1), msgInfo(1), msgWait(1) {}; virtual ~Parameters() {}; static void initIntern(); int binSearch(const ::std::string& key, int n_keys); void swap(int i, int j); void qsort(int left, int right); private: ::std::string cppFlags; ::std::ifstream inputFile; ::std::list< ::std::string> filenames; size_t maxFiles; ::std::string filename; int paramInfo; int msgInfo; int msgWait; ::std::vector allParam; }; /** \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