Initfile.cc 8.94 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
 ******************************************************************************/
Praetorius, Simon's avatar
Praetorius, Simon committed
20 21 22 23 24 25
#include "Initfile.h"

#include <string>
#include <stdexcept>
#include <iostream>
#include <sstream>
Praetorius, Simon's avatar
Praetorius, Simon committed
26
#include<boost/tokenizer.hpp>
27

28 29 30
// a parser for arithmetic expressions
#include "muParser.h"

Praetorius, Simon's avatar
Praetorius, Simon committed
31 32
using namespace std;

33 34
namespace AMDiS {

35
  /// the small parser for the initfile. see description of
36
  /// read(Initfile&,istream&)
37
  struct Parser {
38
    Parser(const string& line)
39 40
    {
      size_t pos = line.find(':');
41
      if (pos == string::npos) {
42 43
	throw runtime_error("cannot find the delimiter ':' in line "
			    "'" + line + "'");
44
      }
45 46 47 48 49 50
      name = line.substr(0, pos);
      value = line.substr(pos + 1, line.length() - (pos + 1));

      // remove everything after the %
      pos = value.find('%');
      if (pos != string::npos)
51
        value = value.substr(0, pos);
52 53 54 55
    }
    string name;
    string value;
  };
56

57 58 59 60 61 62 63
  namespace detail
  {
    double mu_parser_eval(std::string const& valStr)
    {
      mu::Parser parser;
      parser.DefineConst(_T("M_PI"), m_pi);
      parser.DefineConst(_T("M_E"), m_e);
64

65 66 67 68
      parser.SetExpr(valStr);
      return parser.Eval();
    }
  }
69

70

71
  /// initialize singleton object and global parameters
72 73
  void Initfile::init(std::string in)
  {
74 75 76
    getIncludeList().clear();
    singlett().read(in);
    singlett().getInternalParameters();
77
  }
78 79 80


  /// Fill an initfile from a file with filename fn
81
  void Initfile::read(std::string fn, bool force)
82 83
  {
    // read file if its not parsed already
84
    if (getIncludeList().find(fn) == getIncludeList().end() || force) {
85 86
      std::ifstream inputFile;
      inputFile.open(fn.c_str(), std::ios::in);
87 88
      if (!inputFile.is_open())
	throw runtime_error("init-file '" + fn + "' cannot be opened for reading");
89

90
      getIncludeList().insert(fn);
91 92
      read(inputFile);
    }
93
  }
94 95 96


  /// Fill an initfile from an input stream
97
  void Initfile::read(istream& in)
98
  {
Naumann, Andreas's avatar
Naumann, Andreas committed
99
    //const unsigned line_length = 512;
Naumann, Andreas's avatar
Naumann, Andreas committed
100 101
    std::string swap;
    std::getline(in, swap);
102
    while (in.good() || swap.size() > 0) {
103
      std::string whitespaces = " \t\r\f\n";
104
      std::string delimiter = "\r\n";
105 106
      std::string sw(swap);
      size_t pos0 = sw.find_first_not_of(whitespaces);
107

108
      if (pos0 != std::string::npos
109
          && sw[pos0] != '%'
110 111
          && sw[pos0] != '#'
          && sw[pos0] != 0) {
112 113
        // parse line and extract map: tag->value
        Parser parser(sw);
114

115
        // add parameter to map after variable replacement
Praetorius, Simon's avatar
Praetorius, Simon committed
116 117
        std::string paramName = variableReplacement(trim(parser.name));
        std::string paramValue = variableReplacement(trim(parser.value));
Praetorius, Simon's avatar
Praetorius, Simon committed
118
        paramValue = variableEvaluation(paramValue);
119

120 121 122 123
        operator[](paramName) = paramValue;
        int info = 0;
        get("parameter information", info, 0);
        if (info >= 2)
124
          std::cout << "read [" << paramName << " => " << paramValue << "]\n";
125 126 127
      } else if (pos0 != std::string::npos &&
		 sw[pos0] == '#'  &&
		 static_cast<size_t>(sw.find("#include")) == pos0) {
128
        // include file by '#include "filename"' or '#include <filename>'
129 130 131 132 133 134
        bool forceRead = false;
        int posAdd = 1;
        if (sw[pos0 + std::string("#include").size()] == '!') {
          forceRead = true;
          posAdd++;
        }
135
        size_t pos = sw.find_first_not_of(whitespaces,
136
          pos0 + std::string("#include").size() + posAdd);
137 138 139 140 141 142 143
        size_t epos = 0;
        std::string fn =  "";
        std::stringstream errorMsg;
        switch (char c= swap[pos++]) {
          case '<':
            c= '>';
          case '\"':
144 145
            delimiter += c;
            epos = sw.find_first_of(delimiter, pos);
146 147 148 149
            fn = sw.substr(pos, epos - pos);

            if (sw[epos]!=c) {
              errorMsg << "filename in #include not terminated by " << c;
150
	      throw std::runtime_error(errorMsg.str());
151 152
            }
            break;
153 154
	default:
	  throw std::runtime_error("no filename given for #include");
155
        }
156 157


158
        read(fn, forceRead);
159
      }
160

161
      swap.clear();
Naumann, Andreas's avatar
Naumann, Andreas committed
162
      getline(in, swap);
163
    }
164
  }
165 166 167 168 169


