Initfile.h 17.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
//
// Software License for AMDiS
//
// Copyright (c) 2010 Dresden University of Technology 
// All rights reserved.
// Authors: Simon Vey, Thomas Witkowski et al.
//
// This file is part of AMDiS
//
// See also license.opensource.txt in the distribution.

Praetorius, Simon's avatar
Praetorius, Simon committed
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#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/lexical_cast.hpp>
28
29
#include <boost/numeric/conversion/cast.hpp> 

30
#include <boost/type_traits.hpp>
Praetorius, Simon's avatar
Praetorius, Simon committed
31

32
33
// a parser for arithmetic expressions
#include "muParser.h"
Praetorius, Simon's avatar
Praetorius, Simon committed
34

35
36
namespace AMDiS {

Praetorius, Simon's avatar
Praetorius, Simon committed
37
  namespace details {
38
  
39
    /// Exceptions
Praetorius, Simon's avatar
Praetorius, Simon committed
40
41
    ///_________________________________________________________________________________________
    
Praetorius, Simon's avatar
Praetorius, Simon committed
42
    struct WrongVectorSize : std::runtime_error {
Praetorius, Simon's avatar
Praetorius, Simon committed
43
      WrongVectorSize(std::string m) : std::runtime_error(m) {}
44
45
    };

46

Praetorius, Simon's avatar
Praetorius, Simon committed
47
    struct NoDelim : std::runtime_error {
Praetorius, Simon's avatar
Praetorius, Simon committed
48
      NoDelim(std::string m) : std::runtime_error(m) {}
49
50
    };

51

Praetorius, Simon's avatar
Praetorius, Simon committed
52
    struct WrongVectorFormat : std::runtime_error {
Praetorius, Simon's avatar
Praetorius, Simon committed
53
      WrongVectorFormat(std::string m) : std::runtime_error(m) {}
54
55
    };

Praetorius, Simon's avatar
Praetorius, Simon committed
56
    
57
    struct GetTagError : std::runtime_error {
Praetorius, Simon's avatar
Praetorius, Simon committed
58
      GetTagError(std::string m) : std::runtime_error(m) {}
59
60
    };
    
Praetorius, Simon's avatar
Praetorius, Simon committed
61
    
62
    template<typename T>
Praetorius, Simon's avatar
Praetorius, Simon committed
63
    struct WrongValueFormat : std::runtime_error {
Praetorius, Simon's avatar
Praetorius, Simon committed
64
65
66
67
68
69
      
      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"; }
70
71
72
73

      template<typename G>
      static std::string name(G) 
      { 
74
        return std::string(typeid(G).name()); 
75
      }
76

77
      WrongValueFormat(std::string value)
Praetorius, Simon's avatar
Praetorius, Simon committed
78
      : std::runtime_error("cannot convert '" + value + "' into <" + name(T()) + ">")
79
80
      {}
    };
Praetorius, Simon's avatar
Praetorius, Simon committed
81
    
Praetorius, Simon's avatar
Praetorius, Simon committed
82

83
84
    template<typename T>
    struct BadArithmeticExpression : std::runtime_error {
85

Praetorius, Simon's avatar
Praetorius, Simon committed
86
87
88
89
90
      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"; }
91

92
93
94
      template<typename G>
      static std::string name(G) 
      { 
95
        return std::string(typeid(G).name());
96
      }
97

98
      BadArithmeticExpression(std::string m, std::string value) 
Praetorius, Simon's avatar
Praetorius, Simon committed
99
100
      : std::runtime_error("cannot evaluate expression '" + value + "' into <" + name(T()) + ">\n"
			   "Parser message: '" + m + "'")
101
102
      {}
    };
Praetorius, Simon's avatar
Praetorius, Simon committed
103
104
      
    ///_________________________________________________________________________________________
105

106
107
    /// return the delimiter or throw an exception if there is no known 
    /// delimiter in value
108
109
110
    inline size_t checkDelim(const std::string& value, const std::string& delims)
    {
      size_t pos(std::string::npos);
Praetorius, Simon's avatar
Praetorius, Simon committed
111
      for (size_t i = 0; i < delims.length(); i++) {
112
113
114
        pos = value.find(delims[i]);
        if (pos != std::string::npos)
          return i;
115
      }
Thomas Witkowski's avatar
Thomas Witkowski committed
116
      //      throw NoDelim("cannot detect the delimiter in " + value);
117
118
119
120
121
122
123
124
125
126
127
128
129
130
      return 0; 
    }


