Initfile.h 16.8 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
28
#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>
29
30
#include <boost/numeric/conversion/cast.hpp> 

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

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

36
37
38
namespace AMDiS {

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

47

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

54

Praetorius, Simon's avatar
Praetorius, Simon committed
55
    struct WrongVectorFormat : std::runtime_error {
56
      WrongVectorFormat(std::string m) 
57
      : std::runtime_error(m) 
58
59
60
      {}
    };

61
62
63
64
65
66
    struct GetTagError : std::runtime_error {
      GetTagError(std::string m)
      : std::runtime_error(m)
      {}
    };
    
67
    template<typename T>
Praetorius, Simon's avatar
Praetorius, Simon committed
68
    struct WrongValueFormat : std::runtime_error {
69
70
      static std::string name(int) 
      { 
71
        return "int"; 
72
      }
73

74
75
      static std::string name(bool) 
      { 
76
        return "bool"; 
77
      }
78

79
80
      static std::string name(double) 
      { 
81
        return "double"; 
82
      }
83

84
85
      static std::string name(unsigned int) 
      { 
86
        return "unsigned int";
87
88
89
90
91
      }

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

95
      WrongValueFormat(std::string value)
96
97
      : std::runtime_error(std::string("cannot convert '") + 
        value + std::string("' into <") + name(T()) + ">")
98
99
      {}
    };
Praetorius, Simon's avatar
Praetorius, Simon committed
100

101
102
103
104
    template<typename T>
    struct BadArithmeticExpression : std::runtime_error {
      static std::string name(int) 
      {
105
        return "int";
106
      }
107

108
109
      static std::string name(bool) 
      { 
110
        return "bool";
111
      }
112

113
114
      static std::string name(double) 
      { 
115
        return "double";
116
      }
117

118
119
      static std::string name(unsigned int) 
      {
120
        return "unsigned int";
121
      }
122

123
124
125
      template<typename G>
      static std::string name(G) 
      { 
126
        return std::string(typeid(G).name());
127
      }
128

129
      BadArithmeticExpression(std::string m, std::string value) 
130
131
132
      : std::runtime_error(std::string("cannot evaluate expression '") + 
        value + std::string("' into <") + name(T()) + 
        ">\nParser message: '" + m + "'") 
133
134
      {}
    };
Praetorius, Simon's avatar
Praetorius, Simon committed
135

136

137
138
139
140
141
142
143
144
145
    /// trim std::string
    inline std::string trim(const std::string& oldStr) 
    {
      std::string swap(oldStr);
      boost::algorithm::trim(swap);
      return swap;
    }


146
147
    /// return the delimiter or throw an exception if there is no known 
    /// delimiter in value
148
149
150
151
    inline 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++) {
152
153
154
        pos = value.find(delims[i]);
        if (pos != std::string::npos)
          return i;
155
156
157
158
159
160
161
      }
      throw NoDelim("cannot detect the delimiter in " + value);
      return 0; 
    }


    /** parse an container from tag tag. The Container must have the properties:
162
163
164
    * 	- type value_type
    * 	- member function push_back
    */
165
166
    template< typename Container >
    inline void getContainer(const std::string val_, Container& c)
167
    {
168
169
170
      // accepted brackets and delimiters for vector input
      std::string begBrackets= "{[(";
      std::string endBrackets= "}])";
171
      std::string delims= ";,";
172
173

      c.clear();
174
175
      std::string val = trim(val_);
      bool hasBrackets = true;
176
177
      size_t pos = begBrackets.find(val[0]);
      if (pos == std::string::npos)
178
179
        hasBrackets = false;
      if (hasBrackets && val[val.length() - 1] != endBrackets[pos])
180
181
        throw WrongVectorFormat("begin and end bracket are different in"
            " value '" + val + "'");
182
      size_t oldPos = (hasBrackets ? 1 : 0);
183
184
185
186
      size_t curDelim = 0;
      typedef typename Container::value_type ValueType;
      ValueType swap;
      try {
187
188
189
190
191
192
193
194
195
196
        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
197
        std::string curWord = val.substr(oldPos, val.length() - (hasBrackets ? 1 : 0) - oldPos);
198
199
        convert(curWord, swap);
        c.push_back(swap);
200
      } catch (NoDelim nd) {
201
        std::string curWord = val.substr(oldPos, val.length() - (hasBrackets ? 2 : 0));
202
203
204
205
206
207
        curWord = trim(curWord);
        if (curWord.length() > 0) {
          // container with one entry
          convert(curWord, swap);
          c.push_back(swap);
        }
208
209
210
211
212
213
214
215
216
217
218
219
220
221
      }
    }


    /// 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 , 
222
223
        typename boost::enable_if<boost::is_pod<T> >::type* p = NULL , 
        typename boost::disable_if<boost::is_enum<T> >::type* p2 = NULL)
