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

    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
      ERROR_EXIT("Parameters::init(int,std::string,const char*) is depreciated. "
		 "Use Parameters::init(std::string) instead!\n");
414
    }
415
416
417
418
419
420
421
422
423
424


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

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


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

465
466
467
468
469
470
471
472

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

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


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

493

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

497

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

504

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


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

518

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


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

529

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


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


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

560

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

564

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


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

583
584
585
586
587
    /// 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;
588

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

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

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

605
606
    /// Write data-map to initfile with filename fn
    void write(std::string fn);
607

608
609
    /// read parameters for msgInfo, msgWait, paramInfo
    void getInternalParameters();
610

611
612
    int msgInfo, msgWait, paramInfo, breakOnMissingTag;	
  };
613
  
614
  typedef Initfile Parameters;
615

616
} // end namespace AMDiS
Praetorius, Simon's avatar
Praetorius, Simon committed
617
#endif