    /// 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 , 
131
132
        typename boost::enable_if<boost::is_pod<T> >::type* p = NULL , 
        typename boost::disable_if<boost::is_enum<T> >::type* p2 = NULL)
133
134
135
136
137
138
139
    {
      using boost::lexical_cast;
      using boost::numeric_cast;

      mu::Parser parser;
      parser.DefineConst(_T("M_PI"), m_pi);
      parser.DefineConst(_T("M_E"), m_e);
140

Thomas Witkowski's avatar
Thomas Witkowski committed
141
      //      try {
142
143
        parser.SetExpr(valStr);
        value = numeric_cast< T >(parser.Eval());
Thomas Witkowski's avatar
Thomas Witkowski committed
144
145
146
147
148
149
150
/*       } 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); */
/*       } */
151
152
153
154
155
    }


    template<typename T>
    inline void convert(const std::string valStr, T& value, 
156
        typename boost::enable_if< boost::is_enum< T > >::type* p = NULL) 
157
    {
158
      int swap = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
159
      //      try {
160
        swap = boost::lexical_cast<int>(trim(valStr));
Thomas Witkowski's avatar
Thomas Witkowski committed
161
162
163
/*       } catch (boost::bad_lexical_cast e) { */
/*         throw WrongValueFormat< T >(valStr); */
/*       } */
164
165
166
167
      value = static_cast< T >(swap);
    }


168
169
170
171
172
173
174
175
176
177
178
179
    /// convert special enums
    inline void convert(const std::string valStr, Norm& value) 
    {
      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's avatar
Praetorius, Simon committed
180
        int swap = 0;
181
182
183
184
185
186
        convert(valStr, swap);
        value = static_cast< Norm >(swap);
      }
    }


Naumann, Andreas's avatar
Naumann, Andreas committed
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
    /// 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.precision(6);
      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);
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
209
210
211
212
213
214
215
216
217
    template< typename T >
    inline void convert(const std::string valStr, WorldVector<T>& c);

    template<typename T>
    inline void convert(const std::string valStr, std::list<T>& value);

    template<typename T>
    inline void convert(const std::string valStr, std::vector<T>& value);

Naumann, Andreas's avatar
Naumann, Andreas committed
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
    /** 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 + "'"); */
      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);
        }
      }
    }


269
270
271
272
273
274
    /// 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);
Thomas Witkowski's avatar
Thomas Witkowski committed
275
276
/*       if (static_cast<int>(temp_vec.size()) != c.getSize()) */
/*         throw WrongVectorSize("wrong number of entries for WorldVector"); */
277
  
Praetorius, Simon's avatar
Praetorius, Simon committed
278
      for (size_t i = 0; i < temp_vec.size(); i++)
279
        c[i] = temp_vec[i];
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
    }

    /// 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's avatar
Praetorius, Simon committed
298
  } // end namespace details
Praetorius, Simon's avatar
Praetorius, Simon committed
299

Praetorius, Simon's avatar
Praetorius, Simon committed
300
  ///_________________________________________________________________________________________
Praetorius, Simon's avatar
Praetorius, Simon committed
301

302
303
304
305
  /** 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
  */
306
307
308
309
310
311
  struct InitEntry {
    ///the value as string
    std::string valStr;

    /// initialize with value as string
    InitEntry(std::string v = "")
312
    : valStr(v) 
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
    {}

    /// 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;
  }

Praetorius, Simon's avatar
Praetorius, Simon committed
355
  ///_________________________________________________________________________________________
356

357
358
359
  /** Basis data container as a map of tag on a value as strings. The container 
  *  throws an exception, if the tag was not found.
  */
