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

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

46

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

51

Praetorius, Simon's avatar
Praetorius, Simon committed
52
    struct WrongVectorFormat : std::runtime_error {
Praetorius, Simon's avatar
Praetorius, Simon committed
53
      WrongVectorFormat(std::string m) : std::runtime_error(m) {}
54
55
    };

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

      template<typename G>
      static std::string name(G) 
      { 
74
        return std::string(typeid(G).name()); 
75
      }
76

77
      WrongValueFormat(std::string value)
Praetorius, Simon's avatar
Praetorius, Simon committed
78
      : std::runtime_error("cannot convert '" + value + "' into <" + name(T()) + ">")
79
80
      {}
    };
Praetorius, Simon's avatar
Praetorius, Simon committed
81
    
Praetorius, Simon's avatar
Praetorius, Simon committed
82

83
84
    template<typename T>
    struct BadArithmeticExpression : std::runtime_error {
85

Praetorius, Simon's avatar
Praetorius, Simon committed
86
87
88
89
90
      static std::string name(bool) { return "bool"; }
      static std::string name(double) { return "double"; }
      static std::string name(float) { return "float"; }
      static std::string name(int) { return "int"; }
      static std::string name(unsigned int) { return "unsigned int"; }
91

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

98
      BadArithmeticExpression(std::string m, std::string value) 
Praetorius, Simon's avatar
Praetorius, Simon committed
99
100
      : std::runtime_error("cannot evaluate expression '" + value + "' into <" + name(T()) + ">\n"
			   "Parser message: '" + m + "'")
101
102
      {}
    };
Praetorius, Simon's avatar
Praetorius, Simon committed
103
104
      
    ///_________________________________________________________________________________________
105

106
107
    /// return the delimiter or throw an exception if there is no known 
    /// delimiter in value
108
109
110
    inline size_t checkDelim(const std::string& value, const std::string& delims)
    {
      size_t pos(std::string::npos);
Praetorius, Simon's avatar
Praetorius, Simon committed
111
      for (size_t i = 0; i < delims.length(); i++) {
112
113
114
        pos = value.find(delims[i]);
        if (pos != std::string::npos)
          return i;
115
      }
Thomas Witkowski's avatar
Thomas Witkowski committed
116
      //      throw NoDelim("cannot detect the delimiter in " + value);
117
118
119
120
121
      return 0; 
    }


    /** parse an container from tag tag. The Container must have the properties:
122
123
124
    * 	- type value_type
    * 	- member function push_back
    */
125
126
    template< typename Container >
    inline void getContainer(const std::string val_, Container& c)
127
    {
128
129
130
      // accepted brackets and delimiters for vector input
      std::string begBrackets= "{[(";
      std::string endBrackets= "}])";
131
      std::string delims= ";,";
132
133

      c.clear();
134
135
      std::string val = trim(val_);
      bool hasBrackets = true;
136
137
      size_t pos = begBrackets.find(val[0]);
      if (pos == std::string::npos)
138
        hasBrackets = false;
Thomas Witkowski's avatar
Thomas Witkowski committed
139
140
141
/*       if (hasBrackets && val[val.length() - 1] != endBrackets[pos]) */
/*         throw WrongVectorFormat("begin and end bracket are different in" */
/*             " value '" + val + "'"); */
142
      size_t oldPos = (hasBrackets ? 1 : 0);
143
144
145
146
      size_t curDelim = 0;
      typedef typename Container::value_type ValueType;
      ValueType swap;
      try {
147
148
149
150
151
152
153
154
155
156
        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
157
        std::string curWord = val.substr(oldPos, val.length() - (hasBrackets ? 1 : 0) - oldPos);
158
159
        convert(curWord, swap);
        c.push_back(swap);
160
      } catch (NoDelim nd) {
161
        std::string curWord = val.substr(oldPos, val.length() - (hasBrackets ? 2 : 0));
162
163
164
165
166
167
        curWord = trim(curWord);
        if (curWord.length() > 0) {
          // container with one entry
          convert(curWord, swap);
          c.push_back(swap);
        }
168
169
170
171
172
173
174
175
176
177
178
179
180
181
      }
    }


    /// 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 , 