  std::string Initfile::variableReplacement(const std::string& input) const
  {
    std::string whitespaces = " \t\r\f";
Praetorius, Simon's avatar
Praetorius, Simon committed
170
    std::string allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
171
    std::string inputSwap = input;
172 173 174
    size_t posVar = inputSwap.find_first_of('$');
    while (posVar != string::npos) {
      size_t posVarBegin, posVarEnd;
Praetorius, Simon's avatar
Praetorius, Simon committed
175
      if (inputSwap[posVar+1] == '{') {						// ${var_name}
176 177
        posVarEnd = inputSwap.find_first_of('}',posVar + 2);
        posVarBegin = posVar + 1;
Praetorius, Simon's avatar
Praetorius, Simon committed
178 179
      } else if (inputSwap[posVar+1] != '(' && inputSwap[posVar+1] != '[') {
        posVarEnd = inputSwap.find_first_not_of(allowedChars, posVar + 1);
180
        posVarBegin = posVar;
Praetorius, Simon's avatar
Praetorius, Simon committed
181 182 183
      } else {
	posVar = inputSwap.find_first_of('$',posVar+1);
	continue;
184
      }
185

186
      std::string varName = inputSwap.substr(posVarBegin + 1 , posVarEnd - posVarBegin - 1);
187

Praetorius, Simon's avatar
Praetorius, Simon committed
188

189
      // if varname is found in parameter list then replace variable by value
190
      // otherwise throw tagNotFound exception
191 192
      std::string varParam;
      int error_code = checkedGet(varName, varParam);
193 194
      if (error_code > 2)
	throw TagNotFoundBreak("required tag '" + varName + "' for variable substitution not found");
195

196 197 198
      std::string replaceName = inputSwap.substr(posVar , posVarEnd - posVar + (posVarBegin - posVar));
      inputSwap.replace(inputSwap.find(replaceName), replaceName.length(), varParam);

Praetorius, Simon's avatar
Praetorius, Simon committed
199
      posVar = inputSwap.find_first_of('$',posVarBegin);
200 201 202
    }

    return inputSwap;
203
  }
204

205

Praetorius, Simon's avatar
Praetorius, Simon committed
206 207 208 209
  std::string Initfile::variableEvaluation(const std::string& input) const
  {
    std::string whitespaces = " \t\r\f";
    std::string inputSwap = input;
Praetorius, Simon's avatar
Praetorius, Simon committed
210
    size_t posVar = inputSwap.find("$(");
Praetorius, Simon's avatar
Praetorius, Simon committed
211 212
    while (posVar != string::npos) {
      size_t posVarBegin, posVarEnd;
Praetorius, Simon's avatar
Praetorius, Simon committed
213 214
      posVarEnd = inputSwap.find_first_of(')',posVar + 2);
      posVarBegin = posVar + 1;
Praetorius, Simon's avatar
Praetorius, Simon committed
215 216 217
      std::string varName = inputSwap.substr(posVarBegin + 1 , posVarEnd - posVarBegin - 1);

      double value = 0.0;
218 219
      detail::convert(varName, value); // string -> double (using muparser)
      detail::convert(value, varName); // double -> string
Praetorius, Simon's avatar
Praetorius, Simon committed
220 221 222 223

      std::string replaceName = inputSwap.substr(posVar , posVarEnd - posVar + (posVarBegin - posVar));
      inputSwap.replace(inputSwap.find(replaceName), replaceName.length(), varName);

Praetorius, Simon's avatar
Praetorius, Simon committed
224
      posVar = inputSwap.find("$(",posVarBegin);
Praetorius, Simon's avatar
Praetorius, Simon committed
225 226 227 228
    }

    return inputSwap;
  }
229

Praetorius, Simon's avatar
Praetorius, Simon committed
230
  void Initfile::readArgv(std::string parameters, int debugInfo)
231
  {
Praetorius, Simon's avatar
Praetorius, Simon committed
232 233 234 235 236 237 238 239 240 241 242
    char seperator = ';';
    typedef boost::escaped_list_separator<char> TokenizerFunc;
    typedef boost::tokenizer<TokenizerFunc> Tokenizer;
    TokenizerFunc tokenizerFunc('\\', seperator, '\"');
    Tokenizer tok(parameters, tokenizerFunc);

    // split parameterstring by seperator ";"
    std::vector<std::string> val;
    for (Tokenizer::iterator cell = tok.begin(); cell != tok.end(); ++cell) {
      val.push_back(trim(*cell));
    }
243

Praetorius, Simon's avatar
Praetorius, Simon committed
244 245 246 247 248 249 250
    // split each parameter by ":"
    for (size_t i = 0; i < val.size(); i++) {
      int found = val[i].find_first_of(':');
      if (found != static_cast<int>(std::string::npos)) {
	std::string value = trim(val[i].substr(found+1));
	std::string key = trim(val[i].substr(0, found));
	set(key, value, debugInfo);
Praetorius, Simon's avatar
Praetorius, Simon committed
251
      }
252 253 254 255 256
    }
  }


