Reference documentation for deal.II version 8.4.2
function_parser.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2005 - 2015 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 
17 #include <deal.II/base/function_parser.h>
18 #include <deal.II/base/utilities.h>
19 #include <deal.II/base/thread_management.h>
20 #include <deal.II/lac/vector.h>
21 #include <cmath>
22 #include <map>
23 
24 DEAL_II_DISABLE_EXTRA_DIAGNOSTICS
25 #include <boost/random.hpp>
27 
28 #ifdef DEAL_II_WITH_MUPARSER
29 DEAL_II_DISABLE_EXTRA_DIAGNOSTICS
30 #include <muParser.h>
32 #else
33 
34 
35 
36 namespace fparser
37 {
38  class FunctionParser
39  {};
40 }
41 #endif
42 
43 DEAL_II_NAMESPACE_OPEN
44 
45 
46 
47 template <int dim>
48 FunctionParser<dim>::FunctionParser(const unsigned int n_components,
49  const double initial_time)
50  :
51  Function<dim>(n_components, initial_time)
52 {}
53 
54 
55 
56 template <int dim>
58 {}
59 
60 #ifdef DEAL_II_WITH_MUPARSER
61 
62 template <int dim>
63 void FunctionParser<dim>::initialize (const std::string &variables,
64  const std::vector<std::string> &expressions,
65  const std::map<std::string, double> &constants,
66  const bool time_dependent)
67 {
68  this->fp.clear(); // this will reset all thread-local objects
69 
70  this->constants = constants;
71  this->var_names = Utilities::split_string_list(variables, ',');
72  this->expressions = expressions;
73  AssertThrow(((time_dependent)?dim+1:dim) == var_names.size(),
74  ExcMessage("Wrong number of variables"));
75 
76  // We check that the number of
77  // components of this function
78  // matches the number of components
79  // passed in as a vector of
80  // strings.
81  AssertThrow(this->n_components == expressions.size(),
82  ExcInvalidExpressionSize(this->n_components,
83  expressions.size()) );
84 
85  // Now we define how many variables
86  // we expect to read in. We
87  // distinguish between two cases:
88  // Time dependent problems, and not
89  // time dependent problems. In the
90  // first case the number of
91  // variables is given by the
92  // dimension plus one. In the other
93  // case, the number of variables is
94  // equal to the dimension. Once we
95  // parsed the variables string, if
96  // none of this is the case, then
97  // an exception is thrown.
98  if (time_dependent)
99  n_vars = dim+1;
100  else
101  n_vars = dim;
102 
103  // create a parser object for the current thread we can then query
104  // in value() and vector_value(). this is not strictly necessary
105  // because a user may never call these functions on the current
106  // thread, but it gets us error messages about wrong formulas right
107  // away
108  init_muparser ();
109 
110  // finally set the initialization bit
111  initialized = true;
112 }
113 
114 
115 
116 namespace internal
117 {
118  // convert double into int
119  int mu_round(double val)
120  {
121  return static_cast<int>(val + ((val>=0.0) ? 0.5 : -0.5) );
122  }
123 
124  double mu_if(double condition, double thenvalue, double elsevalue)
125  {
126  if (mu_round(condition))
127  return thenvalue;
128  else
129  return elsevalue;
130  }
131 
132  double mu_or(double left, double right)
133  {
134  return (mu_round(left)) || (mu_round(right));
135  }
136 
137  double mu_and(double left, double right)
138  {
139  return (mu_round(left)) && (mu_round(right));
140  }
141 
142  double mu_int(double value)
143  {
144  return static_cast<double>(mu_round(value));
145  }
146 
147  double mu_ceil(double value)
148  {
149  return ceil(value);
150  }
151 
152  double mu_floor(double value)
153  {
154  return floor(value);
155  }
156 
157  double mu_cot(double value)
158  {
159  return 1.0/tan(value);
160  }
161 
162  double mu_csc(double value)
163  {
164  return 1.0/sin(value);
165  }
166 
167  double mu_sec(double value)
168  {
169  return 1.0/cos(value);
170  }
171 
172  double mu_log(double value)
173  {
174  return log(value);
175  }
176 
177  double mu_pow(double a, double b)
178  {
179  return std::pow(a, b);
180  }
181 
182  double mu_erfc(double value)
183  {
184  return erfc(value);
185  }
186 
187  // returns a random value in the range [0,1] initializing the generator
188  // with the given seed
189  double mu_rand_seed(double seed)
190  {
191  static Threads::Mutex rand_mutex;
192  Threads::Mutex::ScopedLock lock(rand_mutex);
193 
194  static boost::random::uniform_real_distribution<> uniform_distribution(0,1);
195 
196  // for each seed an unique random number generator is created,
197  // which is initialized with the seed itself
198  static std::map<double, boost::random::mt19937> rng_map;
199 
200  if (rng_map.find(seed) == rng_map.end())
201  rng_map[seed] = boost::random::mt19937(static_cast<unsigned int>(seed));
202 
203  return uniform_distribution(rng_map[seed]);
204  }
205 
206  // returns a random value in the range [0,1]
207  double mu_rand()
208  {
209  static Threads::Mutex rand_mutex;
210  Threads::Mutex::ScopedLock lock(rand_mutex);
211  static boost::random::uniform_real_distribution<> uniform_distribution(0,1);
212  static boost::random::mt19937 rng(static_cast<unsigned long>(std::time(0)));
213  return uniform_distribution(rng);
214  }
215 
216 }
217 
218 
219 template <int dim>
221 {
222  // check that we have not already initialized the parser on the
223  // current thread, i.e., that the current function is only called
224  // once per thread
225  Assert (fp.get().size()==0, ExcInternalError());
226 
227  // initialize the objects for the current thread (fp.get() and
228  // vars.get())
229  fp.get().resize(this->n_components);
230  vars.get().resize(var_names.size());
231  for (unsigned int component=0; component<this->n_components; ++component)
232  {
233  for (std::map< std::string, double >::const_iterator constant = constants.begin();
234  constant != constants.end(); ++constant)
235  {
236  fp.get()[component].DefineConst(constant->first.c_str(), constant->second);
237  }
238 
239  for (unsigned int iv=0; iv<var_names.size(); ++iv)
240  fp.get()[component].DefineVar(var_names[iv].c_str(), &vars.get()[iv]);
241 
242  // define some compatibility functions:
243  fp.get()[component].DefineFun("if",internal::mu_if, true);
244  fp.get()[component].DefineOprt("|", internal::mu_or, 1);
245  fp.get()[component].DefineOprt("&", internal::mu_and, 2);
246  fp.get()[component].DefineFun("int", internal::mu_int, true);
247  fp.get()[component].DefineFun("ceil", internal::mu_ceil, true);
248  fp.get()[component].DefineFun("cot", internal::mu_cot, true);
249  fp.get()[component].DefineFun("csc", internal::mu_csc, true);
250  fp.get()[component].DefineFun("floor", internal::mu_floor, true);
251  fp.get()[component].DefineFun("sec", internal::mu_sec, true);
252  fp.get()[component].DefineFun("log", internal::mu_log, true);
253  fp.get()[component].DefineFun("pow", internal::mu_pow, true);
254  fp.get()[component].DefineFun("erfc", internal::mu_erfc, true);
255  fp.get()[component].DefineFun("rand_seed", internal::mu_rand_seed, true);
256  fp.get()[component].DefineFun("rand", internal::mu_rand, true);
257 
258  try
259  {
260  // muparser expects that functions have no
261  // space between the name of the function and the opening
262  // parenthesis. this is awkward because it is not backward
263  // compatible to the library we used to use before muparser
264  // (the fparser library) but also makes no real sense.
265  // consequently, in the expressions we set, remove any space
266  // we may find after function names
267  std::string transformed_expression = expressions[component];
268 
269  const char *function_names[] =
270  {
271  // functions predefined by muparser
272  "sin",
273  "cos",
274  "tan",
275  "asin",
276  "acos",
277  "atan",
278  "sinh",
279  "cosh",
280  "tanh",
281  "asinh",
282  "acosh",
283  "atanh",
284  "atan2",
285  "log2",
286  "log10",
287  "log",
288  "ln",
289  "exp",
290  "sqrt",
291  "sign",
292  "rint",
293  "abs",
294  "min",
295  "max",
296  "sum",
297  "avg",
298  // functions we define ourselves above
299  "if",
300  "int",
301  "ceil",
302  "cot",
303  "csc",
304  "floor",
305  "sec",
306  "pow",
307  "erfc",
308  "rand",
309  "rand_seed"
310  };
311  for (unsigned int f=0; f<sizeof(function_names)/sizeof(function_names[0]); ++f)
312  {
313  const std::string function_name = function_names[f];
314  const unsigned int function_name_length = function_name.size();
315 
316  std::string::size_type pos = 0;
317  while (true)
318  {
319  // try to find any occurrences of the function name
320  pos = transformed_expression.find (function_name, pos);
321  if (pos == std::string::npos)
322  break;
323 
324  // replace whitespace until there no longer is any
325  while ((pos+function_name_length<transformed_expression.size())
326  &&
327  ((transformed_expression[pos+function_name_length] == ' ')
328  ||
329  (transformed_expression[pos+function_name_length] == '\t')))
330  transformed_expression.erase (transformed_expression.begin()+pos+function_name_length);
331 
332  // move the current search position by the size of the
333  // actual function name
334  pos += function_name_length;
335  }
336  }
337 
338  // now use the transformed expression
339  fp.get()[component].SetExpr(transformed_expression);
340  }
341  catch (mu::ParserError &e)
342  {
343  std::cerr << "Message: <" << e.GetMsg() << ">\n";
344  std::cerr << "Formula: <" << e.GetExpr() << ">\n";
345  std::cerr << "Token: <" << e.GetToken() << ">\n";
346  std::cerr << "Position: <" << e.GetPos() << ">\n";
347  std::cerr << "Errc: <" << e.GetCode() << ">" << std::endl;
348  AssertThrow(false, ExcParseError(e.GetCode(), e.GetMsg().c_str()));
349  }
350  }
351 }
352 
353 
354 
355 template <int dim>
356 void FunctionParser<dim>::initialize (const std::string &vars,
357  const std::string &expression,
358  const std::map<std::string, double> &constants,
359  const bool time_dependent)
360 {
361  initialize(vars, Utilities::split_string_list(expression, ';'),
362  constants, time_dependent);
363 }
364 
365 
366 
367 template <int dim>
369  const unsigned int component) const
370 {
371  Assert (initialized==true, ExcNotInitialized());
372  Assert (component < this->n_components,
373  ExcIndexRange(component, 0, this->n_components));
374 
375  // initialize the parser if that hasn't happened yet on the current thread
376  if (fp.get().size() == 0)
377  init_muparser();
378 
379  for (unsigned int i=0; i<dim; ++i)
380  vars.get()[i] = p(i);
381  if (dim != n_vars)
382  vars.get()[dim] = this->get_time();
383 
384  try
385  {
386  return fp.get()[component].Eval();
387  }
388  catch (mu::ParserError &e)
389  {
390  std::cerr << "Message: <" << e.GetMsg() << ">\n";
391  std::cerr << "Formula: <" << e.GetExpr() << ">\n";
392  std::cerr << "Token: <" << e.GetToken() << ">\n";
393  std::cerr << "Position: <" << e.GetPos() << ">\n";
394  std::cerr << "Errc: <" << e.GetCode() << ">" << std::endl;
395  AssertThrow(false, ExcParseError(e.GetCode(), e.GetMsg().c_str()));
396  return 0.0;
397  }
398 }
399 
400 
401 
402 template <int dim>
404  Vector<double> &values) const
405 {
406  Assert (initialized==true, ExcNotInitialized());
407  Assert (values.size() == this->n_components,
408  ExcDimensionMismatch (values.size(), this->n_components));
409 
410 
411  // initialize the parser if that hasn't happened yet on the current thread
412  if (fp.get().size() == 0)
413  init_muparser();
414 
415  for (unsigned int i=0; i<dim; ++i)
416  vars.get()[i] = p(i);
417  if (dim != n_vars)
418  vars.get()[dim] = this->get_time();
419 
420  for (unsigned int component = 0; component < this->n_components;
421  ++component)
422  values(component) = fp.get()[component].Eval();
423 }
424 
425 #else
426 
427 
428 template <int dim>
429 void
430 FunctionParser<dim>::initialize(const std::string &,
431  const std::vector<std::string> &,
432  const std::map<std::string, double> &,
433  const bool)
434 {
435  Assert(false, ExcNeedsFunctionparser());
436 }
437 
438 template <int dim>
439 void
440 FunctionParser<dim>::initialize(const std::string &,
441  const std::string &,
442  const std::map<std::string, double> &,
443  const bool)
444 {
445  Assert(false, ExcNeedsFunctionparser());
446 }
447 
448 
449 
450 template <int dim>
452  const Point<dim> &, unsigned int) const
453 {
454  Assert(false, ExcNeedsFunctionparser());
455  return 0.;
456 }
457 
458 
459 template <int dim>
461  const Point<dim> &, Vector<double> &) const
462 {
463  Assert(false, ExcNeedsFunctionparser());
464 }
465 
466 
467 #endif
468 
469 // Explicit Instantiations.
470 
471 template class FunctionParser<1>;
472 template class FunctionParser<2>;
473 template class FunctionParser<3>;
474 
475 DEAL_II_NAMESPACE_CLOSE
virtual double value(const Point< dim > &p, const unsigned int component=0) const
::ExceptionBase & ExcMessage(std::string arg1)
unsigned int n_vars
Threads::ThreadLocalStorage< std::vector< mu::Parser > > fp
#define AssertThrow(cond, exc)
Definition: exceptions.h:358
const unsigned int n_components
Definition: function.h:144
#define Assert(cond, exc)
Definition: exceptions.h:294
std::vector< std::string > split_string_list(const std::string &s, const char delimiter=',')
Definition: utilities.cc:265
std::size_t size() const
Threads::ThreadLocalStorage< std::vector< double > > vars
void init_muparser() const
::ExceptionBase & ExcNeedsFunctionparser()
virtual void vector_value(const Point< dim > &p, Vector< double > &values) const
std::vector< std::string > var_names
void initialize(const std::string &vars, const std::vector< std::string > &expressions, const ConstMap &constants, const bool time_dependent=false)
Number get_time() const
std::vector< std::string > expressions
FunctionParser(const unsigned int n_components=1, const double initial_time=0.0)
std::map< std::string, double > constants