224
225
226
227
228
229
230
    {
      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);
231

232
      try {
233
234
235
236
237
238
        parser.SetExpr(valStr);
        value = numeric_cast< T >(parser.Eval());
      } catch (boost::bad_lexical_cast e) {
        throw WrongValueFormat< T >(valStr);
      } catch (boost::bad_numeric_cast e) {
        throw WrongValueFormat< T >(valStr);
239
      } catch (mu::Parser::exception_type &e) {
240
        throw BadArithmeticExpression<T>(e.GetMsg(), valStr);
241
242
243
244
245
246
      }
    }


    template<typename T>
    inline void convert(const std::string valStr, T& value, 
247
        typename boost::enable_if< boost::is_enum< T > >::type* p = NULL) 
248
    {
249
      int swap = 0;
250
      try {
251
252
253
        swap = boost::lexical_cast<int>(trim(valStr));
      } catch (boost::bad_lexical_cast e) {
        throw WrongValueFormat< T >(valStr);
254
255
256
257
258
      }
      value = static_cast< T >(swap);
    }


259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
    /// 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 {
        int swap= 0;
        convert(valStr, swap);
        value = static_cast< Norm >(swap);
      }
    }


278
279
280
281
282
283
284
    /// 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())
285
286
        throw WrongVectorSize("wrong number of entries for WorldVector");
  
287
      for (unsigned i = 0; i < temp_vec.size(); i++)
288
        c[i] = temp_vec[i];
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
    }


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


308
309
    /// convert value of arbitrary type to string using stringstream and 
    /// operator<< for type
310
311
312
313
    template<typename T>
    inline void convert(const T value, std::string& valStr) 
    {
      std::stringstream ss;
314
      ss.precision(6);
315
      ss << value;
316
      valStr = ss.str();
317
318
319
320
321
322
323
324
325
    }


    /// 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++)
326
        temp_vec[i] = c[i];
327
328
      convert(temp_vec, valStr);
    }
329
  } // end namespace InitfileInternal
Praetorius, Simon's avatar
Praetorius, Simon committed
330
331


332
333
334
335
  /** 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
  */
336
337
338
339
340
341
  struct InitEntry {
    ///the value as string
    std::string valStr;

    /// initialize with value as string
    InitEntry(std::string v = "")
342
    : valStr(v) 
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
372
373
374
375
376
377
378
379
380
381
382
383
384
385
    {}

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


386
387
388
  /** Basis data container as a map of tag on a value as strings. The container 
  *  throws an exception, if the tag was not found.
  */
389
390
391
392
  struct Initfile : public std::map<std::string, std::string> 
  {
    typedef std::map< std::string, std::string > super;

393
394
    static const int TAG_NOT_FOUND = 1;
    static const int TAG_NOT_FOUND_BREAK = 2;
395

396
    /// Exceptions
Praetorius, Simon's avatar
Praetorius, Simon committed
397
    struct TagNotFound : std::invalid_argument {
398
      TagNotFound(std::string m) 
399
      : std::invalid_argument(m) 
400
401
402
      {}
    };

403
404
405

    struct TagNotFoundBreak : std::invalid_argument {
    // print 'tag not found' and exit
406
      TagNotFoundBreak(std::string m)
407
      : std::invalid_argument(m) 
408
409
      {}
    };
410
411
412
413
414
415


    /** initialize init-file from file with filename in, read data and save it 
    *  to singleton-map
    *  @param in: filename string
    */
416
417
418
419
    static void init(std::string in);

    static void init(int print, string filename, const char *flags = NULL) 
    {
420
421
422
        WARNING("Parameters::init(int,std::string,const char*) is depreciated. "
          "Use Parameters::init(std::string) instead!\n");
        init(filename);
423
    }
424
425
426
427
428
429
430
431
432
433


    /** 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]
    */
434
435
436
437
438
439
    template<typename T>
    static void get(const std::string tag, T& value, int debugInfo = -1)
    {
      using namespace InitfileInternal;
      initIntern();
      if (debugInfo == -1)
440
        debugInfo = singlett->getMsgInfo();
441
442
443
444
445
      else {
	int swap(debugInfo);
	debugInfo = singlett->getMsgInfo();
	singlett->msgInfo=swap;
      }
446

447
448
449
450
451
452
453
      std::string valStr;
      int error_code = singlett->checkedGet(tag, valStr);
      if (error_code == 0) {
	valStr = trim(valStr);
	convert(valStr, value);
      } else if(error_code == TAG_NOT_FOUND_BREAK)
	throw TagNotFoundBreak("required tag '" + tag + "' not found");
454
455
456
457
458
      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) + ") in checkedGet(...) returned for tag '" + tag + "'");
459
460
461
462
      
      if (debugInfo == 2) {
	std::cout << "Parameter '" << tag << "'"
		  << " initialized with: " << value << std::endl;
463
      }
464
      singlett->msgInfo = debugInfo;
465
466
467
468
469
470
471
472
    }


    /// return InitEntry object for tag tag
    static InitEntry get(const std::string tag) 
    {
      using namespace InitfileInternal;
      InitEntry result;
473
474
475
476
477
478
479
480
481
482
      
      std::string valStr;
      int error_code = singlett->checkedGet(tag, valStr);
      if (error_code == 0) {
	valStr = trim(valStr);
	result = InitEntry(valStr);
      } else if(error_code == TAG_NOT_FOUND_BREAK)
	throw TagNotFoundBreak("required tag '" + tag + "' not found");
      else if (error_code == TAG_NOT_FOUND)
	throw TagNotFound("there is no tag '" + tag + "'"); // exception must be thrown, because an empty object would be return otherwise
483
484
      else
	throw std::runtime_error("unknown error_code in checkedGet(...) returned for tag '" + tag + "'");
485
	
486
487
      return result;
    }
