Initfile.h 19.1 KB
Newer Older
1
2
3
4
5
6
7
/******************************************************************************
 *
 * AMDiS - Adaptive multidimensional simulations
 *
 * Copyright (C) 2013 Dresden University of Technology. All Rights Reserved.
 * Web: https://fusionforge.zih.tu-dresden.de/projects/amdis
 *
8
 * Authors:
9
10
11
12
13
14
15
16
17
 * Simon Vey, Thomas Witkowski, Andreas Naumann, Simon Praetorius, et al.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 *
 * This file is part of AMDiS
 *
 * See also license.opensource.txt in the distribution.
18
 *
19
 ******************************************************************************/
20

Praetorius, Simon's avatar
Praetorius, Simon committed
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#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"

36
37
#include "traits/size.hpp"

Praetorius, Simon's avatar
Praetorius, Simon committed
38
#include <boost/lexical_cast.hpp>
39
#include <boost/numeric/conversion/cast.hpp>
40
#include <boost/thread/shared_mutex.hpp> // requires c++14
41

42
#include <boost/type_traits.hpp>
Praetorius, Simon's avatar
Praetorius, Simon committed
43

44
45
namespace AMDiS {

46
  namespace detail {
47

48
49
    // Exceptions
    //_________________________________________________________________________________________
50

51
    /// Exception for wrong vector size when parsing for concrete vector type
Praetorius, Simon's avatar
Praetorius, Simon committed
52
    struct WrongVectorSize : std::runtime_error {
Praetorius, Simon's avatar
Praetorius, Simon committed
53
      WrongVectorSize(std::string m) : std::runtime_error(m) {}
54
55
    };

56

57
    /// Exception for no delimiter found in vector
Praetorius, Simon's avatar
Praetorius, Simon committed
58
    struct NoDelim : std::runtime_error {
Praetorius, Simon's avatar
Praetorius, Simon committed
59
      NoDelim(std::string m) : std::runtime_error(m) {}
60
61
    };

62

63
    /// Exception for begin and end brackets are different in vector
Praetorius, Simon's avatar
Praetorius, Simon committed
64
    struct WrongVectorFormat : std::runtime_error {
Praetorius, Simon's avatar
Praetorius, Simon committed
65
      WrongVectorFormat(std::string m) : std::runtime_error(m) {}
66
    };
67
68


69
    /// Exception for wrong value format
70
    template<typename T>
71
72
    struct WrongValueFormat : std::runtime_error
    {
Praetorius, Simon's avatar
Praetorius, Simon committed
73
74
75
76
77
      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"; }
78
79

      template<typename G>
80
81
82
      static std::string name(G)
      {
        return std::string(typeid(G).name());
83
      }
84

85
      WrongValueFormat(std::string value)
Praetorius, Simon's avatar
Praetorius, Simon committed
86
      : std::runtime_error("cannot convert '" + value + "' into <" + name(T()) + ">")
87
88
      {}
    };
89

Praetorius, Simon's avatar
Praetorius, Simon committed
90

91
    /// Exception for bad arithmetic expression that can not be evaluated
92
    template<typename T>
93
    struct BadArithmeticExpression : std::runtime_error
94
    {
Praetorius, Simon's avatar
Praetorius, Simon committed
95
96
97
98
99
      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"; }
100

101
      template<typename G>
102
103
      static std::string name(G)
      {
104
        return std::string(typeid(G).name());
105
      }
106

107
      BadArithmeticExpression(std::string m, std::string value)
Praetorius, Simon's avatar
Praetorius, Simon committed
108
109
      : std::runtime_error("cannot evaluate expression '" + value + "' into <" + name(T()) + ">\n"
			   "Parser message: '" + m + "'")
110
111
      {}
    };
112

113
// _____________________________________________________________________________
114

115
    /// return the delimiter or throw an exception if there is no known
116
    /// delimiter in value
117
118
119
    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
120
      for (size_t i = 0; i < delims.length(); i++) {
121
122
123
        pos = value.find(delims[i]);
        if (pos != std::string::npos)
          return i;
124
      }
Thomas Witkowski's avatar
Thomas Witkowski committed
125
      //      throw NoDelim("cannot detect the delimiter in " + value);
126
      return 0;
127
    }
128
129


130
    double mu_parser_eval(std::string const& valStr);
131
132
133