360
361
362
363
  struct Initfile : public std::map<std::string, std::string> 
  {
    typedef std::map< std::string, std::string > super;

364
365
    static const int TAG_NOT_FOUND = 1;
    static const int TAG_NOT_FOUND_BREAK = 2;
366

367
    /// Exceptions
Praetorius, Simon's avatar
Praetorius, Simon committed
368
    struct TagNotFound : std::invalid_argument {
369
      TagNotFound(std::string m) 
370
      : std::invalid_argument(m) 
371
372
373
      {}
    };

374
375
376

    struct TagNotFoundBreak : std::invalid_argument {
    // print 'tag not found' and exit
377
      TagNotFoundBreak(std::string m)
378
      : std::invalid_argument(m) 
379
380
      {}
    };
381
382
383
384
385
386


    /** initialize init-file from file with filename in, read data and save it 
    *  to singleton-map
    *  @param in: filename string
    */
387
388
389
390
    static void init(std::string in);

    static void init(int print, string filename, const char *flags = NULL) 
    {
391
392
393
        WARNING("Parameters::init(int,std::string,const char*) is depreciated. "
          "Use Parameters::init(std::string) instead!\n");
        init(filename);
394
    }
395
396
397
398
399
400
401
402
403
404


    /** 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 debugInfo: msgInfo for current parameter. (0..no printing,
    *    1..print missing parameter info, 2..print parameter value) [optional]
    */
405
406
407
408
409
    template<typename T>
    static void get(const std::string tag, T& value, int debugInfo = -1)
    {
      initIntern();
      if (debugInfo == -1)
410
        debugInfo = singlett->getMsgInfo();
411
412
413
414
415
      else {
	int swap(debugInfo);
	debugInfo = singlett->getMsgInfo();
	singlett->msgInfo=swap;
      }
416

417
      std::string valStr;
418
      try {
419
420
421
      int error_code = singlett->checkedGet(tag, valStr);
      if (error_code == 0) {
	valStr = trim(valStr);
Praetorius, Simon's avatar
Praetorius, Simon committed
422
	details::convert(valStr, value);
Thomas Witkowski's avatar
Thomas Witkowski committed
423
      } 
424
425
426
427
      } catch(mu::ParserError& e) {
	std::string parser_error = "Could not parse: " + tag;
	throw std::runtime_error(parser_error);
      }
Thomas Witkowski's avatar
Thomas Witkowski committed
428
429
      /*
else if(error_code == TAG_NOT_FOUND_BREAK)
430
	throw TagNotFoundBreak("required tag '" + tag + "' not found");
431
432
433
434
      else if (error_code == TAG_NOT_FOUND) {
	if (debugInfo == 2)
	  std::cout << "there is no tag '" + tag + "'" << std::endl;
      } else
Praetorius, Simon's avatar
Praetorius, Simon committed
435
	throw std::runtime_error("unknown error_code (" + boost::lexical_cast<std::string>(error_code) + ") returned for tag '" + tag + "'");
Thomas Witkowski's avatar
Thomas Witkowski committed
436
437
      */

438
439
440
      if (debugInfo == 2) {
	std::cout << "Parameter '" << tag << "'"
		  << " initialized with: " << value << std::endl;
441
      }
442
      singlett->msgInfo = debugInfo;
443
444
445
446
447
448
449
    }


    /// return InitEntry object for tag tag
    static InitEntry get(const std::string tag) 
    {
      InitEntry result;
450
451
452
453
454
455
      
      std::string valStr;
      int error_code = singlett->checkedGet(tag, valStr);
      if (error_code == 0) {
	valStr = trim(valStr);
	result = InitEntry(valStr);
Thomas Witkowski's avatar
Thomas Witkowski committed
456
457
458
459
      } 

#if 0
else if(error_code == TAG_NOT_FOUND_BREAK)
Praetorius, Simon's avatar
Praetorius, Simon committed
460
	throw TagNotFoundBreak("get(): required tag '" + tag + "' not found");
461
      else if (error_code == TAG_NOT_FOUND)
Praetorius, Simon's avatar
Praetorius, Simon committed
462
463
	throw TagNotFound("get(): there is no tag '" + tag + "'"); 
	// exception must be thrown, because an empty object would be return otherwise
464
      else
Praetorius, Simon's avatar
Praetorius, Simon committed
465
	throw std::runtime_error("get(): unknown error_code returned for tag '" + tag + "'");
Thomas Witkowski's avatar
Thomas Witkowski committed
466
467
#endif

468
469
      return result;
    }
470

471
472
473
474
475
476
477

    /// update map tag->value_old to tag->value in singleton
    template<typename T>
    static void set(const std::string tag, T& value, int debugInfo=  -1) 
    {
      initIntern();
      if (debugInfo == -1)
478
479
        debugInfo = singlett->getMsgInfo();

480
      std::string swap = "";
Praetorius, Simon's avatar
Praetorius, Simon committed
481
      details::convert(value, swap);
482
483
484
485
      (*singlett)[trim(tag)] = swap;
      // update msg parameters msgInfo, msgWait, paramInfo
      singlett->getInternalParameters();
      if (debugInfo == 2)
486
487
        std::cout << "Parameter '" << tag << "'"
                  << " set to: " << value << std::endl;
488
    }
489
490


491
492
493
494
495
496
497
    /// add map tag->value to data in singleton
    template< typename T >
    static void add(const std::string tag, T& value, int debugInfo = -1) 
    {
      set(tag, value, debugInfo);
    }

498

499
    /// rescheduling parameter
Praetorius, Simon's avatar
Praetorius, Simon committed
500
    static void readArgv(std::string parameters, int debugInfo = 2);
501

502

503
504
505
506
507
508
    /// Returns specified info level
    static int getMsgInfo() 
    { 
      return (singlett != NULL) ? singlett->msgInfo : 0; 
    }

509

510
511
512
513
514
    /// Returns specified wait value
    static int getMsgWait() 
    { 
      return (singlett != NULL) ? singlett->msgWait : 0; 
    }
515
516


517
518
519
520
521
522
    /// Checks whether parameters are initialized. if not, call init()
    static bool initialized() 
    { 
      return (singlett != NULL); 
    }

523

524
525
526
527
528
    /// return pointer to singleton
    static Initfile *getSingleton() 
    { 
      return singlett; 
    }
529
530


531
532
533
    /// print all data in singleton to std::cout
    static void printParameters();

534

535
536
537
538
539
540
    /// clear data in singleton
    static void clearData()
    {
      initIntern();
      singlett->clear();
    }
541
542


543
544
545
546
547
548
    /// save singlett-data to file with filename fn
    static void save(std::string fn)
    {
      initIntern();
      singlett->write(fn);
    }
Praetorius, Simon's avatar
Praetorius, Simon committed
549
	
550
protected:	
551
    Initfile() 
552
553
554
555
    : msgInfo(0), 
      msgWait(1), 
      paramInfo(1), 
      breakOnMissingTag(0) 
556
    {}
557
558


559
560
561
    static void initIntern() 
    {
      if (singlett == NULL)
Praetorius, Simon's avatar
Praetorius, Simon committed
562
	singlett = new Initfile;
563
    }
Praetorius, Simon's avatar
Praetorius, Simon committed
564

565

566
567
    /// list of processed files
    static std::set< std::string > fn_include_list;
Praetorius, Simon's avatar
Praetorius, Simon committed
568

569

570
571
    /// pointer to the singleton that contains the data
    static Initfile* singlett;
572
573
574
575


    /// return the value of the given tag or throws an exception if the tag 
    /// does not exist
576
    int checkedGet(const std::string& tag, std::string &valStr) const
577
578
579
    {
      super::const_iterator it = find(tag);
      if (it == end()) {
580
        if (breakOnMissingTag == 0 || msgInfo <= 2)
581
	  return TAG_NOT_FOUND;
582
        else
583
	  return TAG_NOT_FOUND_BREAK;
584
      }
585
586
      valStr = it->second;
      return 0;
587
588
    }

589
590
591
592
593
    /// 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;
594

Praetorius, Simon's avatar
Praetorius, Simon committed
595
596
    std::string variableEvaluation(const std::string& input) const;
    
597
    /** Fill the initfile from an input stream.
598
599
600
601
602
    * @param in: the stream to fill the data from.
    * Current dataformat: tag:value
    * Comment char: percent '%'
    * Include files: #include "filename" or #include <filename>
    */
603
604
605
    void read(std::istream& in);

    /// Fill the initfile from a file with filename fn
606
    void read(std::string fn, bool force = false);
607

608
    /** Write data-map to initfile
609
610
    * @param out: the stream to fill the data in.
    */
611
    void write(std::ostream& out);
Praetorius, Simon's avatar
Praetorius, Simon committed
612

613
614
    /// Write data-map to initfile with filename fn
    void write(std::string fn);
615

616
617
    /// read parameters for msgInfo, msgWait, paramInfo
    void getInternalParameters();
618

619
620
    int msgInfo, msgWait, paramInfo, breakOnMissingTag;	
  };
621
  
622
  typedef Initfile Parameters;
623

624
} // end namespace AMDiS
Praetorius, Simon's avatar
Praetorius, Simon committed
625
#endif