Initfile.h 16.6 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
37
namespace AMDiS {

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

46

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

53

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

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

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

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

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

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

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

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

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

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

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

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

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

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


    /** parse an container from tag tag. The Container must have the properties:
152
153
154
    * 	- type value_type
    * 	- member function push_back
    */
155
156
    template< typename Container >
    inline void getContainer(const std::string val_, Container& c)
157
    {
158
159
160
      // accepted brackets and delimiters for vector input
      std::string begBrackets= "{[(";
      std::string endBrackets= "}])";
161
      std::string delims= ";,";
162
163

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


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

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


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


249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
    /// 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);
      }
    }


268
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);
      if (static_cast<int>(temp_vec.size()) != c.getSize())
275
276
        throw WrongVectorSize("wrong number of entries for WorldVector");
  
277
      for (unsigned i = 0; i < temp_vec.size(); i++)
278
        c[i] = temp_vec[i];
279
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);
    }


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


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


322
323
324
325
  /** 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
  */
326
327
328
329
330
331
  struct InitEntry {
    ///the value as string
    std::string valStr;

    /// initialize with value as string
    InitEntry(std::string v = "")
332
    : valStr(v) 
333
334
335
336
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
    {}

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


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

383
384
    static const int TAG_NOT_FOUND = 1;
    static const int TAG_NOT_FOUND_BREAK = 2;
385

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

393
394
395

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


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

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


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

437
438
439
440
441
442
443
      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");
444
445
446
447
448
      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 + "'");
449
450
451
452
      
      if (debugInfo == 2) {
	std::cout << "Parameter '" << tag << "'"
		  << " initialized with: " << value << std::endl;
453
      }
454
      singlett->msgInfo = debugInfo;
455
456
457
458
459
460
461
462
    }


    /// return InitEntry object for tag tag
    static InitEntry get(const std::string tag) 
    {
      using namespace InitfileInternal;
      InitEntry result;
463
464
465
466
467
468
469
470
471
472
      
      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
473
474
      else
	throw std::runtime_error("unknown error_code in checkedGet(...) returned for tag '" + tag + "'");
475
	
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
      valStr = it->second;
      return 0;
596
597
    }

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

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

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

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

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

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

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

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