488

489
490
491
492
493
494
495
496

    /// 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) 
    {
      using namespace InitfileInternal;
      initIntern();
      if (debugInfo == -1)
497
498
        debugInfo = singlett->getMsgInfo();

499
500
501
502
503
504
      std::string swap = "";
      convert(value, swap);
      (*singlett)[trim(tag)] = swap;
      // update msg parameters msgInfo, msgWait, paramInfo
      singlett->getInternalParameters();
      if (debugInfo == 2)
505
506
        std::cout << "Parameter '" << tag << "'"
                  << " set to: " << value << std::endl;
507
    }
508
509


510
511
512
513
514
515
516
    /// 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);
    }

517

518
    /// rescheduling parameter
519
520
    static void readArgv(int argc, char **argv);

521

522
523
524
525
526
527
    /// Returns specified info level
    static int getMsgInfo() 
    { 
      return (singlett != NULL) ? singlett->msgInfo : 0; 
    }

528

529
530
531
532
533
    /// Returns specified wait value
    static int getMsgWait() 
    { 
      return (singlett != NULL) ? singlett->msgWait : 0; 
    }
534
535


536
537
538
539
540
541
    /// Checks whether parameters are initialized. if not, call init()
    static bool initialized() 
    { 
      return (singlett != NULL); 
    }

542

543
544
545
546
547
    /// return pointer to singleton
    static Initfile *getSingleton() 
    { 
      return singlett; 
    }
548
549


550
551
552
    /// print all data in singleton to std::cout
    static void printParameters();

553

554
555
556
557
558
559
    /// clear data in singleton
    static void clearData()
    {
      initIntern();
      singlett->clear();
    }
560
561


562
563
564
565
566
567
    /// 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
568
	
569
protected:	
570
    Initfile() 
571
572
573
574
    : msgInfo(0), 
      msgWait(1), 
      paramInfo(1), 
      breakOnMissingTag(0) 
575
    {}
576
577


578
579
580
    static void initIntern() 
    {
      if (singlett == NULL)
581
	      singlett = new Initfile;
582
    }
Praetorius, Simon's avatar
Praetorius, Simon committed
583

584

585
586
    /// list of processed files
    static std::set< std::string > fn_include_list;
Praetorius, Simon's avatar
Praetorius, Simon committed
587

588

589
590
    /// pointer to the singleton that contains the data
    static Initfile* singlett;
591
592
593
594


    /// return the value of the given tag or throws an exception if the tag 
    /// does not exist
595
    int checkedGet(const std::string& tag, std::string &valStr) const
596
597
598
    {
      super::const_iterator it = find(tag);
      if (it == end()) {
599
        if (breakOnMissingTag == 0 || msgInfo <= 2)
600
	  return TAG_NOT_FOUND;
601
        else
602
	  return TAG_NOT_FOUND_BREAK;
603
      }
604
605
      valStr = it->second;
      return 0;
606
607
    }

608
609
610
611
612
    /// 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;
613

614
    /** Fill the initfile from an input stream.
615
616
617
618
619
    * @param in: the stream to fill the data from.
    * Current dataformat: tag:value
    * Comment char: percent '%'
    * Include files: #include "filename" or #include <filename>
    */
620
621
622
    void read(std::istream& in);

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

625
    /** Write data-map to initfile
626
627
    * @param out: the stream to fill the data in.
    */
628
    void write(std::ostream& out);
Praetorius, Simon's avatar
Praetorius, Simon committed
629

630
631
    /// Write data-map to initfile with filename fn
    void write(std::string fn);
632

633
634
    /// read parameters for msgInfo, msgWait, paramInfo
    void getInternalParameters();
635

636
637
    int msgInfo, msgWait, paramInfo, breakOnMissingTag;	
  };
638
  
639
  typedef Initfile Parameters;
640

641
} // end namespace AMDiS
Praetorius, Simon's avatar
Praetorius, Simon committed
642
#endif