182
183
        typename boost::enable_if<boost::is_pod<T> >::type* p = NULL , 
        typename boost::disable_if<boost::is_enum<T> >::type* p2 = NULL)
184
185
186
187
188
189
190
    {
      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);
191

Thomas Witkowski's avatar
Thomas Witkowski committed
192
      //      try {
193
194
        parser.SetExpr(valStr);
        value = numeric_cast< T >(parser.Eval());
Thomas Witkowski's avatar
Thomas Witkowski committed
195
196
197
198
199
200
201
/*       } catch (boost::bad_lexical_cast e) { */
/*         throw WrongValueFormat< T >(valStr); */
/*       } catch (boost::bad_numeric_cast e) { */
/*         throw WrongValueFormat< T >(valStr); */
/*       } catch (mu::Parser::exception_type &e) { */
/*         throw BadArithmeticExpression<T>(e.GetMsg(), valStr); */
/*       } */
202
203
204
205
206
    }


    template<typename T>
    inline void convert(const std::string valStr, T& value, 
207
        typename boost::enable_if< boost::is_enum< T > >::type* p = NULL) 
208
    {
209
      int swap = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
210
      //      try {
211
        swap = boost::lexical_cast<int>(trim(valStr));
Thomas Witkowski's avatar
Thomas Witkowski committed
212
213
214
/*       } catch (boost::bad_lexical_cast e) { */
/*         throw WrongValueFormat< T >(valStr); */
/*       } */
215
216
217
218
      value = static_cast< T >(swap);
    }


219
220
221
222
223
224
225
226
227
228
229
230
    /// 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 {
Praetorius, Simon's avatar
Praetorius, Simon committed
231
        int swap = 0;
232
233
234
235
236
237
        convert(valStr, swap);
        value = static_cast< Norm >(swap);
      }
    }


238
239
240
241
242
243
    /// 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);
Thomas Witkowski's avatar
Thomas Witkowski committed
244
245
/*       if (static_cast<int>(temp_vec.size()) != c.getSize()) */
/*         throw WrongVectorSize("wrong number of entries for WorldVector"); */
246
  
Praetorius, Simon's avatar
Praetorius, Simon committed
247
      for (size_t i = 0; i < temp_vec.size(); i++)
248
        c[i] = temp_vec[i];
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
    }


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


268
269
    /// convert value of arbitrary type to string using stringstream and 
    /// operator<< for type
270
271
272
273
    template<typename T>
    inline void convert(const T value, std::string& valStr) 
    {
      std::stringstream ss;
274
      ss.precision(6);
275
      ss << value;
276
      valStr = ss.str();
277
278
279
280
281
282
283
284
285
    }


    /// 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++)
286
        temp_vec[i] = c[i];
287
288
      convert(temp_vec, valStr);
    }
Praetorius, Simon's avatar
Praetorius, Simon committed
289
  } // end namespace details
Praetorius, Simon's avatar
Praetorius, Simon committed
290

Praetorius, Simon's avatar
Praetorius, Simon committed
291
  ///_________________________________________________________________________________________
Praetorius, Simon's avatar
Praetorius, Simon committed
292

293
294
295
296
  /** 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
  */
