Newer
Older
/******************************************************************************
*
* AMDiS - Adaptive multidimensional simulations
*
* Copyright (C) 2013 Dresden University of Technology. All Rights Reserved.
* Web: https://fusionforge.zih.tu-dresden.de/projects/amdis
*
* Simon Vey, Thomas Witkowski, Andreas Naumann, Simon Praetorius, et al.
*
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
* WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
*
* This file is part of AMDiS
*
* See also license.opensource.txt in the distribution.
******************************************************************************/

Praetorius, Simon
committed
#ifndef INITFILE_H
#define INITFILE_H
#include <fstream>
#include <sstream>
#include <string>
#include <map>
#include <list>
#include <set>
#include <vector>
#include <stdexcept>
#include <iostream>
#include <typeinfo>
#include "FixVec.h"
#include <boost/numeric/conversion/cast.hpp>
#include <boost/type_traits.hpp>

Praetorius, Simon
committed
namespace detail {

Praetorius, Simon
committed
// Exceptions
//_________________________________________________________________________________________

Praetorius, Simon
committed
/// Exception for wrong vector size when parsing for concrete vector type
WrongVectorSize(std::string m) : std::runtime_error(m) {}

Praetorius, Simon
committed

Praetorius, Simon
committed
/// Exception for no delimiter found in vector
NoDelim(std::string m) : std::runtime_error(m) {}

Praetorius, Simon
committed

Praetorius, Simon
committed
/// Exception for begin and end brackets are different in vector
WrongVectorFormat(std::string m) : std::runtime_error(m) {}

Praetorius, Simon
committed
/// Exception for wrong value format
struct WrongValueFormat : std::runtime_error
{
static std::string name(bool) { return "bool"; }
static std::string name(double) { return "double"; }
static std::string name(float) { return "float"; }
static std::string name(int) { return "int"; }
static std::string name(unsigned int) { return "unsigned int"; }
static std::string name(G)
{
return std::string(typeid(G).name());

Praetorius, Simon
committed
: std::runtime_error("cannot convert '" + value + "' into <" + name(T()) + ">")

Praetorius, Simon
committed
/// Exception for bad arithmetic expression that can not be evaluated
struct BadArithmeticExpression : std::runtime_error

Praetorius, Simon
committed
{
static std::string name(bool) { return "bool"; }
static std::string name(double) { return "double"; }
static std::string name(float) { return "float"; }
static std::string name(int) { return "int"; }
static std::string name(unsigned int) { return "unsigned int"; }

Praetorius, Simon
committed
static std::string name(G)
{

Praetorius, Simon
committed
return std::string(typeid(G).name());

Praetorius, Simon
committed
BadArithmeticExpression(std::string m, std::string value)
: std::runtime_error("cannot evaluate expression '" + value + "' into <" + name(T()) + ">\n"
"Parser message: '" + m + "'")

Praetorius, Simon
committed
// _____________________________________________________________________________
/// return the delimiter or throw an exception if there is no known

Praetorius, Simon
committed
/// delimiter in value
inline size_t checkDelim(const std::string& value, const std::string& delims)
{
size_t pos(std::string::npos);
for (size_t i = 0; i < delims.length(); i++) {

Praetorius, Simon
committed
pos = value.find(delims[i]);
if (pos != std::string::npos)
return i;
// throw NoDelim("cannot detect the delimiter in " + value);
double mu_parser_eval(std::string const& valStr);
inline void convert(const std::string& valStr, std::string& value)
{
value = trim(valStr);
}
/// convert string to intrinsic type
template<typename T> inline
typename boost::enable_if
< boost::mpl::and_
< boost::is_pod<T>,
boost::mpl::not_< boost::is_enum<T> > >,
convert(const std::string& valStr, T& value)
{
using boost::lexical_cast;
using boost::numeric_cast;
value = numeric_cast< T >(mu_parser_eval(valStr));
/* } catch (boost::bad_lexical_cast e) { */
/* throw WrongValueFormat< T >(valStr); */
/* } catch (boost::bad_numeric_cast e) { */
/* throw WrongValueFormat< T >(valStr); */
/* } catch (mu::Parser::exception_type &e) { */
/* throw BadArithmeticExpression<T>(e.GetMsg(), valStr); */
/* } */
template<typename T> inline
typename boost::enable_if
< boost::is_enum<T>,
convert(const std::string& valStr, T& value)

Praetorius, Simon
committed
int swap = 0;

Praetorius, Simon
committed
swap = boost::lexical_cast<int>(trim(valStr));
/* } catch (boost::bad_lexical_cast e) { */
/* throw WrongValueFormat< T >(valStr); */
/* } */
value = static_cast< T >(swap);
}

Praetorius, Simon
committed
/// convert special enums
inline void convert(const std::string& valStr, Norm& value)

Praetorius, Simon
committed
{
std::string swapStr = boost::to_upper_copy(valStr);
if (swapStr == "NO_NORM")
value = static_cast< Norm >(NO_NORM);
else if (swapStr == "H1_NORM")
value = static_cast< Norm >(H1_NORM);
else if (swapStr == "L2_NORM")
value = static_cast< Norm >(L2_NORM);
else {

Praetorius, Simon
committed
convert(valStr, swap);
value = static_cast< Norm >(swap);
}
}
/// convert value of arbitrary type to string using stringstream and
inline void convert(const T& value, std::string& valStr)
{
std::stringstream ss;
ss.precision(6);
ss << value;
valStr = ss.str();
}
/// convert WorldVector to string
// TODO: allgemeine Funktion zum Schreiben von Vektoren implementieren
// unter Ausnutzung von Type-Traits
template<typename T>
inline void convert(const WorldVector<T>& c, std::string& valStr)
{
std::vector<T> temp_vec(size(c));
for (unsigned i = 0; i < size(temp_vec); i++)
temp_vec[i] = c[i];
convert(temp_vec, valStr);
}
inline void convert(const std::string& valStr, WorldVector<T>& c);
inline void convert(const std::string& valStr, std::list<T>& value);
inline void convert(const std::string& valStr, std::vector<T>& value);
/** parse an container from tag tag. The Container must have the properties:
* - type value_type
* - member function push_back
*/
template< typename Container >
inline void getContainer(const std::string& val_, Container& c)
{
// accepted brackets and delimiters for vector input
std::string begBrackets= "{[(";
std::string endBrackets= "}])";
std::string delims= ";,";
c.clear();
std::string val = trim(val_);
bool hasBrackets = true;
size_t pos = begBrackets.find(val[0]);
if (pos == std::string::npos)
hasBrackets = false;
if (hasBrackets && val[val.length() - 1] != endBrackets[pos])
throw WrongVectorFormat("begin and end bracket are different in"
" value '" + val + "'");
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
282
size_t oldPos = (hasBrackets ? 1 : 0);
size_t curDelim = 0;
typedef typename Container::value_type ValueType;
ValueType swap;
try {
curDelim = checkDelim(val, delims);
pos = val.find(delims[curDelim], oldPos);
while (pos != std::string::npos) {
std::string curWord = val.substr(oldPos, pos - oldPos);
oldPos = pos + 1;
convert(curWord, swap);
c.push_back(swap);
pos = val.find(delims[curDelim], oldPos);
}
//last entry
std::string curWord = val.substr(oldPos, val.length() - (hasBrackets ? 1 : 0) - oldPos);
convert(curWord, swap);
c.push_back(swap);
} catch (NoDelim nd) {
std::string curWord = val.substr(oldPos, val.length() - (hasBrackets ? 2 : 0));
curWord = trim(curWord);
if (curWord.length() > 0) {
// container with one entry
convert(curWord, swap);
c.push_back(swap);
}
}
}
// TODO: Verallgemeinerung der convert-method für bel. Vektoren und
// hinzunahme der Möglichkeit Matrizen anzugeben
/// convert string to WorldVector
template< typename T >
inline void convert(const std::string& valStr, WorldVector<T>& c)
{
std::vector<T> temp_vec;
getContainer(valStr, temp_vec);
if (static_cast<int>(temp_vec.size()) != c.getSize())
throw WrongVectorSize("wrong number of entries for WorldVector");

Praetorius, Simon
committed
c[i] = temp_vec[i];
}
/// convert string to std::list using begBrackets, endBrackets and delims
template<typename T>
inline void convert(const std::string& valStr, std::list<T>& value)
{
getContainer(valStr, value);
}
/// convert string to std::vector using begBrackets, endBrackets and delims
template<typename T>
inline void convert(const std::string& valStr, std::vector<T>& value)
{
getContainer(valStr, value);
}

Praetorius, Simon
committed
} // end namespace detail

Praetorius, Simon
committed
// _____________________________________________________________________________
/** The entry in an initfile. This helper class was constructed to allow calls

Praetorius, Simon
committed
* like val = data.get(tag) for arbitrary types of val. At current stage, only
* double and bool is supported
*/
struct InitEntry {
///the value as string
std::string valStr;
/// initialize with value as string
InitEntry(std::string v = "")
{}
/// cast string to type T
template<typename T>
operator T() const
{
T t;
detail::convert(valStr, t);
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
return t;
}
};
/// output-stream for std::list
template<typename T>
std::ostream& operator<<(std::ostream& o, const std::list< T >& l)
{
typename std::list< T >::const_iterator it = l.begin();
o << "[";
for (unsigned i = 0; it != l.end() && i < l.size(); i++) {
o << *it << (i < l.size() - 1 ? ", " : "");
++it;
}
o << "]";
return o;
}
/// output-stream for std::vector
template<typename T>
std::ostream& operator<<(std::ostream& o, const std::vector<T>& l)
{
typename std::vector<T>::const_iterator it = l.begin();
o << "[";
for (unsigned i = 0; it != l.end() && i < l.size(); i++) {
o << *it << (i < l.size() - 1 ? ", " : "");
++it;
}
o << "]";
return o;
}

Praetorius, Simon
committed
// _____________________________________________________________________________
/** Basis data container as a map of tag on a value as strings. The container

Praetorius, Simon
committed
* throws an exception, if the tag was not found.
*/
struct Initfile : public std::map<std::string, std::string>
{
typedef std::map< std::string, std::string > super;

Thomas Witkowski
committed
static const int TAG_NOT_FOUND = 1;
static const int TAG_NOT_FOUND_BREAK = 2;

Praetorius, Simon
committed
TagNotFound(std::string m)
: std::invalid_argument(m)

Praetorius, Simon
committed
struct TagNotFoundBreak : std::invalid_argument {
// print 'tag not found' and exit
: std::invalid_argument(m)

Praetorius, Simon
committed
/** initialize init-file from file with filename in, read data and save it

Praetorius, Simon
committed
* to singleton-map
* @param in: filename string
*/
static void init(int print, std::string filename, const char *flags = NULL)

Thomas Witkowski
committed
WARNING("Parameters::init(int,std::string,const char*) is depreciated. "
"Use Parameters::init(std::string) instead!\n");
init(filename);

Praetorius, Simon
committed
/** Static get routine for getting parameter-values from init-file

Praetorius, Simon
committed
* initialized in init()-method.
* Cast the value to the desired type using std::stringstream.
* @param tag: The tag to look for
* @param value: The result.
* @param debugInfo: msgInfo for current parameter. (0..no printing,
* 1..print missing parameter info, 2..print parameter value) [optional]
*/
template<typename T>
static void get(const std::string tag, T& value, int debugInfo = -1)
{
if (debugInfo == -1)
debugInfo = singlett().getMsgInfo();
else {
int swap(debugInfo);
debugInfo = singlett().getMsgInfo();
singlett().msgInfo=swap;

Praetorius, Simon
committed

Thomas Witkowski
committed
std::string valStr;
int error_code = singlett().checkedGet(tag, valStr);

Thomas Witkowski
committed
if (error_code == 0) {
valStr = trim(valStr);

Praetorius, Simon
committed
detail::convert(valStr, value);

Naumann, Andreas
committed
else if(error_code == TAG_NOT_FOUND_BREAK)

Thomas Witkowski
committed
throw TagNotFoundBreak("required tag '" + tag + "' not found");
else if (error_code == TAG_NOT_FOUND) {
if (debugInfo == 2)
std::cout << "there is no tag '" + tag + "'" << std::endl;
} else
throw std::runtime_error("unknown error_code (" + boost::lexical_cast<std::string>(error_code) + ") returned for tag '" + tag + "'");

Naumann, Andreas
committed
std::string parser_error = "Could not parse: " + tag;
throw std::runtime_error(parser_error);
}

Thomas Witkowski
committed
if (debugInfo == 2) {
std::cout << "Parameter '" << tag << "'"
<< " initialized with: " << value << std::endl;
singlett().msgInfo = debugInfo;
/** Static get routine for getting a parameter-map from init-file

Backofen, Rainer
committed
* initialized in init()-method.

Backofen, Rainer
committed
* line in Initfile: <tag><key>: <value>
* is extracted in am map [key]->[value].
* @param tag: The tag withch labels the parameter map

Backofen, Rainer
committed
* @param debugInfo: msgInfo for current parameter. (0..no printing,
* 2..print parameter value) [optional]
*/
static void getParameterMap(const std::string tag,

Backofen, Rainer
committed
std::map<std::string,std::string> &pm,
int debugInfo = -1)
{
for (Initfile::iterator it = singlett().begin(); it != singlett().end(); it++){

Backofen, Rainer
committed
std::string longTag= (*it).first ;
std::string value=(*it).second;
if(longTag.length()>tag.length() &&
longTag.compare(0,tag.length(),tag)==0){

Backofen, Rainer
committed
if (debugInfo == 2){
std::cout <<"tag "<< tag <<"\n";
std::cout <<"Extract Parameter map from "<<(*it).first
<< " => " <<(*it).second << std::endl;

Backofen, Rainer
committed
}

Backofen, Rainer
committed
std::string key=trim(longTag.substr(tag.length()));

Backofen, Rainer
committed
if (debugInfo == 2){
std::cout <<"Parameter map "<< key << " => "
<< value << std::endl;

Backofen, Rainer
committed
}
pm[key]=value;
}

Backofen, Rainer
committed
}
/// return InitEntry object for tag tag
static InitEntry get(const std::string tag)

Thomas Witkowski
committed
std::string valStr;
int error_code = singlett().checkedGet(tag, valStr);

Thomas Witkowski
committed
if (error_code == 0) {
valStr = trim(valStr);
result = InitEntry(valStr);
#if 0
else if(error_code == TAG_NOT_FOUND_BREAK)
throw TagNotFoundBreak("get(): required tag '" + tag + "' not found");

Thomas Witkowski
committed
else if (error_code == TAG_NOT_FOUND)
throw TagNotFound("get(): there is no tag '" + tag + "'");
// exception must be thrown, because an empty object would be return otherwise
throw std::runtime_error("get(): unknown error_code returned for tag '" + tag + "'");

Praetorius, Simon
committed
/// update map tag->value_old to tag->value in singleton
template<typename T>
static void set(const std::string tag, T const& value, int debugInfo= -1)
debugInfo = singlett().getMsgInfo();

Praetorius, Simon
committed

Praetorius, Simon
committed
detail::convert(value, swap);
singlett()[trim(tag)] = swap;
// update msg parameters msgInfo, msgWait, paramInfo
singlett().getInternalParameters();

Praetorius, Simon
committed
std::cout << "Parameter '" << tag << "'"
<< " set to: " << value << std::endl;

Praetorius, Simon
committed
/// add map tag->value to data in singleton
template< typename T >
static void add(const std::string tag, T const& value, int debugInfo = -1)
{
set(tag, value, debugInfo);
}

Praetorius, Simon
committed
static void readArgv(std::string parameters, int debugInfo = 2);

Praetorius, Simon
committed
static int getMsgInfo()
{
return singlett().msgInfo;

Praetorius, Simon
committed
static int getMsgWait()
{
return singlett().msgWait;

Praetorius, Simon
committed
/// print all data in singleton to std::cout
static void printParameters();

Praetorius, Simon
committed
/// clear data in singleton
static void clearData()
{
singlett().clear();

Praetorius, Simon
committed
/// save singlett-data to file with filename fn
static void save(std::string fn)
{
singlett().write(fn);
// list of included filenames
static std::set< std::string >& getIncludeList()
{
static std::set< std::string > include_list;
return include_list;
protected:
Initfile()
: msgInfo(0),
msgWait(1),
paramInfo(1),
breakOnMissingTag(0)

Praetorius, Simon
committed
/// return reference to singleton
static Initfile& singlett()
static Initfile singlett_{};
return singlett_;

Praetorius, Simon
committed
/// return the value of the given tag or throws an exception if the tag

Praetorius, Simon
committed
/// does not exist

Thomas Witkowski
committed
int checkedGet(const std::string& tag, std::string &valStr) const
{
super::const_iterator it = find(tag);
if (it == end()) {

Praetorius, Simon
committed
if (breakOnMissingTag == 0 || msgInfo <= 2)

Thomas Witkowski
committed
return TAG_NOT_FOUND;

Praetorius, Simon
committed
else

Thomas Witkowski
committed
return TAG_NOT_FOUND_BREAK;

Thomas Witkowski
committed
valStr = it->second;
return 0;
/// replace variables by its value defined as parameter previousely
/// variable definition is simple parameter definition
/// variable evaluation by ${variablename} or $variablename
/// the last version only for variablenames without whitespaces
std::string variableReplacement(const std::string& input) const;

Praetorius, Simon
committed
std::string variableEvaluation(const std::string& input) const;
/** Fill the initfile from an input stream.

Praetorius, Simon
committed
* @param in: the stream to fill the data from.
* Current dataformat: tag:value
* Comment char: percent '%'
* Include files: #include "filename" or #include <filename>
*/
void read(std::istream& in);
/// Fill the initfile from a file with filename fn
void read(std::string fn, bool force = false);

Praetorius, Simon
committed

Praetorius, Simon
committed
* @param out: the stream to fill the data in.
*/
/// Write data-map to initfile with filename fn
void write(std::string fn);

Praetorius, Simon
committed
/// read parameters for msgInfo, msgWait, paramInfo
void getInternalParameters();

Praetorius, Simon
committed
int msgInfo, msgWait, paramInfo, breakOnMissingTag;