  /// read standard values for output and information of parameter-values
257
  void Initfile::getInternalParameters()
258 259 260 261
  {
    int val = 0;
    get("level of information", val, 0);
    msgInfo = val;
262

263 264 265
    val = 1;
    get("WAIT", val, 0);
    msgWait = val;
266

267 268 269
    val = 1;
    get("parameter information", val, 0);
    paramInfo = val;
270

271 272 273 274 275 276
    val = 0;
    get("break on missing tag", val, 0);
    breakOnMissingTag = val;

    if (msgInfo == 0)
      paramInfo = 0;
277
  }
278 279 280


  /// print all parameters to std::cout
281
  void Initfile::printParameters()
282
  {
283
    for (Initfile::iterator it = singlett().begin(); it != singlett().end(); it++)
284
      std::cout << (*it).first << " => " << (*it).second << std::endl;
285
  }
286 287 288 289 290 291


  /// Write data-map to initfile
  void Initfile::write(ostream& out)
  {
    for (Initfile::iterator it = begin() ; it!=end(); it++)
292
      out << (*it).first << ": " << (*it).second << std::endl;
293 294 295 296
  }


  /// Write data-map to initfile
297
  void Initfile::write(std::string fn)
298 299 300
  {
    std::ofstream outFile;
    outFile.open(fn.c_str(), std::ios::out);
Thomas Witkowski's avatar
Thomas Witkowski committed
301 302
//     if (!outFile.is_open())
//       throw runtime_error("init-file cannot be opened for writing");
303

304 305
    write(outFile);
  }
306
} // end namespace AMDiS