    /// convert string to string
134
    inline void convert(const std::string& valStr, std::string& value)
135
136
137
138
139
140
    {
      value = trim(valStr);
    }


    /// convert string to intrinsic type
141
142
143
    template<typename T> inline
    typename boost::enable_if
	     < boost::mpl::and_
144
145
	       < boost::is_pod<T>,
	         boost::mpl::not_< boost::is_enum<T> > >,
146
147
	       void
	     >::type
148
    convert(const std::string& valStr, T& value)
149
150
151
152
    {
      using boost::lexical_cast;
      using boost::numeric_cast;

153
      value = numeric_cast< T >(mu_parser_eval(valStr));
Thomas Witkowski's avatar
Thomas Witkowski committed
154
155
156
157
158
159
160
/*       } 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); */
/*       } */
161
162
163
    }


164
165
    template<typename T> inline
    typename boost::enable_if
166
	     < boost::is_enum<T>,
167
168
	       void
	     >::type
169
    convert(const std::string& valStr, T& value)
170
    {
171
      int swap = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
172
      //      try {
173
        swap = boost::lexical_cast<int>(trim(valStr));
Thomas Witkowski's avatar
Thomas Witkowski committed
174
175
176
/*       } catch (boost::bad_lexical_cast e) { */
/*         throw WrongValueFormat< T >(valStr); */
/*       } */
177
178
179
180
      value = static_cast< T >(swap);
    }


181
    /// convert special enums
182
    inline void convert(const std::string& valStr, Norm& value)
183
184
185
186
187
188
189
190
191
192
    {
      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
193
        int swap = 0;
194
195
196
197
198
199
        convert(valStr, swap);
        value = static_cast< Norm >(swap);
      }
    }


200
    /// convert value of arbitrary type to string using stringstream and
Naumann, Andreas's avatar
Naumann, Andreas committed
201
202
    /// operator<< for type
    template<typename T>
203
    inline void convert(const T& value, std::string& valStr)
Naumann, Andreas's avatar
Naumann, Andreas committed
204
205
206
207
208
209
210
211
212
    {
      std::stringstream ss;
      ss.precision(6);
      ss << value;
      valStr = ss.str();
    }


    /// convert WorldVector to string
213
214
    // TODO: allgemeine Funktion zum Schreiben von Vektoren implementieren
    //       unter Ausnutzung von Type-Traits
Naumann, Andreas's avatar
Naumann, Andreas committed
215
216
217
    template<typename T>
    inline void convert(const WorldVector<T>& c, std::string& valStr)
    {
218
219
      std::vector<T> temp_vec(size(c));
      for (unsigned i = 0; i < size(temp_vec); i++)
Naumann, Andreas's avatar
Naumann, Andreas committed
220
221
222
223
        temp_vec[i] = c[i];
      convert(temp_vec, valStr);
    }

224
    // forward declarations
Thomas Witkowski's avatar
Thomas Witkowski committed
225
    template< typename T >
226
    inline void convert(const std::string& valStr, WorldVector<T>& c);
Thomas Witkowski's avatar
Thomas Witkowski committed
227
228

    template<typename T>
229
    inline void convert(const std::string& valStr, std::list<T>& value);
Thomas Witkowski's avatar
Thomas Witkowski committed
230
231

    template<typename T>
232
    inline void convert(const std::string& valStr, std::vector<T>& value);
Thomas Witkowski's avatar
Thomas Witkowski committed
233

Naumann, Andreas's avatar
Naumann, Andreas committed
234
235
236
237
238
    /** parse an container from tag tag. The Container must have the properties:
    * 	- type value_type
    * 	- member function push_back
    */
    template< typename Container >