297
298
299
300
301
302
  struct InitEntry {
    ///the value as string
    std::string valStr;

    /// initialize with value as string
    InitEntry(std::string v = "")
303
    : valStr(v) 
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
    {}

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

Praetorius, Simon's avatar
Praetorius, Simon committed
346
  ///_________________________________________________________________________________________
347

348
349
350
  /** Basis data container as a map of tag on a value as strings. The container 
  *  throws an exception, if the tag was not found.
  */
351
352
353
354
  struct Initfile : public std::map<std::string, std::string> 
  {
    typedef std::map< std::string, std::string > super;

355
356
    static const int TAG_NOT_FOUND = 1;
    static const int TAG_NOT_FOUND_BREAK = 2;
357

358
    /// Exceptions
Praetorius, Simon's avatar
Praetorius, Simon committed
359
    struct TagNotFound : std::invalid_argument {
360
      TagNotFound(std::string m) 
361
      : std::invalid_argument(m) 
362
363
364
      {}
    };

365
366
367

    struct TagNotFoundBreak : std::invalid_argument {
    // print 'tag not found' and exit
368
      TagNotFoundBreak(std::string m)
369
      : std::invalid_argument(m) 
370
371
      {}
    };
372
373
374
375
376
377


    /** initialize init-file from file with filename in, read data and save it 
    *  to singleton-map
    *  @param in: filename string
    */
378
379
380
381
    static void init(std::string in);

    static void init(int print, string filename, const char *flags = NULL) 
    {
382
383
384
        WARNING("Parameters::init(int,std::string,const char*) is depreciated. "
          "Use Parameters::init(std::string) instead!\n");
        init(filename);
385
    }
386
387
388
389
390
391
392
393
394
395


    /** 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]
    */
396
397
398
399
400
    template<typename T>
    static void get(const std::string tag, T& value, int debugInfo = -1)
    {
      initIntern();
      if (debugInfo == -1)
401
        debugInfo = singlett->getMsgInfo();
402
403
404
405
406
      else {
	int swap(debugInfo);
	debugInfo = singlett->getMsgInfo();
	singlett->msgInfo=swap;
      }
407

408
409
410
411
      std::string valStr;
      int error_code = singlett->checkedGet(tag, valStr);
      if (error_code == 0) {
	valStr = trim(valStr);
Praetorius, Simon's avatar
Praetorius, Simon committed
412
	details::convert(valStr, value);
Thomas Witkowski's avatar
Thomas Witkowski committed
413
414
415
      } 
      /*
else if(error_code == TAG_NOT_FOUND_BREAK)
416
	throw TagNotFoundBreak("required tag '" + tag + "' not found");
417
418
419
420
      else if (error_code == TAG_NOT_FOUND) {
	if (debugInfo == 2)
	  std::cout << "there is no tag '" + tag + "'" << std::endl;
      } else
Praetorius, Simon's avatar
Praetorius, Simon committed
421
	throw std::runtime_error("unknown error_code (" + boost::lexical_cast<std::string>(error_code) + ") returned for tag '" + tag + "'");
Thomas Witkowski's avatar
Thomas Witkowski committed
422
423
      */

424
425
426
      if (debugInfo == 2) {
	std::cout << "Parameter '" << tag << "'"
		  << " initialized with: " << value << std::endl;
427
      }
428
      singlett->msgInfo = debugInfo;
429
430
431
432
433
434
435
    }


    /// return InitEntry object for tag tag
    static InitEntry get(const std::string tag) 
    {
      InitEntry result;
436
437
438
439
440
441
      
      std::string valStr;
      int error_code = singlett->checkedGet(tag, valStr);
      if (error_code == 0) {
	valStr = trim(valStr);
	result = InitEntry(valStr);
Thomas Witkowski's avatar
Thomas Witkowski committed
442
443
444
445
      } 

#if 0
else if(error_code == TAG_NOT_FOUND_BREAK)
Praetorius, Simon's avatar
Praetorius, Simon committed
446
	throw TagNotFoundBreak("get(): required tag '" + tag + "' not found");
447
      else if (error_code == TAG_NOT_FOUND)
Praetorius, Simon's avatar
Praetorius, Simon committed
448
449
	throw TagNotFound("get(): there is no tag '" + tag + "'"); 
	// exception must be thrown, because an empty object would be return otherwise
450
      else
Praetorius, Simon's avatar
Praetorius, Simon committed
451
	throw std::runtime_error("get(): unknown error_code returned for tag '" + tag + "'");
Thomas Witkowski's avatar
Thomas Witkowski committed
452
453
#endif

454
455
      return result;
    }
456

457
458
459
460
461
462
463

    /// 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) 
    {
      initIntern();
      if (debugInfo == -1)
464
465
        debugInfo = singlett->getMsgInfo();

466
      std::string swap = "";
Praetorius, Simon's avatar
Praetorius, Simon committed
467
      details::convert(value, swap);
468
469
470
471
      (*singlett)[trim(tag)] = swap;
      // update msg parameters msgInfo, msgWait, paramInfo
      singlett->getInternalParameters();
      if (debugInfo == 2)
472
473
        std::cout << "Parameter '" << tag << "'"
                  << " set to: " << value << std::endl;
474
    }
475
476


477
478
479
480
481
482
483
    /// 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);
    }

484

485
    /// rescheduling parameter
Praetorius, Simon's avatar
Praetorius, Simon committed
486
    static void readArgv(std::string parameters, int debugInfo = 2);
487

488

489
490
491
492
493
494
    /// Returns specified info level
    static int getMsgInfo() 
    { 
      return (singlett != NULL) ? singlett->msgInfo : 0; 
    }

495

496
497
498
499
500
    /// Returns specified wait value
    static int getMsgWait() 
    { 
      return (singlett != NULL) ? singlett->msgWait : 0; 
    }
501
502


503
504
505
506
507
508
    /// Checks whether parameters are initialized. if not, call init()
    static bool initialized() 
    { 
      return (singlett != NULL); 
    }

509

510
511
512
513
514
    /// return pointer to singleton
    static Initfile *getSingleton() 
    { 
      return singlett; 
    }
515
516


517
518
519
    /// print all data in singleton to std::cout
    static void printParameters();

520

521
522
523
524
525
526
    /// clear data in singleton
    static void clearData()
    {
      initIntern();
      singlett->clear();
    }
527
528


529
530
531
532
533
534
    /// 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
535
	
536
protected:	
537
    Initfile() 
538
539
540
541
    : msgInfo(0), 
      msgWait(1), 
      paramInfo(1), 
      breakOnMissingTag(0) 
542
    {}
543
544


545
546
547
    static void initIntern() 
    {
      if (singlett == NULL)
Praetorius, Simon's avatar
Praetorius, Simon committed
548
	singlett = new Initfile;
549
    }
Praetorius, Simon's avatar
Praetorius, Simon committed
550

551

552
553
    /// list of processed files
    static std::set< std::string > fn_include_list;
Praetorius, Simon's avatar
Praetorius, Simon committed
554

555

556
557
    /// pointer to the singleton that contains the data
    static Initfile* singlett;
558
559
560
561


    /// return the value of the given tag or throws an exception if the tag 
    /// does not exist
562
    int checkedGet(const std::string& tag, std::string &valStr) const
563
564
565
    {
      super::const_iterator it = find(tag);
      if (it == end()) {
566
        if (breakOnMissingTag == 0 || msgInfo <= 2)
567
	  return TAG_NOT_FOUND;
568
        else
569
	  return TAG_NOT_FOUND_BREAK;
570
      }
571
572
      valStr = it->second;
      return 0;
573
574
    }

575
576
577
578
579
    /// 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;
580

Praetorius, Simon's avatar
Praetorius, Simon committed
581
582
    std::string variableEvaluation(const std::string& input) const;
    
583
    /** Fill the initfile from an input stream.
584
585
586
587
588
    * @param in: the stream to fill the data from.
    * Current dataformat: tag:value
    * Comment char: percent '%'
    * Include files: #include "filename" or #include <filename>
    */
589
590
591
    void read(std::istream& in);

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

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

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

602
603
    /// read parameters for msgInfo, msgWait, paramInfo
    void getInternalParameters();
604

605
606
    int msgInfo, msgWait, paramInfo, breakOnMissingTag;	
  };
607
  
608
  typedef Initfile Parameters;
609

610
} // end namespace AMDiS
Praetorius, Simon's avatar
Praetorius, Simon committed
611
#endif