From 005615331eb8b03a965534158bda088cf6494ca5 Mon Sep 17 00:00:00 2001 From: Simon Praetorius <simon.praetorius@tu-dresden.de> Date: Fri, 3 Jun 2011 12:01:50 +0000 Subject: [PATCH] new Initfile parser --- AMDiS/AMDiSConfig.cmake.in | 7 +- AMDiS/CMakeLists.txt | 25 ++- AMDiS/src/Initfile.cc | 142 ++++++++++++++ AMDiS/src/Initfile.h | 378 +++++++++++++++++++++++++++++++++++++ AMDiS/src/Parameters.cc | 70 +++---- 5 files changed, 580 insertions(+), 42 deletions(-) create mode 100644 AMDiS/src/Initfile.cc create mode 100644 AMDiS/src/Initfile.h diff --git a/AMDiS/AMDiSConfig.cmake.in b/AMDiS/AMDiSConfig.cmake.in index 113c0b97..c711d0fa 100644 --- a/AMDiS/AMDiSConfig.cmake.in +++ b/AMDiS/AMDiSConfig.cmake.in @@ -68,7 +68,7 @@ set(AMDIS_MINOR_VERSION @AMDIS_MINOR@) if(AMDiS_NEED_UMFPACK) #look for umfpack, we need the headers only find_file(UMFPACK_H umfpack.h - HINTS /usr/include /usr/include/suitesparse + HINTS /usr/include /usr/include/suitesparse /usr/include/ufsparse DOC "headerfile umfpack.h for UMFPACK") if( UMFPACK_H ) #construct the include path @@ -125,6 +125,11 @@ if(AMDiS_NEED_UMFPACK) list(APPEND AMDIS_LIBRARY_DIRS ${BLAS_LIBRARY_DIR}) endif(AMDiS_NEED_UMFPACK) + +#add directories for reinit +list(APPEND AMDIS_INCLUDE_DIRS ${AMDIS_INCLUDE_DIR}/reinit) +list(APPEND AMDIS_INCLUDE_DIRS ${AMDIS_INCLUDE_DIR}/compositeFEM) + if(${AMDIS_FIND_COMPONENTS} MATCHES umfpack ) if( NOT AMDiS_NEED_UMFPACK ) set( AMDiS_umfpack_FOUND FALSE) diff --git a/AMDiS/CMakeLists.txt b/AMDiS/CMakeLists.txt index bbf3e5f1..4427d078 100644 --- a/AMDiS/CMakeLists.txt +++ b/AMDiS/CMakeLists.txt @@ -100,6 +100,7 @@ SET(AMDIS_SRC ${SOURCE_DIR}/AdaptBase.cc ${SOURCE_DIR}/Global.cc ${SOURCE_DIR}/GlobalDOFNumbering.cc ${SOURCE_DIR}/GlobalElementNumbering.cc + ${SOURCE_DIR}/Initfile.cc ${SOURCE_DIR}/Lagrange.cc ${SOURCE_DIR}/LeafData.cc ${SOURCE_DIR}/Line.cc @@ -288,7 +289,7 @@ if(ENABLE_UMFPACK) #look for umfpack, we need the headers only find_file(UMFPACK_H umfpack.h - HINTS /usr/include /usr/include/suitesparse + HINTS /usr/include /usr/include/suitesparse /usr/include/ufsparse DOC "headerfile umfpack.h for UMFPACK") if( UMFPACK_H ) #construct the include path @@ -345,8 +346,9 @@ include_directories(${AMDiS_INCLUDE_DIRS}) add_library(amdis SHARED ${AMDIS_SRC} ${PARALLEL_DOMAIN_AMDIS_SRC}) add_library(compositeFEM SHARED ${COMPOSITE_FEM_SRC}) -add_library(reinit STATIC ${REINIT_SRC}) -target_link_libraries(compositeFEM amdis) +add_library(reinit SHARED ${REINIT_SRC}) +#target_link_libraries(compositeFEM amdis) +#target_link_libraries(reinit amdis) list(APPEND AMDiS_LIBS amdis ${Boost_LIBRARIES}) if(WIN32) @@ -361,9 +363,6 @@ if(ENABLE_MARMOT) endif(ENABLE_MARMOT) #dont change this destination. the GUI depends on it to guess the buildsystem -list(APPEND deb_add_dirs "lib/amdis") -install(TARGETS amdis compositeFEM - LIBRARY DESTINATION lib/amdis/ ) FILE(GLOB HEADERS "${SOURCE_DIR}/*.h") INSTALL(FILES ${HEADERS} @@ -398,6 +397,20 @@ FILE(GLOB HEADERS "${SOURCE_DIR}/io/*.hh") INSTALL(FILES ${HEADERS} DESTINATION include/amdis/io) +FILE(GLOB HEADERS "${REINIT_SOURCE_DIR}/*.h") +INSTALL(FILES ${HEADERS} + DESTINATION include/amdis/reinit) +list(APPEND deb_add_dirs "include/amdis/reinit") + +FILE(GLOB HEADERS "${COMPOSITE_SOURCE_DIR}/*.h") +INSTALL(FILES ${HEADERS} + DESTINATION include/amdis/compositeFEM) +list(APPEND deb_add_dirs "include/amdis/compositeFEM") + +list(APPEND deb_add_dirs "lib/amdis") +install(TARGETS amdis compositeFEM reinit + LIBRARY DESTINATION lib/amdis/ ) + configure_file(${AMDiS_SOURCE_DIR}/AMDiSConfig.cmake.in ${AMDiS_BINARY_DIR}/AMDISConfig.cmake @ONLY diff --git a/AMDiS/src/Initfile.cc b/AMDiS/src/Initfile.cc new file mode 100644 index 00000000..e22348b7 --- /dev/null +++ b/AMDiS/src/Initfile.cc @@ -0,0 +1,142 @@ +#include "Initfile.h" + +#include <string> +#include <stdexcept> +#include <iostream> +#include <sstream> +using namespace std; + +/// the small parser for the initfile. see description of read(Initfile&, istream&) +struct Parser { + Parser(const string& line) { + size_t pos= line.find(':'); + if (pos == string::npos) + throw runtime_error("cannot find the delimiter ':' in line '"+line+"'"); + name= line.substr(0, pos); + value= line.substr(pos+1, line.length() - (pos + 1)); + // remove everything after the % + pos= value.find('%'); + if (pos != string::npos) { + value= value.substr(0, pos); + } + } + string name; + string value; +}; + +Initfile* Initfile::singlett= NULL; +std::set< std::string > Initfile::fn_include_list; + +/// initialize singleton object an global parameters +void Initfile::init(std::string in) { + initIntern(); + singlett->clear(); + fn_include_list.clear(); + singlett->read(in); + + singlett->getInternalParameters(); + + // initialize global strcutures using parameters + Global::init(); +}; + +/// Fill an initfile from a file with filename fn +void Initfile::read(std::string fn) { +// read file if its not parsed already + if (fn_include_list.find(fn)==fn_include_list.end()) { + std::ifstream inputFile; + inputFile.open(fn.c_str(), std::ios::in); + if (!inputFile.is_open()) + throw runtime_error("init-file cannot be opened for reading"); + + fn_include_list.insert(fn); + read(inputFile); + } +}; + +/// Fill an initfile from an input stream +void Initfile::read(istream& in) { + unsigned line_length= 256; + char swap[line_length]; + in.getline(swap, line_length); + while (in.good()) { + std::string whitespaces= " \t\r\f"; + std::string sw(swap); + size_t pos0= sw.find_first_not_of(whitespaces); + + if (pos0!=std::string::npos && sw[pos0]!='%' && sw[pos0]!='#' && sw[pos0]!=0) { + // parse line and extract map: tag->value + Parser parser(sw); + operator[](parser.name)= parser.value; + } else if (sw[pos0]=='#' && static_cast<size_t>(sw.find("#include"))==pos0) { + // include file by '#include "filename"' or '#include <filename>' + size_t pos= sw.find_first_not_of(whitespaces,std::string("#include").size()+1); + size_t epos= 0; + std::string fn= ""; + std::stringstream errorMsg; + switch (char c= swap[pos++]) { + case '<': + c= '>'; + case '\"': + whitespaces+= c; + epos= sw.find_first_of(whitespaces, pos); + fn= sw.substr(pos,epos-pos); + + if (sw[epos]!=c) { + errorMsg << "filename in #include not terminated by " << c; + throw std::runtime_error(errorMsg.str()); + } + break; + default: + throw std::runtime_error("no filename given for #include"); + } + read(fn); + } + in.getline(swap, line_length); + } +}; + +/// read standard values for output and information of parameter-values +void Initfile::getInternalParameters() +{ + int val= 10; + get("level of information", val, 0); + msgInfo= val; + + val= 1; + get("WAIT", val, 0); + msgWait= val; + + val= 1; + get("parameter information", val, 0); + paramInfo= val; + + if (msgInfo==0) + paramInfo= 0; +}; + +/// print all parameters to std::cout +void Initfile::printParameters() { + initIntern(); + Initfile::iterator it; + for (it= singlett->begin(); it!=singlett->end(); it++) + std::cout << (*it).first << " => " << (*it).second << std::endl; +}; + +/// Write data-map to initfile +void Initfile::write(ostream& out) { + Initfile::iterator it; + for (it= begin() ; it!=end(); it++) + out << (*it).first << ": " << (*it).second << std::endl; + +}; + +/// Write data-map to initfile +void Initfile::write(std::string fn) { + std::ofstream outFile; + outFile.open(fn.c_str(), std::ios::out); + if (!outFile.is_open()) + throw runtime_error("init-file cannot be opened for writing"); + + write(outFile); +}; diff --git a/AMDiS/src/Initfile.h b/AMDiS/src/Initfile.h new file mode 100644 index 00000000..5f815214 --- /dev/null +++ b/AMDiS/src/Initfile.h @@ -0,0 +1,378 @@ +#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/algorithm/string/trim.hpp> +#include <boost/lexical_cast.hpp> + +using namespace AMDiS; + +namespace InitfileInternal { + /// Exceptions + struct WrongVectorSize : std::runtime_error { + WrongVectorSize(std::string m):std::runtime_error(m) {} + }; + struct NoDelim : std::runtime_error { + NoDelim(std::string m):std::runtime_error(m) {} + }; + struct WrongVectorFormat : std::runtime_error { + WrongVectorFormat(std::string m):std::runtime_error(m) {} + }; + template< typename T > + struct WrongValueFormat : std::runtime_error { + static std::string name(int ) { return "int"; } + static std::string name(bool ) { return "bool"; } + static std::string name(double ) { return "double"; } + static std::string name(unsigned int ) { return "unsigned int"; } + template< typename G > + static std::string name(G ) { return std::string(typeid(G).name()); } + + WrongValueFormat(std::string value): std::runtime_error(std::string("cannot convert '") + value + std::string("' into <")+ name(T())+">" ) + {} + + }; + + /// trim std::string + inline std::string trim(const std::string& oldStr) { + std::string swap(oldStr); + boost::algorithm::trim(swap); + return swap; + } + /// return the delimiter or throw an exception if there is no known delimiter in value + size_t checkDelim(const std::string& value, const std::string& delims) { + size_t pos(std::string::npos); + for (unsigned i= 0; i<delims.length(); ++i) { + pos= value.find(delims[i]); + if (pos!=std::string::npos) + return i; + } + throw NoDelim("cannot detect the delimiter in " + value); + return 0; + } + + + /** 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_); + size_t pos= begBrackets.find(val[0]); + if( pos == std::string::npos ) + throw WrongVectorFormat("cannot convert '" + val + "' into a list. No leading bracket found!"); + if( val[val.length() - 1] != endBrackets[pos] ) + throw WrongVectorFormat("begin and end bracket are different in value '" + val + "'"); + size_t oldPos= 1; + 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 - 1); + 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() - oldPos-1); + convert(curWord, swap); + c.push_back(swap); + } catch (NoDelim nd) { + std::string curWord= val.substr(1, val.length()-2); + curWord = trim(curWord); + if(curWord.length()>0) { + // container with one entry + convert(curWord, swap); + c.push_back(swap); + } + } + } + + /// convert string to string + inline void convert(const std::string valStr, std::string& value) { + value= trim(valStr); + } + + /// convert string to intrinsic type + template< typename T > + inline void convert(const std::string valStr, T& value) { + using boost::lexical_cast; + try { + value = lexical_cast< T >(trim(valStr)); + }catch(boost::bad_lexical_cast e) { + throw WrongValueFormat< T >(valStr); + } + } + /// 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"); + + for (unsigned i= 0; i<temp_vec.size(); ++i) + 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); + } + + /// convert value of arbitrary type to string using stringstream and operator<< for type + template< typename T > + inline void convert(const T value, std::string& valStr) { + std::stringstream ss; + ss << value; + valStr= ss.str(); + } + /// convert WorldVector to string + template< typename T > + inline void convert(const WorldVector<T>& c, std::string& valStr) { + std::vector<T> temp_vec(c.getSize()); + for (unsigned i= 0; i<temp_vec.size(); ++i) + temp_vec[i]= c[i]; + convert(temp_vec, valStr); + } +} // end namespace InitfileInternal + +/** The entry in an initfile. This helper class was constructed to allow calls 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= ""): + valStr(v) {} + + /// cast string to type T + template< typename T > + operator T() const { T t; convert(valStr, t); 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; +} + +/** Basis data container as a map of tag on a value as strings. The container 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; + + /// Exceptions + struct TagNotFound : std::invalid_argument { + TagNotFound(std::string m):std::invalid_argument(m) {} + }; + + /** initialize init-file from file with filename in, read data and save it to singleton-map + * @param in: filename string + */ + static void init(std::string in); + + /** Static get routine for getting parameter-values from init-file 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 debug_info: 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 debug_info= -1) { + using namespace InitfileInternal; + initIntern(); + if (debug_info==-1) + debug_info= singlett->getMsgInfo(); + + try { + std::string valStr(singlett->checkedGet(tag)); + valStr= trim(valStr); + convert(valStr, value); + if (debug_info==2) + std::cout << "Parameter '" << tag << "' initialized with: " << value << std::endl; + } catch (TagNotFound ia) { + if (debug_info>=1) + std::cout << ia.what() << std::endl; + } + } + /// return InitEntry object for tag tag + static InitEntry get(const std::string tag) { + using namespace InitfileInternal; + int debug_info= singlett->getMsgInfo(); + InitEntry result; + try { + std::string valStr(singlett->checkedGet(tag)); + valStr= trim(valStr); + result= InitEntry(valStr); + } catch (TagNotFound ia) { + if (debug_info>=1) + std::cout << ia.what() << std::endl; + } + return result; + } + + /// update map tag->value_old to tag->value in singleton + template< typename T > + static void set(const std::string tag, T& value, int debug_info= -1) { + using namespace InitfileInternal; + initIntern(); + if (debug_info==-1) + debug_info= singlett->getMsgInfo(); + + std::string swap= ""; + convert(value, swap); + (*singlett)[trim(tag)]= swap; + // update msg parameters msgInfo, msgWait, paramInfo + singlett->getInternalParameters(); + if (debug_info==2) + std::cout << "Parameter '" << tag << "' set to: " << value << std::endl; + } + + /// add map tag->value to data in singleton + template< typename T > + static void add(const std::string tag, T& value, int debug_info= -1) { + set(tag, value, debug_info); + } + + /// Returns specified info level + static int getMsgInfo() + { + return (singlett!=NULL) ? singlett->msgInfo : 0; + } + + /// Returns specified wait value + static int getMsgWait() + { + return (singlett!=NULL) ? singlett->msgWait : 0; + } + + /// Checks whether parameters are initialized. if not, call init() + static bool initialized() + { + return (singlett!=NULL); + } + + /// return pointer to singleton + static Initfile *getSingleton() + { + return singlett; + } + + /// print all data in singleton to std::cout + static void printParameters(); + + /// clear data in singleton + static void clearData() + { + initIntern(); + singlett->clear(); + } + + /// save singlett-data to file with filename fn + static void save(std::string fn) + { + initIntern(); + singlett->write(fn); + } + +protected: + Initfile() : msgInfo(10), msgWait(1), paramInfo(1) {} + + static void initIntern() { + if (singlett == NULL) + singlett= new Initfile; + } + + /// list of processed files + static std::set< std::string > fn_include_list; + + /// pointer to the singleton that contains the data + static Initfile* singlett; + + /// return the value of the given tag or throws an exception if the tag does not exist + std::string checkedGet(const std::string& tag) const { + super::const_iterator it= find(tag); + if (it==end()) + throw TagNotFound("there is no tag '"+ tag + "'"); + return it->second; + } + + /** Fill the initfile from an input stream. + * @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); + + /** Write data-map to initfile + * @param out: the stream to fill the data in. + */ + void write(std::ostream& out); + + /// Write data-map to initfile with filename fn + void write(std::string fn); + + /// read parameters for msgInfo, msgWait, paramInfo + void getInternalParameters(); + + int msgInfo, msgWait, paramInfo; + +}; +#endif diff --git a/AMDiS/src/Parameters.cc b/AMDiS/src/Parameters.cc index 2d887ebb..dc003fa0 100644 --- a/AMDiS/src/Parameters.cc +++ b/AMDiS/src/Parameters.cc @@ -340,41 +340,41 @@ namespace AMDiS { return(key); if (s[pos] == '#') { - if (static_cast<int>(s.find("#include")) == pos) { - /****************************************************************************/ - /* another init file has to be included */ - /****************************************************************************/ - - pos += strlen("#include"); - pos = s.find_first_not_of(" \t\f\r"); - - i = 0; - switch (c = s[pos++]) { - case '<': - c = '>'; - case '\"': - h += c; - epos = s.find_first_not_of(h, pos); - fn = s.substr(pos,epos-1); - - if (s[epos] != c) { - ERROR("aFilename of include not terminated by %c\n", c); - ERROR("skipping line %d of file %s\n", nLine, aFilename.c_str()); - return(""); - } - break; - default: - ERROR("no aFilename of include file found\n"); - ERROR("skipping line %d of file %s\n", nLine, aFilename.c_str()); - return(""); - } - - read(fn); - return(""); - } else { - ERROR("# must not be the first character on a line; except #include\n"); - return(""); - } +// if (static_cast<int>(s.find("#include")) == pos) { +// /****************************************************************************/ +// /* another init file has to be included */ +// /****************************************************************************/ +// +// pos += strlen("#include"); +// pos = s.find_first_not_of(" \t\f\r"); +// +// i = 0; +// switch (c = s[pos++]) { +// case '<': +// c = '>'; +// case '\"': +// h += c; +// epos = s.find_first_not_of(h, pos); +// fn = s.substr(pos,epos-1); +// +// if (s[epos] != c) { +// ERROR("aFilename of include not terminated by %c\n", c); +// ERROR("skipping line %d of file %s\n", nLine, aFilename.c_str()); +// return(""); +// } +// break; +// default: +// ERROR("no aFilename of include file found\n"); +// ERROR("skipping line %d of file %s\n", nLine, aFilename.c_str()); +// return(""); +// } +// +// read(fn); +// return(""); +// } else { +// ERROR("# must not be the first character on a line; except #include\n"); +// return(""); +// } } /****************************************************************************/ -- GitLab