Initfile.h 16.4 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
171
172
173
174
175
176
      // 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)
177
178
        throw WrongVectorFormat("cannot convert "
            "'" + val + "' into a list. No leading bracket found!");
179
      if (val[val.length() - 1] != endBrackets[pos])
180
181
        throw WrongVectorFormat("begin and end bracket are different in"
            " value '" + val + "'");
182
183
184
185
186
      size_t oldPos = 1;
      size_t curDelim = 0;
      typedef typename Container::value_type ValueType;
      ValueType swap;
      try {
187
188
189
190
191
192
193
194
195
196
197
198
199
        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);
200
      } catch (NoDelim nd) {
201
202
203
204
205
206
207
        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);
        }
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
441
        debugInfo = singlett->getMsgInfo();

442
443
444
445
446
447
448
449
450
451
452
453
454
      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");
      else if (error_code == TAG_NOT_FOUND && debugInfo == 2)
	std::cout << "there is no tag '" + tag + "'" << std::endl;
      
      if (debugInfo == 2) {
	std::cout << "Parameter '" << tag << "'"
		  << " initialized with: " << value << std::endl;
455
456
457
458
459
460
461
462
      }
    }


    /// return InitEntry object for tag tag
    static InitEntry get(const std::string tag) 
    {
      using namespace InitfileInternal;
463
      singlett->getMsgInfo();
464
      InitEntry result;
465
466
467
468
469
470
471
472
473
474
475
      
      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
	
476
477
      return result;
    }
478

479
480
481
482
483
484
485
486

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

489
490
491
492
493
494
      std::string swap = "";
      convert(value, swap);
      (*singlett)[trim(tag)] = swap;
      // update msg parameters msgInfo, msgWait, paramInfo
      singlett->getInternalParameters();
      if (debugInfo == 2)
495
496
        std::cout << "Parameter '" << tag << "'"
                  << " set to: " << value << std::endl;
497
    }
498
499


500
501
502
503
504
505
506
    /// 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);
    }

507

508
    /// rescheduling parameter
509
510
    static void readArgv(int argc, char **argv);

511

512
513
514
515
516
517
    /// Returns specified info level
    static int getMsgInfo() 
    { 
      return (singlett != NULL) ? singlett->msgInfo : 0; 
    }

518

519
520
521
522
523
    /// Returns specified wait value
    static int getMsgWait() 
    { 
      return (singlett != NULL) ? singlett->msgWait : 0; 
    }
524
525


526
527
528
529
530
531
    /// Checks whether parameters are initialized. if not, call init()
    static bool initialized() 
    { 
      return (singlett != NULL); 
    }

532

533
534
535
536
537
    /// return pointer to singleton
    static Initfile *getSingleton() 
    { 
      return singlett; 
    }
538
539


540
541
542
    /// print all data in singleton to std::cout
    static void printParameters();

543

544
545
546
547
548
549
    /// clear data in singleton
    static void clearData()
    {
      initIntern();
      singlett->clear();
    }
550
551


552
553
554
555
556
557
    /// 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
558
	
559
protected:	
560
    Initfile() 
561
562
563
564
    : msgInfo(0), 
      msgWait(1), 
      paramInfo(1), 
      breakOnMissingTag(0) 
565
    {}
566
567


568
569
570
    static void initIntern() 
    {
      if (singlett == NULL)
571
	      singlett = new Initfile;
572
    }
Praetorius, Simon's avatar
Praetorius, Simon committed
573

574

575
576
    /// list of processed files
    static std::set< std::string > fn_include_list;
Praetorius, Simon's avatar
Praetorius, Simon committed
577

578

579
580
    /// pointer to the singleton that contains the data
    static Initfile* singlett;
581
582
583
584


    /// return the value of the given tag or throws an exception if the tag 
    /// does not exist
585
    int checkedGet(const std::string& tag, std::string &valStr) const
586
587
588
    {
      super::const_iterator it = find(tag);
      if (it == end()) {
589
        if (breakOnMissingTag == 0 || msgInfo <= 2)
590
	  return TAG_NOT_FOUND;
591
        else
592
	  return TAG_NOT_FOUND_BREAK;
593
      }
594
595
596
      valStr = it->second;

      return 0;
597
598
    }

599
600
601
602
603
    /// 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;
604

605
    /** Fill the initfile from an input stream.
606
607
608
609
610
    * @param in: the stream to fill the data from.
    * Current dataformat: tag:value
    * Comment char: percent '%'
    * Include files: #include "filename" or #include <filename>
    */
611
612
613
    void read(std::istream& in);

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

616
    /** Write data-map to initfile
617
618
    * @param out: the stream to fill the data in.
    */
619
    void write(std::ostream& out);
Praetorius, Simon's avatar
Praetorius, Simon committed
620

621
622
    /// Write data-map to initfile with filename fn
    void write(std::string fn);
623

624
625
    /// read parameters for msgInfo, msgWait, paramInfo
    void getInternalParameters();
626

627
628
    int msgInfo, msgWait, paramInfo, breakOnMissingTag;	
  };
629
  
630
  typedef Initfile Parameters;
631

632
} // end namespace AMDiS
Praetorius, Simon's avatar
Praetorius, Simon committed
633
#endif