239
    inline void getContainer(const std::string& val_, Container& c)
Naumann, Andreas's avatar
Naumann, Andreas committed
240
241
242
243
244
245
246
247
248
249
250
251
    {
      // accepted brackets and delimiters for vector input
      std::string begBrackets= "{[(";
      std::string endBrackets= "}])";
      std::string delims= ";,";

      c.clear();
      std::string val = trim(val_);
      bool hasBrackets = true;
      size_t pos = begBrackets.find(val[0]);
      if (pos == std::string::npos)
        hasBrackets = false;
252
253
       if (hasBrackets && val[val.length() - 1] != endBrackets[pos])
        throw WrongVectorFormat("begin and end bracket are different in"
254
            " value '" + val + "'");
Naumann, Andreas's avatar
Naumann, Andreas committed
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
      size_t oldPos = (hasBrackets ? 1 : 0);
      size_t curDelim = 0;
      typedef typename Container::value_type ValueType;
      ValueType swap;
      try {
        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() - (hasBrackets ? 1 : 0) - oldPos);
        convert(curWord, swap);
        c.push_back(swap);
      } catch (NoDelim nd) {
        std::string curWord = val.substr(oldPos, val.length() - (hasBrackets ? 2 : 0));
        curWord = trim(curWord);
        if (curWord.length() > 0) {
          // container with one entry
          convert(curWord, swap);
          c.push_back(swap);
        }
      }
    }

284
285
    // TODO: Verallgemeinerung der convert-method für bel. Vektoren und
    //       hinzunahme der Möglichkeit Matrizen anzugeben
Naumann, Andreas's avatar
Naumann, Andreas committed
286

287
288
    /// convert string to WorldVector
    template< typename T >
289
    inline void convert(const std::string& valStr, WorldVector<T>& c)
290
291
292
    {
      std::vector<T> temp_vec;
      getContainer(valStr, temp_vec);
293
       if (static_cast<int>(temp_vec.size()) != c.getSize())
294
295
        throw WrongVectorSize("wrong number of entries for WorldVector");

Praetorius, Simon's avatar
Praetorius, Simon committed
296
      for (size_t i = 0; i < temp_vec.size(); i++)
297
        c[i] = temp_vec[i];
298
299
300
301
    }

    /// convert string to std::list using begBrackets, endBrackets and delims
    template<typename T>
302
    inline void convert(const std::string& valStr, std::list<T>& value)
303
304
305
306
307
308
309
    {
      getContainer(valStr, value);
    }


    /// convert string to std::vector using begBrackets, endBrackets and delims
    template<typename T>
310
    inline void convert(const std::string& valStr, std::vector<T>& value)
311
312
313
314
315
    {
      getContainer(valStr, value);
    }


316
  } // end namespace detail
Praetorius, Simon's avatar
Praetorius, Simon committed
317

318
// _____________________________________________________________________________
Praetorius, Simon's avatar
Praetorius, Simon committed
319

320
  /** The entry in an initfile. This helper class was constructed to allow calls
321
322
323
  *  like val = data.get(tag) for arbitrary types of val. At current stage, only
  *  double and bool is supported
  */
