Initfile.h 15.5 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
      {}
    };

    template<typename T>
Praetorius, Simon's avatar
Praetorius, Simon committed
62
    struct WrongValueFormat : std::runtime_error {
63
64
      static std::string name(int) 
      { 
65
        return "int"; 
66
      }
67

68
69
      static std::string name(bool) 
      { 
70
        return "bool"; 
71
      }
72

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

78
79
      static std::string name(unsigned int) 
      { 
80
        return "unsigned int";
81
82
83
84
85
      }

      template<typename G>
      static std::string name(G) 
      { 
86
        return std::string(typeid(G).name()); 
87
      }
88

89
      WrongValueFormat(std::string value)
90
91
      : std::runtime_error(std::string("cannot convert '") + 
        value + std::string("' into <") + name(T()) + ">")
92
93
      {}
    };
Praetorius, Simon's avatar
Praetorius, Simon committed
94

95
96
97
98
    template<typename T>
    struct BadArithmeticExpression : std::runtime_error {
      static std::string name(int) 
      {
99
        return "int";
100
      }
101

102
103
      static std::string name(bool) 
      { 
104
        return "bool";
105
      }
106

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

112
113
      static std::string name(unsigned int) 
      {
114
        return "unsigned int";
115
      }
116

117
118
119
      template<typename G>
      static std::string name(G) 
      { 
120
        return std::string(typeid(G).name());
121
      }
122

123
      BadArithmeticExpression(std::string m, std::string value) 
124
125
126
      : std::runtime_error(std::string("cannot evaluate expression '") + 
        value + std::string("' into <") + name(T()) + 
        ">\nParser message: '" + m + "'") 
127
128
      {}
    };
Praetorius, Simon's avatar
Praetorius, Simon committed
129

130

131
132
133
134
135
136
137
138
139
    /// trim std::string
    inline std::string trim(const std::string& oldStr) 
    {
      std::string swap(oldStr);
      boost::algorithm::trim(swap);
      return swap;
    }


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


    /** parse an container from tag tag. The Container must have the properties:
156
157
158
    * 	- type value_type
    * 	- member function push_back
    */
159
160
    template< typename Container >
    inline void getContainer(const std::string val_, Container& c)
161
    {
162
163
164
165
166
167
168
169
170
      // 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)
171
172
        throw WrongVectorFormat("cannot convert "
            "'" + val + "' into a list. No leading bracket found!");
173
      if (val[val.length() - 1] != endBrackets[pos])
174
175
        throw WrongVectorFormat("begin and end bracket are different in"
            " value '" + val + "'");
176
177
178
179
180
      size_t oldPos = 1;
      size_t curDelim = 0;
      typedef typename Container::value_type ValueType;
      ValueType swap;
      try {
181
182
183
184
185
186
187
188
189
190
191
192
193
        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() - 1 - oldPos);
        convert(curWord, swap);
        c.push_back(swap);
194
      } catch (NoDelim nd) {
195
196
197
198
199
200
201
        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);
        }
202
203
204
205
206
207
208
209
210
211
212
213
214
215
      }
    }


    /// 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 , 
216
217
        typename boost::enable_if<boost::is_pod<T> >::type* p = NULL , 
        typename boost::disable_if<boost::is_enum<T> >::type* p2 = NULL)
218
219
220
221
222
223
224
    {
      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);
225

226
      try {
227
228
229
230
231
232
        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);
233
      } catch (mu::Parser::exception_type &e) {
234
        throw BadArithmeticExpression<T>(e.GetMsg(), valStr);
235
236
237
238
239
240
      }
    }


    template<typename T>
    inline void convert(const std::string valStr, T& value, 
241
        typename boost::enable_if< boost::is_enum< T > >::type* p = NULL) 
242
    {
243
      int swap = 0;
244
      try {
245
246
247
        swap = boost::lexical_cast<int>(trim(valStr));
      } catch (boost::bad_lexical_cast e) {
        throw WrongValueFormat< T >(valStr);
248
249
250
251
252
      }
      value = static_cast< T >(swap);
    }


253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
    /// 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);
      }
    }


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


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


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


    /// 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++)
320
        temp_vec[i] = c[i];
321
322
      convert(temp_vec, valStr);
    }
323
  } // end namespace InitfileInternal
Praetorius, Simon's avatar
Praetorius, Simon committed
324
325


326
327
328
329
  /** 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
  */
