Initfile.hpp 8.88 KB
Newer Older
1
2
#pragma once

3
#include <array>
4
5
6
#include <string>
#include <iostream>
#include <type_traits>
7
8
#include <list>
#include <vector>
9
10
11
12
13
14
15

#include <boost/lexical_cast.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/tokenizer.hpp>

#include <boost/property_tree/ptree.hpp>

16
17
#include <dune/common/fvector.hh>

18
19
#include <dune/amdis/Output.hpp>
#include <dune/amdis/Math.hpp>
20
21
22
23
24

namespace AMDiS
{
  namespace detail
  {
25
//     double mu_parser_eval(std::string const& valStr);
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

    template <class T> inline T numeric_cast(double value)
    {
      return boost::numeric_cast< T >(value);
    }

    template <> inline bool numeric_cast<bool>(double value)
    {
      return value != 0.0;
    }

    /// convert string to intrinsic type
    template <class T, class Enable = void>
    struct Convert
    {
      static void eval(std::string valStr, T& value)
      {
        value = boost::lexical_cast<T>(valStr);
      }
    };

47
48
49
50
51
52
53
54
//     template <class T>
//     struct Convert<T, std::enable_if_t<std::is_arithmetic<T>::value> >
//     {
//       static void eval(std::string valStr, T& value)
//       {
//         try {
//             value = numeric_cast< T >(mu_parser_eval(valStr));
//         } catch(...) {
55
//             error_exit("Could not parse '", valStr, "' to '", typeid(T).name(), "'\n");
56
57
58
//         }
//       }
//     };
59

60
61
62
63
64
65
66
67
//     template <class T>
//     struct Convert<T, std::enable_if_t<std::is_enum<T>::value> >
//     {
//       static void eval(std::string valStr, T& value)
//       {
//         EnumParser<T>()(valStr, value);
//       }
//     };
68

69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
//     convert string to vector
    template <class V, int dim>
    struct Convert<Dune::FieldVector<V, dim>>
    {
      using T = Dune::FieldVector<V, dim>;
      static void eval(std::string valStr, T& values)
      {
        using value_type = typename T::value_type;
        using Tokenizer = boost::tokenizer<boost::char_separator<char>>;

        boost::char_separator<char> sep(",; ");
        Tokenizer tokens(valStr, sep);
        int i = 0;
        for (auto token : tokens)
        {
84
85
          test_exit(i < dim, "Vector data exceeds field-vector dimension!");

86
87
88
89
90
91
92
93
          value_type v;
          Convert<value_type>::eval(token, v);
          values[i++] = v;
        }
      }
    };

//     convert string to vector
94
    template <class V, std::size_t dim>
95
96
97
98
99
100
101
102
103
104
    struct Convert<std::array<V, dim>>
    {
      using T = std::array<V, dim>;
      static void eval(std::string valStr, T& values)
      {
        using value_type = typename T::value_type;
        using Tokenizer = boost::tokenizer<boost::char_separator<char>>;

        boost::char_separator<char> sep(",; ");
        Tokenizer tokens(valStr, sep);
105
        std::size_t i = 0;
106
107
        for (auto token : tokens)
        {
108
109
          test_exit(i < dim, "Vector data exceeds array dimension!");

110
111
112
113
114
115
          value_type v;
          Convert<value_type>::eval(token, v);
          values[i++] = v;
        }
      }
    };
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168

    // convert string to vector
    template <class T, class Alloc>
    struct Convert<std::vector<T, Alloc>>
    {
      static void eval(std::string valStr, std::vector<T>& values)
      {
        using value_type = T;
        using Tokenizer = boost::tokenizer<boost::char_separator<char>>;

        boost::char_separator<char> sep(",; ");
        Tokenizer tokens(valStr, sep);
        for (auto token : tokens)
        {
          value_type v;
          Convert<value_type>::eval(token, v);
          values.push_back(v);
        }
      }
    };

  } // end namespace detail


  /// output-stream for std::list
  template <class T, class Alloc>
  std::ostream& operator<<(std::ostream& out, std::list<T,Alloc> const& l)
  {
    auto it = l.begin();
    out << "["; if (l.size() > 0) out << *it;
    for (; it != l.end(); ++it)
      out << ", " << *it;
    out << "]";
    return out;
  }


  /// output-stream for std::vector
  template <class T, class Alloc>
  std::ostream& operator<<(std::ostream& out, std::vector<T,Alloc> const& l)
  {
    auto it = l.begin();
    out << "["; if (l.size() > 0) out << *it;
    for (; it != l.end(); ++it)
      out << ", " << *it;
    out << "]";
    return out;
  }