324
325
326
327
328
329
  struct InitEntry {
    ///the value as string
    std::string valStr;

    /// initialize with value as string
    InitEntry(std::string v = "")
330
    : valStr(v)
331
332
333
334
    {}

    /// cast string to type T
    template<typename T>
335
336
337
338
    operator T() const
    {
      T t;
      detail::convert(valStr, t);
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
      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;
  }

373
// _____________________________________________________________________________
374

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

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

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

392
393
394

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


401
    /** initialize init-file from file with filename in, read data and save it
402
403
404
    *  to singleton-map
    *  @param in: filename string
    */
405
406
    static void init(std::string in);

407
    static void init(int print, std::string filename, const char *flags = NULL)
408
    {
409
410
411
        WARNING("Parameters::init(int,std::string,const char*) is depreciated. "
          "Use Parameters::init(std::string) instead!\n");
        init(filename);
412
    }
413
414


415
    /** Static get routine for getting parameter-values from init-file
416
417
418
419
420
421
422
    *  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]
    */
423
424
425
    template<typename T>
    static void get(const std::string tag, T& value, int debugInfo = -1)
    {
426
427
//       boost::shared_lock<boost::shared_mutex> lock(singlett().mutex_);
      
428
      if (debugInfo == -1)
429
        debugInfo = singlett().getMsgInfo();
430
431
      else {
	int swap(debugInfo);
432
433
	debugInfo = singlett().getMsgInfo();
	singlett().msgInfo=swap;
434
      }
435

436
      std::string valStr;
437
      try {
438
      int error_code = singlett().checkedGet(tag, valStr);
439
440
      if (error_code == 0) {
	valStr = trim(valStr);
441
	detail::convert(valStr, value);
442
      }
443
      else if(error_code == TAG_NOT_FOUND_BREAK)
444
	throw TagNotFoundBreak("required tag '" + tag + "' not found");
445
446
447
448
      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
449
	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
450

451
      } catch(...) {
452
453
454
	std::string parser_error = "Could not parse: " + tag;
	throw std::runtime_error(parser_error);
      }
455
456
457
      if (debugInfo == 2) {
	std::cout << "Parameter '" << tag << "'"
		  << " initialized with: " << value << std::endl;
458
      }
459
      singlett().msgInfo = debugInfo;
460
461
    }

462

463
    /** Static get routine for getting a parameter-map from init-file
464
    *  initialized in init()-method.
465
    *  Idea:
466
467
    *     line in Initfile: <tag><key>: <value>
    *     is extracted in am map [key]->[value].
468
    *  @param tag: The tag withch labels the parameter map
469
470
471
    *  @param debugInfo: msgInfo for current parameter. (0..no printing,
    *    2..print parameter value) [optional]
    */
472
    static void getParameterMap(const std::string tag,
473
474
475
				std::map<std::string,std::string> &pm,
				int debugInfo = -1)
    {
476
	for (Initfile::iterator it = singlett().begin(); it != singlett().end(); it++){
477
478
	    std::string longTag= (*it).first ;
	    std::string value=(*it).second;
479
	    if(longTag.length()>tag.length() &&
480
	       longTag.compare(0,tag.length(),tag)==0){
481
		if (debugInfo == 2){
482
		  std::cout <<"tag "<< tag <<"\n";
483
		  std::cout <<"Extract Parameter map from "<<(*it).first
484
			    << " => " <<(*it).second  << std::endl;
485
		}
486

487
		std::string key=trim(longTag.substr(tag.length()));
488

489
		if (debugInfo == 2){
490
		  std::cout <<"Parameter map "<< key << " => "
491
			    << value << std::endl;
492
493
494
		}
		pm[key]=value;
	    }
495
	}
496
    }
497

498
    /// return InitEntry object for tag tag
499
    static InitEntry get(const std::string tag)
500
    {
501
502
//       boost::shared_lock<boost::shared_mutex> lock(singlett().mutex_);
      
503
      InitEntry result;
504

505
      std::string valStr;
506
      int error_code = singlett().checkedGet(tag, valStr);
507
508
509
      if (error_code == 0) {
	valStr = trim(valStr);
	result = InitEntry(valStr);
510
      }
Thomas Witkowski's avatar
Thomas Witkowski committed
511
512
513

#if 0
else if(error_code == TAG_NOT_FOUND_BREAK)
514
	throw TagNotFoundBreak("get(): required tag '" + tag + "' not found");
515
      else if (error_code == TAG_NOT_FOUND)
516
	throw TagNotFound("get(): there is no tag '" + tag + "'");
Praetorius, Simon's avatar
Praetorius, Simon committed
517
	// exception must be thrown, because an empty object would be return otherwise
518
      else
519
	throw std::runtime_error("get(): unknown error_code returned for tag '" + tag + "'");
Thomas Witkowski's avatar
Thomas Witkowski committed
520
521
#endif

522
523
      return result;
    }
524

525
526
527

    /// update map tag->value_old to tag->value in singleton
    template<typename T>
528
    static void set(const std::string tag, T const& value, int debugInfo=  -1)
529
    {
530
531
//       boost::unique_lock<boost::shared_mutex> lock(singlett().mutex_);
      
532
      if (debugInfo == -1)
533
        debugInfo = singlett().getMsgInfo();
534

535
      std::string swap = "";
536
      detail::convert(value, swap);
537
      singlett()[trim(tag)] = swap;
538
      // update msg parameters msgInfo, msgWait, paramInfo
539
      singlett().getInternalParameters();
540
      if (debugInfo == 2)
541
542
        std::cout << "Parameter '" << tag << "'"
                  << " set to: " << value << std::endl;
543
    }
544
545


546
547
    /// add map tag->value to data in singleton
    template< typename T >
548
    static void add(const std::string tag, T const& value, int debugInfo = -1)
549
550
551
552
    {
      set(tag, value, debugInfo);
    }

553

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

557

558
    /// Returns specified info level
559
560
    static int getMsgInfo()
    {
561
      return singlett().msgInfo;
562
563
    }

564

565
    /// Returns specified wait value
566
567
    static int getMsgWait()
    {
568
      return singlett().msgWait;
569
    }
570
571


572
573
574
    /// print all data in singleton to std::cout
    static void printParameters();

575

576
577
578
    /// clear data in singleton
    static void clearData()
    {
579
      singlett().clear();
580
    }
581
    
582

583
584
585
    /// save singlett-data to file with filename fn
    static void save(std::string fn)
    {
586
      singlett().write(fn);
587
    }
588
    
589

590
591
592
593
594
    // list of included filenames
    static std::set< std::string >& getIncludeList()
    {
      static std::set< std::string > include_list;
      return include_list;
595
    }
596
    
597
598
599
600
601
602
protected:
    Initfile()
    : msgInfo(0),
      msgWait(1),
      paramInfo(1),
      breakOnMissingTag(0)
603
    {}
604

605
606
    /// return reference to singleton
    static Initfile& singlett()
607
    {
608
609
      static Initfile singlett_{};
      return singlett_;
610
    }
Praetorius, Simon's avatar
Praetorius, Simon committed
611

612

613
    /// return the value of the given tag or throws an exception if the tag
614
    /// does not exist
615
    int checkedGet(const std::string& tag, std::string &valStr) const
616
617
618
    {
      super::const_iterator it = find(tag);
      if (it == end()) {
619
        if (breakOnMissingTag == 0 || msgInfo <= 2)
620
	  return TAG_NOT_FOUND;
621
        else
622
	  return TAG_NOT_FOUND_BREAK;
623
      }
624
625
      valStr = it->second;
      return 0;
626
627
    }

628
629
630
631
632
    /// 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;
633

Praetorius, Simon's avatar
Praetorius, Simon committed
634
    std::string variableEvaluation(const std::string& input) const;
635

636
    /** Fill the initfile from an input stream.
637
638
639
640
641
    * @param in: the stream to fill the data from.
    * Current dataformat: tag:value
    * Comment char: percent '%'
    * Include files: #include "filename" or #include <filename>
    */
642
643
644
    void read(std::istream& in);

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

647
    /** Write data-map to initfile
648
649
    * @param out: the stream to fill the data in.
    */
650
    void write(std::ostream& out);
Praetorius, Simon's avatar
Praetorius, Simon committed
651

652
653
    /// Write data-map to initfile with filename fn
    void write(std::string fn);
654

655
656
    /// read parameters for msgInfo, msgWait, paramInfo
    void getInternalParameters();
657

658
    int msgInfo, msgWait, paramInfo, breakOnMissingTag;
659
660
    
//     mutable boost::shared_mutex mutex_;
661
  };
662

663
  typedef Initfile Parameters;
664

665
} // end namespace AMDiS
Praetorius, Simon's avatar
Praetorius, Simon committed
666
#endif