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