  inline void replaceAll(std::string& str, std::string const& from, std::string const& to)
  {
    if (from.empty())
      return;
169
    std::size_t start_pos = 0;
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
    while ((start_pos = str.find(from, start_pos)) != std::string::npos)
    {
      str.replace(start_pos, from.length(), to);
      start_pos += to.length();
    }
  }

  // _____________________________________________________________________________

  /** Basis data container as a map of tag on a value as strings. The container
  *  throws an exception, if the tag was not found.
  */
  struct Initfile
  {
    using Self = Initfile;

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


    /** 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]
    */
    template <class T>
    static void get(std::string tag, T& value, int debugInfo = -1)
    {
      if (debugInfo == -1)
205
        debugInfo = singlett().getMsgInfo();
206
207
208
      else
      {
        int swap(debugInfo);
209
210
        debugInfo = singlett().getMsgInfo();
        singlett().msgInfo=swap;
211
212
213
214
215
216
217
218
219
      }

      using path = boost::property_tree::ptree::path_type;
      replaceAll(tag, "->", ">");
      auto tagPath = path(tag, '>');

      // TODO: use boost::optional instead
      // TODO: use convert method from above
      std::string valueStr = "-";
220
      valueStr = singlett().pt.get(tagPath, valueStr);
221
222
223
224

      if (valueStr != "-")
        detail::Convert<T>::eval(valueStr, value);

225
226
227
228
229
//       if (debugInfo == 2)
//       {
//         std::cout << "Parameter '" << tag << "'"
//                   << " initialized with: " << value << std::endl;
//       }
230
      singlett().msgInfo = debugInfo;
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
    }


    template <class T, class S>
    static T get(std::string tag, S const& default_value)
    {
      T value = default_value;
      Self::get(tag, value);
      return value;
    }


    template <class T>
    static T get(std::string tag)
    {
      T value; nullify(value);
      Self::get(tag, value);
      return value;
    }


    /// update map tag->value_old to tag->value in singleton
    template <class T>
    static void set(std::string tag, T& value, int debugInfo=  -1)
    {
      if (debugInfo == -1)
257
        debugInfo = singlett().getMsgInfo();
258
259
260
261

      using path = boost::property_tree::ptree::path_type;
      replaceAll(tag, "->", ">");
      auto tagPath = path(tag, '>');
262
      singlett().pt.put(tagPath, value);
263
264

      // update msg parameters msgInfo, msgWait, paramInfo
265
      singlett().getInternalParameters();
266
267
268
//       if (debugInfo == 2)
//         std::cout << "Parameter '" << tag << "'"
//                   << " set to: " << value << std::endl;
269
270
271
272
273
274
275
276
277
278
279
280
281
    }


    /// add map tag->value to data in singleton
    template <class T>
    static void add(std::string tag, T& value, int debugInfo = -1)
    {
      set(tag, value, debugInfo);
    }

    /// Returns specified info level
    static int getMsgInfo()
    {
282
      return singlett().msgInfo;
283
284
285
286
287
288
289
290
291
292
    }


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


    /// clear data in singleton
    static void clearData()
    {
293
      // singlett().clear();
294
295
296
297
298
299
300
    }


    /// save singlett-data to file with filename fn
    static void save(std::string /*fn*/)
    {
      using namespace boost::property_tree;
301
      // json_parser::write_jason(fn, singlett().pt);
302
303
304
305
306
    }

  protected:
    Initfile() = default;

307
308
    /// return the singleton that contains the data
    static Initfile& singlett()
309
    {
310
311
      static Initfile initfile;
      return initfile;
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
    }

    /** Fill the initfile from an input stream.
    * @param in: the stream to fill the data from.
    * Current dataformat: tag:value
    * Comment char: percent '%'
    * Include files: #include "filename" or #include <filename>
    */
    void read(std::string fn, bool force = false);

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

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

    int msgInfo = 0;
    int paramInfo = 1;
    int breakOnMissingTag = 0;

    /// boost:property_tree to read/store parameter values
    boost::property_tree::ptree pt;
  };

  using Parameters = Initfile;

#ifndef AMDIS_NO_EXTERN_INITFILE
  extern template void Initfile::get(std::string, int&, int);
  extern template void Initfile::get(std::string, double&, int);
  extern template void Initfile::get(std::string, std::string&, int);
#endif

} // end namespace AMDiS