330
331
332
333
334
335
  struct InitEntry {
    ///the value as string
    std::string valStr;

    /// initialize with value as string
    InitEntry(std::string v = "")
336
    : valStr(v) 
337
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
372
373
374
375
376
377
378
379
    {}

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


380
381
382
  /** Basis data container as a map of tag on a value as strings. The container 
  *  throws an exception, if the tag was not found.
  */
383
384
385
386
  struct Initfile : public std::map<std::string, std::string> 
  {
    typedef std::map< std::string, std::string > super;

387

388
    /// Exceptions
Praetorius, Simon's avatar
Praetorius, Simon committed
389
    struct TagNotFound : std::invalid_argument {
390
      TagNotFound(std::string m) 
391
      : std::invalid_argument(m) 
392
393
394
      {}
    };

395
396
397

    struct TagNotFoundBreak : std::invalid_argument {
    // print 'tag not found' and exit
398
      TagNotFoundBreak(std::string m)
399
      : std::invalid_argument(m) 
400
401
      {}
    };
402
403
404
405
406
407


    /** initialize init-file from file with filename in, read data and save it 
    *  to singleton-map
    *  @param in: filename string
    */
408
409
410
411
    static void init(std::string in);

    static void init(int print, string filename, const char *flags = NULL) 
    {
412
413
414
        WARNING("Parameters::init(int,std::string,const char*) is depreciated. "
          "Use Parameters::init(std::string) instead!\n");
        init(filename);
415
    }
416
417
418
419
420
421
422
423
424
425


    /** 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]
    */
426
427
428
429
430
431
    template<typename T>
    static void get(const std::string tag, T& value, int debugInfo = -1)
    {
      using namespace InitfileInternal;
      initIntern();
      if (debugInfo == -1)
432
433
        debugInfo = singlett->getMsgInfo();

434
      try {
435
436
437
438
439
440
441
        std::string valStr(singlett->checkedGet(tag));
        valStr = trim(valStr);
        convert(valStr, value);
        if (debugInfo == 2) {
          std::cout << "Parameter '" << tag << "'"
                    << " initialized with: " << value << std::endl;
        }
442
      } catch (TagNotFound ia) {
443
444
        if (debugInfo >= 1)
          std::cout << ia.what() << std::endl;
445
446
447
448
449
450
451
452
453
454
455
      }
    }


    /// return InitEntry object for tag tag
    static InitEntry get(const std::string tag) 
    {
      using namespace InitfileInternal;
      int debugInfo = singlett->getMsgInfo();
      InitEntry result;
      try {
456
457
458
        std::string valStr(singlett->checkedGet(tag));
        valStr = trim(valStr);
        result = InitEntry(valStr);
459
      } catch (TagNotFound ia) {
460
461
        if (debugInfo >= 1)
          std::cout << ia.what() << std::endl;
462
463
464
      }
      return result;
    }
465

466
467
468
469
470
471
472
473

    /// 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)
474
475
        debugInfo = singlett->getMsgInfo();

476
477
478
479
480
481
      std::string swap = "";
      convert(value, swap);
      (*singlett)[trim(tag)] = swap;
      // update msg parameters msgInfo, msgWait, paramInfo
      singlett->getInternalParameters();
      if (debugInfo == 2)
482
483
        std::cout << "Parameter '" << tag << "'"
                  << " set to: " << value << std::endl;
484
    }
485
486


487
488
489
490
491
492
493
    /// 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);
    }

494

495
    /// rescheduling parameter
496
497
    static void readArgv(int argc, char **argv);

498

499
500
501
502
503
504
    /// Returns specified info level
    static int getMsgInfo() 
    { 
      return (singlett != NULL) ? singlett->msgInfo : 0; 
    }

505

506
507
508
509
510
    /// Returns specified wait value
    static int getMsgWait() 
    { 
      return (singlett != NULL) ? singlett->msgWait : 0; 
    }
511
512


513
514
515
516
517
518
    /// Checks whether parameters are initialized. if not, call init()
    static bool initialized() 
    { 
      return (singlett != NULL); 
    }

519

520
521
522
523
524
    /// return pointer to singleton
    static Initfile *getSingleton() 
    { 
      return singlett; 
    }
525
526


527
528
529
    /// print all data in singleton to std::cout
    static void printParameters();

530

531
532
533
534
535
536
    /// clear data in singleton
    static void clearData()
    {
      initIntern();
      singlett->clear();
    }
537
538


539
540
541
542
543
544
    /// 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
545
	
546
protected:	
547
    Initfile() 
548
549
550
551
    : msgInfo(0), 
      msgWait(1), 
      paramInfo(1), 
      breakOnMissingTag(0) 
552
    {}
553
554


555
556
557
    static void initIntern() 
    {
      if (singlett == NULL)
558
	      singlett = new Initfile;
559
    }
Praetorius, Simon's avatar
Praetorius, Simon committed
560

561

562
563
    /// list of processed files
    static std::set< std::string > fn_include_list;
Praetorius, Simon's avatar
Praetorius, Simon committed
564

565

566
567
    /// pointer to the singleton that contains the data
    static Initfile* singlett;
568
569
570
571


    /// return the value of the given tag or throws an exception if the tag 
    /// does not exist
572
573
574
575
    std::string checkedGet(const std::string& tag) const 
    {
      super::const_iterator it = find(tag);
      if (it == end()) {
576
577
578
579
        if (breakOnMissingTag == 0 || msgInfo <= 2)
          throw TagNotFound("there is no tag '" + tag + "'");
        else
          throw TagNotFoundBreak("required tag '" + tag + "' not found");
580
581
582
583
      }
      return it->second;
    }

584

585
    /** Fill the initfile from an input stream.
586
587
588
589
590
    * @param in: the stream to fill the data from.
    * Current dataformat: tag:value
    * Comment char: percent '%'
    * Include files: #include "filename" or #include <filename>
    */
591
592
593
594
    void read(std::istream& in);

    /// Fill the initfile from a file with filename fn
    void read(std::string fn);
595

596
    /** Write data-map to initfile
597
598
    * @param out: the stream to fill the data in.
    */
599
    void write(std::ostream& out);
Praetorius, Simon's avatar
Praetorius, Simon committed
600

601
602
    /// Write data-map to initfile with filename fn
    void write(std::string fn);
603

604
605
    /// read parameters for msgInfo, msgWait, paramInfo
    void getInternalParameters();
606

607
608
    int msgInfo, msgWait, paramInfo, breakOnMissingTag;	
  };
609
  
610
  typedef Initfile Parameters;
611

612
} // end namespace AMDiS
Praetorius, Simon's avatar
Praetorius, Simon committed
613
#endif