Nektar++
Interpreter.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File: Interpreter.cpp
4 //
5 // For more information, please see: http://www.nektar.info
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // License for the specific language governing rights and limitations under
14 // Permission is hereby granted, free of charge, to any person obtaining a
15 // copy of this software and associated documentation files (the "Software"),
16 // to deal in the Software without restriction, including without limitation
17 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 // and/or sell copies of the Software, and to permit persons to whom the
19 // Software is furnished to do so, subject to the following conditions:
20 //
21 // The above copyright notice and this permission notice shall be included
22 // in all copies or substantial portions of the Software.
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 // DEALINGS IN THE SOFTWARE.
31 //
32 // Description: Parser and evaluator of analytic expressions.
33 //
34 ///////////////////////////////////////////////////////////////////////////////
35 
38 
39 #define BOOST_SPIRIT_THREADSAFE
40 #include <boost/spirit/include/classic_assign_actor.hpp>
41 #include <boost/spirit/include/classic_ast.hpp>
42 #include <boost/spirit/include/classic_core.hpp>
43 #include <boost/spirit/include/classic_push_back_actor.hpp>
44 #include <boost/spirit/include/classic_symbols.hpp>
45 
46 #include <boost/random/mersenne_twister.hpp>
47 #include <boost/random/normal_distribution.hpp>
48 #include <boost/random/variate_generator.hpp>
49 
50 #include <boost/algorithm/string/trim.hpp>
51 #include <boost/math/special_functions/bessel.hpp>
52 
53 namespace bsp = boost::spirit::classic;
54 
55 #include <map>
56 #include <string>
57 #include <vector>
58 #if defined(__INTEL_COMPILER)
59 #include <mathimf.h>
60 #else
61 #include <cmath>
62 #endif
63 
64 namespace Nektar
65 {
66 namespace LibUtilities
67 {
68 
69 // signum function
71 {
72  return (arg > 0.0) - (arg < 0.0);
73 }
74 
75 // Additive white Gaussian noise function. Arg: sigma of the zero-mean gaussian
76 // distribution Attention: this function is not actually used for evaluation
77 // purposes.
79 {
80  boost::mt19937 rng;
81  boost::variate_generator<boost::mt19937 &, boost::normal_distribution<>>
82  _normal(rng, boost::normal_distribution<>(0, sigma));
83  return _normal();
84 }
85 
87 {
88  return (x != 0.0 || y != 0.0) ? sqrt(x * x + y * y) : 0.0;
89 }
90 
92 {
93  return (x != 0.0 || y != 0.0) ? atan2(y, x) : 0.0;
94 }
95 
96 // =========================================================================
97 // AnalyticExpression definitions for Spirit Parser
98 // =========================================================================
99 
100 typedef NekDouble (*PFD)();
105 struct func
106 {
107  func(PFD1 p) : func1(p), size(1){};
108  func(PFD2 p) : func2(p), size(2){};
109  func(PFD3 p) : func3(p), size(3){};
110  func(PFD4 p) : func4(p), size(4){};
111 
112  union // Pointer to a function
113  {
118  };
119  size_t size;
120 };
121 
122 /** This struct creates a parser that matches the function definitions from
123  math.h. All of the functions accept one of more NekDoubles as arguments and
124  returns a NekDouble. **/
125 static struct functions : bsp::symbols<func>
126 {
128  {
129  // Add all of the functions from math.h
130  add("abs", std::abs) // absolute value
131  ("asin", asin) // arcsin
132  ("acos", acos) // arccos
133  ("atan", atan) // arctan
134  ("atan2", atan2) // arctan2
135  ("ang", ang) // angle calculation
136  ("ceil", ceil) // ceiling
137  ("cos", cos) // cosine
138  ("cosh", cosh) // hyperbolic cosine
139  ("exp", exp) // exponential
140  ("fabs", fabs) // absolute value
141  ("floor", floor) // floor
142  ("log", log) // natural log
143  ("log10", log10) // log base 10
144  ("rad", rad) // radians
145  ("sin", sin) // sine
146  ("sinh", sinh) // hyperbolic sine
147  ("sqrt", sqrt) // square root
148  ("tan", tan) // tangent
149  ("tanh", tanh) // hyperbolic tangent
150  // and few more custom functions
151  ("sign", sign) // sign
152  ("awgn", awgn) // white noise
153  ;
154  }
156 
157 /**
158  * @brief Concrete implementation of the interface defined in Interpreter.
159  */
161 {
162 private:
163  struct EvaluationStep;
164 
165 public:
166  typedef std::map<std::string, int> VariableMap;
167  typedef std::map<std::string, int> ConstantMap;
168  typedef std::map<std::string, int> ParameterMap;
169  typedef std::map<std::string, int> ExpressionMap;
170  typedef std::map<std::string, int> FunctionNameMap;
171  typedef std::vector<EvaluationStep *> ExecutionStack;
172  typedef std::pair<bool, NekDouble> PrecomputedValue;
175 
176  typedef bsp::tree_parse_info<std::string::const_iterator,
177  bsp::node_val_data_factory<NekDouble>>
179  typedef bsp::tree_match<std::string::const_iterator,
180  bsp::node_val_data_factory<NekDouble>>::
181  tree_iterator ParsedTreeIterator;
182 
183  typedef std::vector<const Array<OneD, const NekDouble> *> VariableArray;
184 
185  /**
186  * @brief Initializes the evaluator.
187  *
188  * This routine will initialize the evaluator with some basic default
189  * constants,
190  */
192  {
193  m_state_size = 1;
194 
195  // Constant definitions.
196  AddConstant("MEANINGLESS", 0.0);
197  AddConstant("E", M_E); // Natural logarithm
198  AddConstant("LOG2E", M_LOG2E); // log_2 e
199  AddConstant("LOG10E", M_LOG10E); // log_10 e
200  AddConstant("LN2", M_LN2); // log_e 2
201  AddConstant("LN10", M_LN10); // log_e 10
202  AddConstant("PI", M_PI); // pi
203  AddConstant("PI_2", M_PI_2); // pi/2
204  AddConstant("PI_4", M_PI_4); // pi/4
205  AddConstant("1_PI", M_1_PI); // 1/pi
206  AddConstant("2_PI", M_2_PI); // 2/pi
207  AddConstant("2_SQRTPI", M_2_SQRTPI); // 2/sqrt(pi)
208  AddConstant("SQRT2", M_SQRT2); // sqrt(2)
209  AddConstant("SQRT1_2", M_SQRT1_2); // 1/sqrt(2)
210  AddConstant("GAMMA", 0.57721566490153286060); // Euler
211  AddConstant("DEG", 57.2957795130823208768); // deg/radian
212  AddConstant("PHI", 1.61803398874989484820); // golden ratio
213 
214  // Function definitions.
238 
240  m_function[E_ASIN] = asin;
241  m_function[E_ACOS] = acos;
242  m_function[E_ATAN] = atan;
243  m_function[E_CEIL] = ceil;
244  m_function[E_COS] = cos;
245  m_function[E_COSH] = cosh;
246  m_function[E_EXP] = exp;
247  m_function[E_FABS] = fabs;
248  m_function[E_FLOOR] = floor;
249  m_function[E_LOG] = log;
250  m_function[E_LOG10] = log10;
251  m_function[E_SIN] = sin;
252  m_function[E_SINH] = sinh;
254  m_function[E_TAN] = tan;
255  m_function[E_TANH] = tanh;
257  m_function2[E_ATAN2] = atan2;
258  m_function2[E_ANG] = ang;
259  m_function2[E_RAD] = rad;
260  m_function2[E_BESSEL] = boost::math::cyl_bessel_j;
261 
262  // Note that there is no entry in m_function that corresponds to the
263  // awgn function. This is intentional as this function need not be
264  // pre-evaluated once!
265  }
266 
267  /**
268  * @brief Destructor that removes all entries from the execution stack.
269  */
271  {
272  for (auto &it_es : m_executionStack)
273  {
274  for (auto &it : it_es)
275  {
276  delete it;
277  }
278  it_es.clear();
279  }
280  m_executionStack.clear();
281  }
282 
283  /**
284  * @copydoc Interpreter::SetRandomSeed
285  */
286  void SetRandomSeed(unsigned int seed)
287  {
288  m_generator.seed(seed);
289  }
290 
291  /**
292  * @copydoc Interpreter::AddConstants
293  */
294  void AddConstants(std::map<std::string, NekDouble> const &constants)
295  {
296  for (auto const &it : constants)
297  {
298  AddConstant(it.first, it.second);
299  }
300  }
301 
302  /**
303  * @copydoc Interpreter::AddConstant
304  */
305  int AddConstant(std::string const &name, NekDouble value)
306  {
307  ConstantMap::const_iterator it = m_constantMapNameToId.find(name);
308  if (it == m_constantMapNameToId.end())
309  {
310  // We are trying to avoid duplicating entries in m_constantParser
311  // and m_constants.
312  m_constantsParser.add(name.c_str(), value);
313  int index = m_constant.size();
314  m_constantMapNameToId[name] = index;
315  m_constant.push_back(value);
316  return index;
317  }
318  else
319  {
320  if (m_constant[it->second] != value)
321  {
322  std::string errormsg =
323  "Attempt to add numerically different constants under the "
324  "same name: " +
325  name;
326  std::cout << errormsg << std::endl;
327  }
328  }
329  return it->second;
330  }
331 
332  /**
333  * @copydoc Interpreter::GetConstant
334  */
335  NekDouble GetConstant(std::string const &name)
336  {
337  NekDouble *value = find(m_constantsParser, name.c_str());
338  ASSERTL1(value != NULL, "Constant variable not found: " + name);
339  return *value;
340  }
341 
342  /**
343  * @copydoc Interpreter::SetParameters
344  */
345  void SetParameters(std::map<std::string, NekDouble> const &params)
346  {
347  for (auto const &it : params)
348  {
349  SetParameter(it.first, it.second);
350  }
351  }
352 
353  /**
354  * @copydoc Interpreter::SetParameter
355  */
356  void SetParameter(std::string const &name, NekDouble value)
357  {
358  ParameterMap::const_iterator it = m_parameterMapNameToId.find(name);
359  if (it == m_parameterMapNameToId.end())
360  {
362  m_parameter.push_back(value);
363  }
364  else
365  {
366  // If parameter is known, change its value.
367  m_parameter[it->second] = value;
368  }
369  }
370 
371  /**
372  * @copydoc Interpreter::GetParameter
373  */
374  NekDouble GetParameter(std::string const &name)
375  {
376  ParameterMap::const_iterator it = m_parameterMapNameToId.find(name);
377  ASSERTL1(it != m_parameterMapNameToId.end(),
378  "Parameter not found: " + name);
379  return m_parameter[it->second];
380  }
381 
382  /**
383  * @copydoc Interpreter::GetTime
384  */
386  {
387  return m_total_eval_time;
388  }
389 
390  /**
391  * @copydoc Interpreter::DefineFunction
392  */
393  int DefineFunction(const std::string &vlist, const std::string &expr)
394  {
395  // If we have previously parsed an identical expression, return its ID.
396  auto it = m_parsedMapExprToExecStackId.find(expr);
397  if (it != m_parsedMapExprToExecStackId.end())
398  {
399  // If this function is already defined, don't do anything but return
400  // its ID.
401  return it->second;
402  }
403 
404  // Otherwise, prepare an iterator that allows to walk along the string
405  // representing an analytic expression in the order that respects its
406  // recursive structure (thanks to boost::spirit).
407 
408  // Parse the vlist input and separate the variables into ordered entries
409  // in a vector<string> object. These need to be ordered because this is
410  // the order the variables will get assigned to in the Map when
411  // Evaluate(...) is called.
412  std::vector<std::string> variableNames;
413  bsp::parse((char *)vlist.c_str(),
414  (*bsp::space_p >>
415  *(+(+bsp::graph_p)[bsp::push_back_a(variableNames)] >>
416  +bsp::space_p)));
417 
418  // Set up our grammar.
419  AnalyticExpression myGrammar(&m_constantsParser, variableNames);
420 
421  // Do the actual parsing with boost::spirit and alert the user if there
422  // was an error with an exception.
423  ParsedTreeInfo parseInfo =
424  bsp::ast_parse<bsp::node_val_data_factory<NekDouble>,
425  std::string::const_iterator, AnalyticExpression,
426  bsp::space_parser>(expr.begin(), expr.end(),
427  myGrammar, bsp::space_p);
428 
429  ASSERTL1(parseInfo.full != false,
430  "Unable to fully parse function. Stopped just before: " +
431  std::string(parseInfo.stop, parseInfo.stop + 15));
432 
433  if (!parseInfo.full)
434  {
435  throw std::runtime_error(
436  "Unable to fully parse function at: " +
437  std::string(parseInfo.stop, parseInfo.stop + 15));
438  }
439 
440  // ----------------------------------------------
441  // Data parsed, start setting up internal data structures.
442  // ----------------------------------------------
443 
444  ExecutionStack stack;
445  VariableMap variableMap;
446 
447  int stackId = m_executionStack.size();
448  m_state_size = 1;
449 
450  // Register all variables declared in the expression
451  for (int i = 0; i < variableNames.size(); i++)
452  {
453  variableMap[variableNames[i]] = i;
454  }
455 
456  // Then prepare an execution stack. This method also calculates a
457  // length of internal state storage (m_state_size) for this function.
458  PrecomputedValue v = PrepareExecutionAsYouParse(parseInfo.trees.begin(),
459  stack, variableMap, 0);
460 
461  // Constant expression, fully evaluated already.
462  if (true == v.first)
463  {
464  ASSERTL1(stack.size() == 0,
465  "Constant expression yeilds non-empty execution stack. "
466  "Bug in PrepareExecutionAsYouParse()");
467 
468  int const_index = AddConstant(
469  std::string("EXPRESSION_") + std::to_string(stackId), v.second);
470  stack.push_back(makeStep<StoreConst>(0, const_index));
471  }
472 
473  m_parsedMapExprToExecStackId[expr] = stackId;
474 
475  // The execution stack and its corresponding variable index map are two
476  // parallel std::vectors that share their ids. This split helps to
477  // achieve some performance improvement.
478  m_executionStack.push_back(stack);
479  m_stackVariableMap.push_back(variableMap);
480  m_state_sizes.push_back(m_state_size);
481 
482  return stackId;
483  }
484 
485  /**
486  * @copydoc Interpreter::Evaluate
487  */
488  NekDouble Evaluate(const int id)
489  {
490  m_timer.Start();
491 
492  ASSERTL1(m_executionStack.size() > id,
493  "unknown analytic expression, it must first be defined "
494  "with DefineFunction(...)");
495 
496  ExecutionStack &stack = m_executionStack[id];
497 
498  m_state.resize(m_state_sizes[id]);
499  for (int i = 0; i < stack.size(); i++)
500  {
501  (*stack[i]).run_once();
502  }
503 
504  m_timer.Stop();
506 
507  return m_state[0];
508  }
509 
510  /**
511  * @copydoc Interpreter::Evaluate
512  */
513  NekDouble Evaluate(const int id, const NekDouble x, const NekDouble y,
514  const NekDouble z, const NekDouble t)
515  {
516  m_timer.Start();
517 
518  ASSERTL1(m_executionStack.size() > id,
519  "unknown analytic expression, it must first be defined with "
520  "DefineFunction(...)");
521 
522  ExecutionStack &stack = m_executionStack[id];
523 
524  // initialise internal vector of variable values
525  m_state.resize(m_state_sizes[id]);
526 
527  if (m_variable.size() < 4)
528  {
529  m_variable.resize(4);
530  }
531 
532  // no flexibility, no change of variable ordering in m_variable
533  // container depending on their names ordering in the input vlist
534  // argument of DefineFunction. Ordering convention (x,y,z,t) is assumed.
535  m_variable[0] = x;
536  m_variable[1] = y;
537  m_variable[2] = z;
538  m_variable[3] = t;
539 
540  // main execution cycle is hidden here
541  for (int i = 0; i < stack.size(); i++)
542  {
543  (*stack[i]).run_once();
544  }
545 
546  m_timer.Stop();
548 
549  return m_state[0];
550  }
551 
552  /**
553  * @copydoc Interpreter::EvaluateAtPoint
554  */
555  NekDouble EvaluateAtPoint(const int id, const std::vector<NekDouble> point)
556  {
557  m_timer.Start();
558 
559  ASSERTL1(m_executionStack.size() > id,
560  "unknown analytic expression, it must first be defined with "
561  "DefineFunction(...)");
562 
563  ExecutionStack &stack = m_executionStack[id];
564  VariableMap &variableMap = m_stackVariableMap[id];
565 
566  ASSERTL1(point.size() == variableMap.size(),
567  "The number of variables used to define this expression should"
568  " match the point dimensionality.");
569 
570  // initialise internal vector of variable values
571  m_state.resize(m_state_sizes[id]);
572  m_variable.resize(point.size());
573  VariableMap::const_iterator it;
574 
575  for (it = variableMap.begin(); it != variableMap.end(); ++it)
576  {
577  m_variable[it->second] = point[it->second];
578  }
579 
580  // main execution cycle is hidden here
581  for (int i = 0; i < stack.size(); i++)
582  {
583  (*stack[i]).run_once();
584  }
585 
586  m_timer.Stop();
588 
589  return m_state[0];
590  }
591 
592  /**
593  * @copydoc Interpreter::Evaluate
594  */
595  void Evaluate(const int id, const Array<OneD, const NekDouble> &x,
599  Array<OneD, NekDouble> &result)
600  {
601  m_timer.Start();
602  std::vector<Array<OneD, const NekDouble>> points = {x, y, z, t};
603  Evaluate(id, points, result);
604  m_timer.Stop();
606  }
607 
608  /**
609  * @copydoc Interpreter::Evaluate
610  */
611  void Evaluate(const int id,
612  const std::vector<Array<OneD, const NekDouble>> &points,
613  Array<OneD, NekDouble> &result)
614  {
615  m_timer.Start();
616 
617  const int num_points = points[0].size();
618  ASSERTL1(m_executionStack.size() > id,
619  "unknown analytic expression, it must first be defined "
620  "with DefineFunction(...)");
621  ASSERTL1(result.size() >= num_points,
622  "destination array must have enough capacity to store "
623  "expression values at each given point");
624 
625  ExecutionStack &stack = m_executionStack[id];
626 
627  /// If number of points tends to 10^6, one may end up with up to ~0.5Gb
628  /// data allocated for m_state only. Lets split the work into
629  /// cache-sized chunks. Ahtung, magic constant!
630  const int max_chunk_size = 1024;
631  const int nvals = points.size();
632  const int chunk_size = (std::min)(max_chunk_size, num_points);
633 
634  if (m_state.size() < chunk_size * m_state_sizes[id])
635  {
636  m_state.resize(m_state_sizes[id] * chunk_size, 0.0);
637  }
638  if (m_variable.size() < nvals * chunk_size)
639  {
640  m_variable.resize(nvals * chunk_size, 0.0);
641  }
642  if (result.size() < num_points)
643  {
644  result = Array<OneD, NekDouble>(num_points, 0.0);
645  }
646 
647  int offset = 0;
648  int work_left = num_points;
649  while (work_left > 0)
650  {
651  const int this_chunk_size = (std::min)(work_left, 1024);
652  for (int i = 0; i < this_chunk_size; i++)
653  {
654  for (int j = 0; j < nvals; ++j)
655  {
656  m_variable[i + this_chunk_size * j] = points[j][offset + i];
657  }
658  }
659  for (int i = 0; i < stack.size(); i++)
660  {
661  (*stack[i]).run_many(this_chunk_size);
662  }
663  for (int i = 0; i < this_chunk_size; i++)
664  {
665  result[offset + i] = m_state[i];
666  }
667  work_left -= this_chunk_size;
668  offset += this_chunk_size;
669  }
670  m_timer.Stop();
672  }
673 
674  // ======================================================
675  // Private parsing and partial evaluation method
676  // ======================================================
677 
678  /**
679  * @brief Prepares an execution stack for the evaluation of a function.
680  *
681  * This method prepares the execution stack (an ordered sequence of
682  * operators that perform the evaluation) for the parsed evaluation tree.
683  * In order to do this, it unrolls the binary tree representing the
684  * recursive evaluation into an ordered sequence of commands. That ordered
685  * sequence of commands is equivalent to a bottom-up walk up the evaluation
686  * tree, but this allows not to form tree explicitly.
687  *
688  * This approach requires to introduce explicitly an execution state
689  * (memory) shared by commands in the evaluation sequence: recursively
690  * dependent commands need to pass data between each other. Such state for
691  * the recursive evaluation is passed via return values of a recursive
692  * evaluation function --- which is bad if one wants to implement vectorized
693  * evaluator.
694  *
695  * On the other hand, to run through a sequential container of functors is
696  * faster than to walk the tree and at each node to check the node type.
697  *
698  * @param root Iterator generated by boost::spirit.
699  * @param stack Initially empty sequential container of evaluation
700  * steps.
701  * @param varMap Maps variable names to their ids.
702  * @param stateIndex An index in the state[] array where an evaluation
703  * step corresponding to the current tree node
704  * is allowed to write.
705  *
706  * @return A std::pair<bool, NekDouble> which encodes fully pre-evaluated
707  * NekDouble values as `(true, value)` if all sub-tree down the
708  * current node evaluates to constant, or flags the opposite
709  * via `(false, 0)`.
710  */
712  const ParsedTreeIterator &location, ExecutionStack &stack,
713  VariableMap &variableMap, int stateIndex)
714  {
715  std::string valueStr(location->value.begin(), location->value.end());
716  boost::algorithm::trim(valueStr);
717 
718  const bsp::parser_id parserID = location->value.id();
719 #if defined(NEKTAR_DEBUG) || defined(NEKTAR_FULLDEBUG)
720  const int num_children = location->children.size();
721 #endif
722 
723  if (parserID == AnalyticExpression::constantID)
724  {
725  ASSERTL1(num_children == 0,
726  "Illegal children under constant node: " + valueStr);
727 
728  auto it = m_constantMapNameToId.find(valueStr);
729  ASSERTL1(it != m_constantMapNameToId.end(),
730  "Cannot find the value for the specified constant: " +
731  valueStr);
732 
733  return std::make_pair(true, m_constant[it->second]);
734  }
735  else if (parserID == AnalyticExpression::numberID)
736  {
737  ASSERTL1(num_children == 0,
738  "Illegal children under number node: " + valueStr);
739  return std::make_pair(
740  true, boost::lexical_cast<NekDouble>(valueStr.c_str()));
741  }
742  else if (parserID == AnalyticExpression::variableID)
743  {
744  ASSERTL1(num_children == 0,
745  "Illegal children under variable node: " + valueStr);
746 
747  VariableMap::const_iterator it = variableMap.find(valueStr);
748  ASSERTL1(it != variableMap.end(),
749  "Unknown variable parsed: " + valueStr);
750 
751  // Variables are not defined at the time of this parse.
752  stack.push_back(makeStep<StoreVar>(stateIndex, it->second));
753  return std::make_pair(false, 0);
754  }
755  else if (parserID == AnalyticExpression::parameterID)
756  {
757  ASSERTL1(num_children == 0,
758  "Illegal children under parameter node: " + valueStr);
759 
760  auto it = m_parameterMapNameToId.find(valueStr);
761  ASSERTL1(it != m_parameterMapNameToId.end(),
762  "Unknown parameter parsed: " + valueStr);
763 
764  // Parameters may change in between of evalutions.
765  stack.push_back(makeStep<StorePrm>(stateIndex, it->second));
766  return std::make_pair(false, 0);
767  }
768  else if (parserID == AnalyticExpression::functionID)
769  {
770  auto it = m_functionMapNameToInstanceType.find(valueStr);
772  "Invalid function specified: " + valueStr);
773  ASSERTL1(num_children == 1 || num_children == 2,
774  "Function " + valueStr +
775  " has neither one or two "
776  "arguments: this is not implemented yet.");
777 
778  if (location->children.size() == 1)
779  {
781  location->children.begin(), stack, variableMap, stateIndex);
782 
783  // additive white gaussian noise function
784  if (it->second == E_AWGN)
785  {
786  int const_index =
787  AddConstant(std::string("SUB_EXPR_") +
788  std::to_string(m_constant.size()),
789  v.second);
790  stack.push_back(
791  makeStep<StoreConst>(stateIndex, const_index));
792  stack.push_back(makeStep<EvalAWGN>(stateIndex, stateIndex));
793  return std::make_pair(false, 0);
794  }
795 
796  if (true == v.first)
797  {
798  return std::make_pair(true,
799  m_function[it->second](v.second));
800  }
801  }
802  else
803  {
804  PrecomputedValue v1 =
805  PrepareExecutionAsYouParse(location->children.begin() + 0,
806  stack, variableMap, stateIndex);
808  location->children.begin() + 1, stack, variableMap,
809  stateIndex + 1);
810  m_state_size++;
811 
812  if (true == v1.first && true == v2.first)
813  {
814  return std::make_pair(
815  true, m_function2[it->second](v1.second, v2.second));
816  }
817  }
818 
819  // if somewhere down the parse tree there is a variable or
820  // parameter, set up an evaluation sequence.
821  switch (it->second)
822  {
823  case E_ABS:
824  stack.push_back(makeStep<EvalAbs>(stateIndex, stateIndex));
825  return std::make_pair(false, 0);
826  case E_ASIN:
827  stack.push_back(makeStep<EvalAsin>(stateIndex, stateIndex));
828  return std::make_pair(false, 0);
829  case E_ACOS:
830  stack.push_back(makeStep<EvalAcos>(stateIndex, stateIndex));
831  return std::make_pair(false, 0);
832  case E_ATAN:
833  stack.push_back(makeStep<EvalAtan>(stateIndex, stateIndex));
834  return std::make_pair(false, 0);
835  case E_ATAN2:
836  stack.push_back(makeStep<EvalAtan2>(stateIndex, stateIndex,
837  stateIndex + 1));
838  return std::make_pair(false, 0);
839  case E_ANG:
840  stack.push_back(makeStep<EvalAng>(stateIndex, stateIndex,
841  stateIndex + 1));
842  return std::make_pair(false, 0);
843  case E_BESSEL:
844  stack.push_back(makeStep<EvalBessel>(stateIndex, stateIndex,
845  stateIndex + 1));
846  return std::make_pair(false, 0);
847  case E_CEIL:
848  stack.push_back(makeStep<EvalCeil>(stateIndex, stateIndex));
849  return std::make_pair(false, 0);
850  case E_COS:
851  stack.push_back(makeStep<EvalCos>(stateIndex, stateIndex));
852  return std::make_pair(false, 0);
853  case E_COSH:
854  stack.push_back(makeStep<EvalCosh>(stateIndex, stateIndex));
855  return std::make_pair(false, 0);
856  case E_EXP:
857  stack.push_back(makeStep<EvalExp>(stateIndex, stateIndex));
858  return std::make_pair(false, 0);
859  case E_FABS:
860  stack.push_back(makeStep<EvalFabs>(stateIndex, stateIndex));
861  return std::make_pair(false, 0);
862  case E_FLOOR:
863  stack.push_back(
864  makeStep<EvalFloor>(stateIndex, stateIndex));
865  return std::make_pair(false, 0);
866  case E_LOG:
867  stack.push_back(makeStep<EvalLog>(stateIndex, stateIndex));
868  return std::make_pair(false, 0);
869  case E_LOG10:
870  stack.push_back(
871  makeStep<EvalLog10>(stateIndex, stateIndex));
872  return std::make_pair(false, 0);
873  case E_RAD:
874  stack.push_back(makeStep<EvalRad>(stateIndex, stateIndex,
875  stateIndex + 1));
876  return std::make_pair(false, 0);
877  case E_SIN:
878  stack.push_back(makeStep<EvalSin>(stateIndex, stateIndex));
879  return std::make_pair(false, 0);
880  case E_SINH:
881  stack.push_back(makeStep<EvalSinh>(stateIndex, stateIndex));
882  return std::make_pair(false, 0);
883  case E_SQRT:
884  stack.push_back(makeStep<EvalSqrt>(stateIndex, stateIndex));
885  return std::make_pair(false, 0);
886  case E_TAN:
887  stack.push_back(makeStep<EvalTan>(stateIndex, stateIndex));
888  return std::make_pair(false, 0);
889  case E_TANH:
890  stack.push_back(makeStep<EvalTanh>(stateIndex, stateIndex));
891  return std::make_pair(false, 0);
892  case E_SIGN:
893  stack.push_back(makeStep<EvalSign>(stateIndex, stateIndex));
894  return std::make_pair(false, 0);
895  default:
896  ASSERTL0(false, "Evaluation of " + valueStr +
897  " is not implemented yet");
898  }
899  return std::make_pair(false, 0);
900  }
901  else if (parserID == AnalyticExpression::unaryID)
902  {
903  ASSERTL1(*valueStr.begin() == '-',
904  "Illegal factor - it can only be '-' and it was: " +
905  valueStr);
906  ASSERTL1(num_children == 1,
907  "Illegal number of children under factor node: " +
908  valueStr);
910  location->children.begin(), stack, variableMap, stateIndex);
911 
912  // if precomputed value is valid, process it further.
913  if (true == v.first)
914  {
915  return std::make_pair(true, -v.second);
916  }
917  stack.push_back(makeStep<EvalNeg>(stateIndex, stateIndex));
918  return std::make_pair(false, 0);
919  }
920  else if (parserID == AnalyticExpression::operatorID)
921  {
922  ASSERTL1(
923  num_children == 2,
924  "Too few or too many arguments for mathematical operator: " +
925  valueStr);
927  location->children.begin() + 0, stack, variableMap, stateIndex);
928  PrecomputedValue right =
929  PrepareExecutionAsYouParse(location->children.begin() + 1,
930  stack, variableMap, stateIndex + 1);
931  m_state_size++;
932 
933  // if both precomputed values are valid, process them further.
934  if ((left.first == true) && (right.first == true))
935  {
936  switch (*valueStr.begin())
937  {
938  case '+':
939  return std::make_pair(true, left.second + right.second);
940  case '-':
941  return std::make_pair(true, left.second - right.second);
942  case '*':
943  return std::make_pair(true, left.second * right.second);
944  case '/':
945  return std::make_pair(true, left.second / right.second);
946  case '^':
947  return std::make_pair(
948  true, std::pow(left.second, right.second));
949  case '=':
950  return std::make_pair(true,
951  left.second == right.second);
952  case '<':
953  if (*(valueStr.end() - 1) == '=')
954  {
955  return std::make_pair(true,
956  left.second <= right.second);
957  }
958  else
959  {
960  return std::make_pair(true,
961  left.second < right.second);
962  }
963  return std::make_pair(false, 0);
964  case '>':
965  if (*(valueStr.end() - 1) == '=')
966  {
967  return std::make_pair(true,
968  left.second >= right.second);
969  }
970  else
971  {
972  return std::make_pair(true,
973  left.second > right.second);
974  }
975  return std::make_pair(false, 0);
976  default:
977  ASSERTL0(false,
978  "Invalid operator encountered: " + valueStr);
979  }
980  return std::make_pair(false, 0);
981  }
982 
983  // either operator argument is not fully evaluated
984  // add pre-evaluated value to the contaner of constants
985  if (true == left.first)
986  {
987  int const_index =
988  AddConstant(std::string("SUB_EXPR_") +
989  std::to_string(m_constant.size()),
990  left.second);
991  stack.push_back(makeStep<StoreConst>(stateIndex, const_index));
992  }
993  if (true == right.first)
994  {
995  int const_index =
996  AddConstant(std::string("SUB_EXPR_") +
997  std::to_string(m_constant.size()),
998  right.second);
999  stack.push_back(
1000  makeStep<StoreConst>(stateIndex + 1, const_index));
1001  }
1002 
1003  switch (*valueStr.begin())
1004  {
1005  case '+':
1006  stack.push_back(makeStep<EvalSum>(stateIndex, stateIndex,
1007  stateIndex + 1));
1008  return std::make_pair(false, 0);
1009  case '-':
1010  stack.push_back(makeStep<EvalSub>(stateIndex, stateIndex,
1011  stateIndex + 1));
1012  return std::make_pair(false, 0);
1013  case '*':
1014  stack.push_back(makeStep<EvalMul>(stateIndex, stateIndex,
1015  stateIndex + 1));
1016  return std::make_pair(false, 0);
1017  case '/':
1018  stack.push_back(makeStep<EvalDiv>(stateIndex, stateIndex,
1019  stateIndex + 1));
1020  return std::make_pair(false, 0);
1021  case '^':
1022  stack.push_back(makeStep<EvalPow>(stateIndex, stateIndex,
1023  stateIndex + 1));
1024  return std::make_pair(false, 0);
1025  case '=':
1026  stack.push_back(makeStep<EvalLogicalEqual>(
1027  stateIndex, stateIndex, stateIndex + 1));
1028  return std::make_pair(false, 0);
1029  case '<':
1030  if (*(valueStr.end() - 1) == '=')
1031  {
1032  stack.push_back(makeStep<EvalLogicalLeq>(
1033  stateIndex, stateIndex, stateIndex + 1));
1034  }
1035  else
1036  {
1037  stack.push_back(makeStep<EvalLogicalLess>(
1038  stateIndex, stateIndex, stateIndex + 1));
1039  }
1040  return std::make_pair(false, 0);
1041 
1042  case '>':
1043  if (*(valueStr.end() - 1) == '=')
1044  {
1045  stack.push_back(makeStep<EvalLogicalGeq>(
1046  stateIndex, stateIndex, stateIndex + 1));
1047  }
1048  else
1049  {
1050  stack.push_back(makeStep<EvalLogicalGreater>(
1051  stateIndex, stateIndex, stateIndex + 1));
1052  }
1053  return std::make_pair(false, 0);
1054 
1055  default:
1056  ASSERTL0(false,
1057  "Invalid operator encountered: " + valueStr);
1058  }
1059  return std::make_pair(false, 0);
1060  }
1061  else if (parserID == AnalyticExpression::operatorID)
1062  {
1063  ASSERTL1(
1064  false,
1065  "Too few or too many arguments for mathematical operator: " +
1066  valueStr);
1067  }
1068  ASSERTL0(false, "Illegal expression encountered: " + valueStr);
1069  return std::make_pair(false, 0);
1070  }
1071 
1072  // ======================================================
1073  // Boost::spirit related data structures
1074  // ======================================================
1075 
1076  /** This is a parser for spirit that parses the CONSTANT values. The default
1077  constants are those that are in math.h without the M_ prefix and they
1078  are initialized in the AnalyticExpressionEvaluator constructor. **/
1079 
1080  bsp::symbols<NekDouble> m_constantsParser;
1081 
1082  /** This is the class that is used as the grammar parser for the spirit
1083  * engine. **/
1084  class AnalyticExpression : public bsp::grammar<AnalyticExpression>
1085  {
1086  private:
1087  const bsp::symbols<NekDouble> *constants_p;
1088 
1089  /** Variables is a customized parser that will match the variables that
1090  the function depends on (the first argument of #DefineFunction). **/
1091  struct variables : bsp::symbols<NekDouble *>
1092  {
1093  variables(std::vector<std::string> const &vars)
1094  {
1095  for (auto const &it : vars)
1096  {
1097  add(it.c_str(), 0);
1098  }
1099  }
1101 
1102  public:
1103  /** These constants are used to determine what parser was used to parse
1104  what value, which allows for type identification when analyzing the
1105  parsed AST. **/
1106  static const int constantID = 1;
1107  static const int numberID = 2;
1108  static const int variableID = 3;
1109  static const int parameterID = 4;
1110  static const int functionID = 5;
1111  static const int unaryID = 6;
1112  static const int operatorID = 7;
1113 
1114  AnalyticExpression(const bsp::symbols<NekDouble> *constants,
1115  const std::vector<std::string> &variables)
1116  : bsp::grammar<AnalyticExpression>(), constants_p(constants),
1118  {
1119  }
1120 
1121  // Trivial constructor to avoid compiler warning with
1122  // constants_p.
1124  {
1125  constants_p = NULL;
1126  }
1127 
1128  template <typename ScannerT> struct definition
1129  {
1130  /** This function specifies the grammar of the
1131  * MathAnalyticExpression parser. **/
1133  {
1135 
1136  logical_or =
1137  logical_and >>
1138  *((bsp::root_node_d[bsp::str_p("||")] >> logical_and));
1139 
1140  logical_and =
1141  equality >>
1142  *((bsp::root_node_d[bsp::str_p("&&")] >> equality));
1143 
1144  equality =
1145  lt_gt >> *((bsp::root_node_d[bsp::str_p("==")] >> lt_gt));
1146 
1147  lt_gt = add_sub >>
1148  *((bsp::root_node_d[bsp::str_p("<=")] >> add_sub) |
1149  (bsp::root_node_d[bsp::str_p(">=")] >> add_sub) |
1150  (bsp::root_node_d[bsp::ch_p('<')] >> add_sub) |
1151  (bsp::root_node_d[bsp::ch_p('>')] >> add_sub));
1152 
1153  add_sub =
1154  negate >> *((bsp::root_node_d[bsp::ch_p('+')] >> negate) |
1155  (bsp::root_node_d[bsp::ch_p('-')] >> negate));
1156 
1157  negate = !(bsp::root_node_d[bsp::ch_p('-')]) >> mult_div;
1158 
1159  mult_div = exponential >>
1160  *((bsp::root_node_d[bsp::ch_p('*')] >> exponential) |
1161  (bsp::root_node_d[bsp::ch_p('/')] >> exponential));
1162 
1163  exponential =
1164  base >> !(bsp::root_node_d[bsp::ch_p('^')] >> exponential);
1165 
1166  base = number | function | variable | constant | parameter |
1167  bsp::inner_node_d[bsp::ch_p('(') >> expression >>
1168  bsp::ch_p(')')];
1169  parameter =
1170  bsp::leaf_node_d[bsp::lexeme_d[(bsp::alpha_p | '_' | '$') >>
1171  *(bsp::alnum_p | '_' |
1172  '$')]] >>
1173  op;
1174 
1175  function =
1176  bsp::root_node_d[functions_p] >>
1177  bsp::infix_node_d[bsp::inner_node_d[bsp::ch_p('(') >>
1178  expression >>
1179  *(',' >> expression) >>
1180  bsp::ch_p(')')]];
1181 
1182  variable =
1183  bsp::leaf_node_d[bsp::lexeme_d[self.variables_p]] >> op;
1184 
1185  number = bsp::leaf_node_d[bsp::lexeme_d[bsp::real_p]] >> op;
1186 
1187  constant =
1188  bsp::leaf_node_d[bsp::lexeme_d[*self.constants_p]] >> op;
1189 
1190  op = bsp::eps_p(bsp::end_p | "||" | "&&" | "==" | "<=" | ">=" |
1191  '<' | '>' | '+' | '-' | '*' | '/' | '^' | ')' |
1192  ',');
1193  }
1194 
1195  /** This holds the NekDouble value that is parsed by spirit so it
1196  * can be stored in the AST. **/
1198 
1199  template <int N>
1200  using bsp_rule =
1201  bsp::rule<ScannerT, bsp::parser_context<>, bsp::parser_tag<N>>;
1202 
1220 
1222  {
1223  return expression;
1224  }
1225  };
1226  }; // class AnalyticExpression
1227 
1228 private:
1229  // ======================================================
1230  // Pre-processed expressions
1231  // ======================================================
1232 
1233  /// These vector and map store pre-processed evaluation sequences
1234  /// for the analytic expressions. Each ExecutionStack is an ordered
1235  /// container of steps of sequential execution process which
1236  /// evaluates an analytic expression.
1237 
1239  std::vector<ExecutionStack> m_executionStack;
1240 
1241  /// Keeping map of variables individually per each analytic expression
1242  /// allows correctly handling expressions which depend on different
1243  /// number of variables.
1244 
1245  std::vector<VariableMap> m_stackVariableMap;
1246 
1247  // ======================================================
1248  // Execution state and data
1249  // ======================================================
1250 
1251  /// The following data structures hold input data to be used on evaluation
1252  /// stage. There are three types of input data:
1253  /// - constants (never change their value)
1254  /// - parameters are allowed to change their values between evaluations
1255  /// (compared to constants)
1256  /// - variables always change their values at every evaluation call.
1257  /// First map looks like <parameter_name, parameter_id> while the second is
1258  /// <parameter_id, parameter_value>. The map is used at a preparation
1259  /// stage when the analytic expression is parsed. This associates an
1260  /// integer id with a parameter name in its string form. On evaluation
1261  /// stage the id and a std::vector constant lookup time make evaluation
1262  /// faster compared to permanent std::map<std::string, NekDouble> lookup.
1263 
1267 
1268  std::vector<NekDouble> m_parameter;
1269  std::vector<NekDouble> m_constant;
1270  std::vector<NekDouble> m_variable;
1271 
1272  /// This vector stores the execution state (memory) used by the
1273  /// sequential execution process.
1274  std::vector<NekDouble> m_state;
1275 
1276  /// Vector of state sizes per each
1277  std::vector<int> m_state_sizes;
1278 
1279  /// This counter is used by PrepareExecutionAsYouParse for finding
1280  /// the minimal state size necessary for evaluation of function parsed.
1282 
1283  /// Timer and sum of evaluation times
1286 
1287  boost::mt19937 m_generator;
1288 
1289  // ======================================================
1290  // A map of (external) mathematical functions
1291  // ======================================================
1292 
1294  std::map<int, OneArgFunc> m_function;
1295  std::map<int, TwoArgFunc> m_function2;
1296 
1297  // ======================================================
1298  // Internal representation of evaluation step
1299  // ======================================================
1300 
1301  /// Short names to minimise the infractructural code mess in defining
1302  /// functors below.
1303  typedef std::vector<NekDouble> &vr;
1304  typedef const std::vector<NekDouble> &cvr;
1305  typedef const int ci;
1306  typedef boost::mt19937 &rgt;
1307 
1308  /// Factory method which makes code little less messy
1309  template <typename StepType>
1310  EvaluationStep *makeStep(ci dest, ci src_left = 0, ci src_right = 0)
1311  {
1312  return (new StepType(m_generator, m_state, m_constant, m_parameter,
1313  m_variable, dest, src_left, src_right));
1314  }
1315 
1317  {
1341  E_BESSEL
1342  };
1343 
1344  /// Function objects (functors)
1346  {
1347  /// reference to random number generator
1349 
1350  /// references to arrays holding the common state
1355 
1356  /// indices in the above arrays uniquely defining actual command
1357  /// arguments
1361 
1362  EvaluationStep(rgt rn, ci i, ci l, ci r, vr s, cvr c, cvr p, cvr v)
1363  : rng(rn), state(s), consts(c), params(p), vars(v), storeIdx(i),
1364  argIdx1(l), argIdx2(r){};
1365 
1367  {
1368  }
1369 
1370  /// declaring this guy pure virtual shortens virtual table. It saves
1371  /// some execution time.
1372  virtual void run_many(ci n) = 0;
1373  virtual void run_once() = 0;
1374  };
1375  struct CopyState : public EvaluationStep
1376  {
1377  CopyState(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1378  : EvaluationStep(rn, i, l, r, s, c, p, v)
1379  {
1380  }
1381  virtual void run_many(ci n)
1382  {
1383  for (int i = 0; i < n; i++)
1384  state[storeIdx * n + i] = state[argIdx1];
1385  }
1386  virtual void run_once()
1387  {
1389  }
1390  };
1391  struct StoreConst : public EvaluationStep
1392  {
1393  StoreConst(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1394  : EvaluationStep(rn, i, l, r, s, c, p, v)
1395  {
1396  }
1397  virtual void run_many(ci n)
1398  {
1399  for (int i = 0; i < n; i++)
1400  state[storeIdx * n + i] = consts[argIdx1];
1401  }
1402  virtual void run_once()
1403  {
1405  }
1406  };
1407  struct StoreVar : public EvaluationStep
1408  {
1409  StoreVar(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1410  : EvaluationStep(rn, i, l, r, s, c, p, v)
1411  {
1412  }
1413  virtual void run_many(ci n)
1414  {
1415  for (int i = 0; i < n; i++)
1416  state[storeIdx * n + i] = vars[argIdx1 * n + i];
1417  }
1418  virtual void run_once()
1419  {
1420  state[storeIdx] = vars[argIdx1];
1421  }
1422  };
1423  struct StorePrm : public EvaluationStep
1424  {
1425  StorePrm(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1426  : EvaluationStep(rn, i, l, r, s, c, p, v)
1427  {
1428  }
1429  virtual void run_many(ci n)
1430  {
1431  for (int i = 0; i < n; i++)
1432  state[storeIdx * n + i] = params[argIdx1];
1433  }
1434  virtual void run_once()
1435  {
1437  }
1438  };
1439  struct EvalSum : public EvaluationStep
1440  {
1441  EvalSum(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1442  : EvaluationStep(rn, i, l, r, s, c, p, v)
1443  {
1444  }
1445  virtual void run_many(ci n)
1446  {
1447  for (int i = 0; i < n; i++)
1448  state[storeIdx * n + i] =
1449  state[argIdx1 * n + i] + state[argIdx2 * n + i];
1450  }
1451  virtual void run_once()
1452  {
1454  }
1455  };
1456  struct EvalSub : public EvaluationStep
1457  {
1458  EvalSub(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1459  : EvaluationStep(rn, i, l, r, s, c, p, v)
1460  {
1461  }
1462  virtual void run_many(ci n)
1463  {
1464  for (int i = 0; i < n; i++)
1465  state[storeIdx * n + i] =
1466  state[argIdx1 * n + i] - state[argIdx2 * n + i];
1467  }
1468  virtual void run_once()
1469  {
1471  }
1472  };
1473  struct EvalMul : public EvaluationStep
1474  {
1475  EvalMul(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1476  : EvaluationStep(rn, i, l, r, s, c, p, v)
1477  {
1478  }
1479  virtual void run_many(ci n)
1480  {
1481  for (int i = 0; i < n; i++)
1482  state[storeIdx * n + i] =
1483  state[argIdx1 * n + i] * state[argIdx2 * n + i];
1484  }
1485  virtual void run_once()
1486  {
1488  }
1489  };
1490  struct EvalDiv : public EvaluationStep
1491  {
1492  EvalDiv(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1493  : EvaluationStep(rn, i, l, r, s, c, p, v)
1494  {
1495  }
1496  virtual void run_many(ci n)
1497  {
1498  for (int i = 0; i < n; i++)
1499  state[storeIdx * n + i] =
1500  state[argIdx1 * n + i] / state[argIdx2 * n + i];
1501  }
1502  virtual void run_once()
1503  {
1505  }
1506  };
1507  struct EvalPow : public EvaluationStep
1508  {
1509  EvalPow(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1510  : EvaluationStep(rn, i, l, r, s, c, p, v)
1511  {
1512  }
1513  virtual void run_many(ci n)
1514  {
1515  for (int i = 0; i < n; i++)
1516  state[storeIdx * n + i] =
1517  std::pow(state[argIdx1 * n + i], state[argIdx2 * n + i]);
1518  }
1519  virtual void run_once()
1520  {
1521  state[storeIdx] = std::pow(state[argIdx1], state[argIdx2]);
1522  }
1523  };
1524  struct EvalNeg : public EvaluationStep
1525  {
1526  EvalNeg(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1527  : EvaluationStep(rn, i, l, r, s, c, p, v)
1528  {
1529  }
1530  virtual void run_many(ci n)
1531  {
1532  for (int i = 0; i < n; i++)
1533  state[storeIdx * n + i] = -state[argIdx1 * n + i];
1534  }
1535  virtual void run_once()
1536  {
1537  state[storeIdx] = -state[argIdx1];
1538  }
1539  };
1541  {
1542  EvalLogicalEqual(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1543  : EvaluationStep(rn, i, l, r, s, c, p, v)
1544  {
1545  }
1546  virtual void run_many(ci n)
1547  {
1548  for (int i = 0; i < n; i++)
1549  state[storeIdx * n + i] =
1550  (state[argIdx1 * n + i] == state[argIdx2 * n + i]);
1551  }
1552  virtual void run_once()
1553  {
1555  }
1556  };
1558  {
1559  EvalLogicalLeq(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1560  : EvaluationStep(rn, i, l, r, s, c, p, v)
1561  {
1562  }
1563  virtual void run_many(ci n)
1564  {
1565  for (int i = 0; i < n; i++)
1566  state[storeIdx * n + i] =
1567  (state[argIdx1 * n + i] <= state[argIdx2 * n + i]);
1568  }
1569  virtual void run_once()
1570  {
1572  }
1573  };
1575  {
1576  EvalLogicalLess(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1577  : EvaluationStep(rn, i, l, r, s, c, p, v)
1578  {
1579  }
1580  virtual void run_many(ci n)
1581  {
1582  for (int i = 0; i < n; i++)
1583  state[storeIdx * n + i] =
1584  (state[argIdx1 * n + i] < state[argIdx2 * n + i]);
1585  }
1586  virtual void run_once()
1587  {
1589  }
1590  };
1592  {
1593  EvalLogicalGeq(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1594  : EvaluationStep(rn, i, l, r, s, c, p, v)
1595  {
1596  }
1597  virtual void run_many(ci n)
1598  {
1599  for (int i = 0; i < n; i++)
1600  state[storeIdx * n + i] =
1601  (state[argIdx1 * n + i] >= state[argIdx2 * n + i]);
1602  }
1603  virtual void run_once()
1604  {
1606  }
1607  };
1609  {
1610  EvalLogicalGreater(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1611  : EvaluationStep(rn, i, l, r, s, c, p, v)
1612  {
1613  }
1614  virtual void run_many(ci n)
1615  {
1616  for (int i = 0; i < n; i++)
1617  state[storeIdx * n + i] =
1618  (state[argIdx1 * n + i] > state[argIdx2 * n + i]);
1619  }
1620  virtual void run_once()
1621  {
1623  }
1624  };
1625  struct EvalAbs : public EvaluationStep
1626  {
1627  EvalAbs(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1628  : EvaluationStep(rn, i, l, r, s, c, p, v)
1629  {
1630  }
1631  virtual void run_many(ci n)
1632  {
1633  for (int i = 0; i < n; i++)
1634  state[storeIdx * n + i] = std::abs(state[argIdx1 * n + i]);
1635  }
1636  virtual void run_once()
1637  {
1639  }
1640  };
1641  struct EvalSign : public EvaluationStep
1642  {
1643  EvalSign(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1644  : EvaluationStep(rn, i, l, r, s, c, p, v)
1645  {
1646  }
1647  virtual void run_many(ci n)
1648  {
1649  for (int i = 0; i < n; i++)
1650  state[storeIdx * n + i] = ((state[argIdx1 * n + i] > 0.0) -
1651  (state[argIdx1 * n + i] < 0.0));
1652  }
1653  virtual void run_once()
1654  {
1655  state[storeIdx] = ((state[argIdx1] > 0.0) - (state[argIdx1] < 0.0));
1656  }
1657  };
1658  struct EvalAsin : public EvaluationStep
1659  {
1660  EvalAsin(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1661  : EvaluationStep(rn, i, l, r, s, c, p, v)
1662  {
1663  }
1664  virtual void run_many(ci n)
1665  {
1666  for (int i = 0; i < n; i++)
1667  state[storeIdx * n + i] = std::asin(state[argIdx1 * n + i]);
1668  }
1669  virtual void run_once()
1670  {
1671  state[storeIdx] = std::asin(state[argIdx1]);
1672  }
1673  };
1674  struct EvalAcos : public EvaluationStep
1675  {
1676  EvalAcos(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1677  : EvaluationStep(rn, i, l, r, s, c, p, v)
1678  {
1679  }
1680  virtual void run_many(ci n)
1681  {
1682  for (int i = 0; i < n; i++)
1683  state[storeIdx * n + i] = std::acos(state[argIdx1 * n + i]);
1684  }
1685  virtual void run_once()
1686  {
1687  state[storeIdx] = std::acos(state[argIdx1]);
1688  }
1689  };
1690  struct EvalAtan : public EvaluationStep
1691  {
1692  EvalAtan(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1693  : EvaluationStep(rn, i, l, r, s, c, p, v)
1694  {
1695  }
1696  virtual void run_many(ci n)
1697  {
1698  for (int i = 0; i < n; i++)
1699  state[storeIdx * n + i] = std::atan(state[argIdx1 * n + i]);
1700  }
1701  virtual void run_once()
1702  {
1703  state[storeIdx] = std::atan(state[argIdx1]);
1704  }
1705  };
1706  struct EvalAtan2 : public EvaluationStep
1707  {
1708  EvalAtan2(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1709  : EvaluationStep(rn, i, l, r, s, c, p, v)
1710  {
1711  }
1712  virtual void run_many(ci n)
1713  {
1714  for (int i = 0; i < n; i++)
1715  state[storeIdx * n + i] =
1716  std::atan2(state[argIdx1 * n + i], state[argIdx2 * n + i]);
1717  }
1718  virtual void run_once()
1719  {
1720  state[storeIdx] = std::atan2(state[argIdx1], state[argIdx2]);
1721  }
1722  };
1723  struct EvalAng : public EvaluationStep
1724  {
1725  EvalAng(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1726  : EvaluationStep(rn, i, l, r, s, c, p, v)
1727  {
1728  }
1729  virtual void run_many(ci n)
1730  {
1731  for (int i = 0; i < n; i++)
1732  state[storeIdx * n + i] =
1733  ang(state[argIdx1 * n + i], state[argIdx2 * n + i]);
1734  }
1735  virtual void run_once()
1736  {
1738  }
1739  };
1740  struct EvalBessel : public EvaluationStep
1741  {
1742  EvalBessel(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1743  : EvaluationStep(rn, i, l, r, s, c, p, v)
1744  {
1745  }
1746  virtual void run_many(ci n)
1747  {
1748  for (int i = 0; i < n; i++)
1749  state[storeIdx * n + i] = boost::math::cyl_bessel_j(
1750  state[argIdx1 * n + i], state[argIdx2 * n + i]);
1751  }
1752  virtual void run_once()
1753  {
1754  state[storeIdx] =
1755  boost::math::cyl_bessel_j(state[argIdx1], state[argIdx2]);
1756  }
1757  };
1758  struct EvalCeil : public EvaluationStep
1759  {
1760  EvalCeil(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1761  : EvaluationStep(rn, i, l, r, s, c, p, v)
1762  {
1763  }
1764  virtual void run_many(ci n)
1765  {
1766  for (int i = 0; i < n; i++)
1767  state[storeIdx * n + i] = std::ceil(state[argIdx1 * n + i]);
1768  }
1769  virtual void run_once()
1770  {
1771  state[storeIdx] = std::ceil(state[argIdx1]);
1772  }
1773  };
1774  struct EvalCos : public EvaluationStep
1775  {
1776  EvalCos(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1777  : EvaluationStep(rn, i, l, r, s, c, p, v)
1778  {
1779  }
1780  virtual void run_many(ci n)
1781  {
1782  for (int i = 0; i < n; i++)
1783  state[storeIdx * n + i] = std::cos(state[argIdx1 * n + i]);
1784  }
1785  virtual void run_once()
1786  {
1787  state[storeIdx] = std::cos(state[argIdx1]);
1788  }
1789  };
1790  struct EvalCosh : public EvaluationStep
1791  {
1792  EvalCosh(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1793  : EvaluationStep(rn, i, l, r, s, c, p, v)
1794  {
1795  }
1796  virtual void run_many(ci n)
1797  {
1798  for (int i = 0; i < n; i++)
1799  state[storeIdx * n + i] = std::cosh(state[argIdx1 * n + i]);
1800  }
1801  virtual void run_once()
1802  {
1803  state[storeIdx] = std::cosh(state[argIdx1]);
1804  }
1805  };
1806  struct EvalExp : public EvaluationStep
1807  {
1808  EvalExp(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1809  : EvaluationStep(rn, i, l, r, s, c, p, v)
1810  {
1811  }
1812  virtual void run_many(ci n)
1813  {
1814  for (int i = 0; i < n; i++)
1815  state[storeIdx * n + i] = std::exp(state[argIdx1 * n + i]);
1816  }
1817  virtual void run_once()
1818  {
1819  state[storeIdx] = std::exp(state[argIdx1]);
1820  }
1821  };
1822  struct EvalFabs : public EvaluationStep
1823  {
1824  EvalFabs(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1825  : EvaluationStep(rn, i, l, r, s, c, p, v)
1826  {
1827  }
1828  virtual void run_many(ci n)
1829  {
1830  for (int i = 0; i < n; i++)
1831  state[storeIdx * n + i] = std::fabs(state[argIdx1 * n + i]);
1832  }
1833  virtual void run_once()
1834  {
1835  state[storeIdx] = std::fabs(state[argIdx1]);
1836  }
1837  };
1838  struct EvalFloor : public EvaluationStep
1839  {
1840  EvalFloor(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1841  : EvaluationStep(rn, i, l, r, s, c, p, v)
1842  {
1843  }
1844  virtual void run_many(ci n)
1845  {
1846  for (int i = 0; i < n; i++)
1847  state[storeIdx * n + i] = std::floor(state[argIdx1 * n + i]);
1848  }
1849  virtual void run_once()
1850  {
1851  state[storeIdx] = std::floor(state[argIdx1]);
1852  }
1853  };
1854  struct EvalLog : public EvaluationStep
1855  {
1856  EvalLog(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1857  : EvaluationStep(rn, i, l, r, s, c, p, v)
1858  {
1859  }
1860  virtual void run_many(ci n)
1861  {
1862  for (int i = 0; i < n; i++)
1863  state[storeIdx * n + i] = std::log(state[argIdx1 * n + i]);
1864  }
1865  virtual void run_once()
1866  {
1868  }
1869  };
1870  struct EvalLog10 : public EvaluationStep
1871  {
1872  EvalLog10(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1873  : EvaluationStep(rn, i, l, r, s, c, p, v)
1874  {
1875  }
1876  virtual void run_many(ci n)
1877  {
1878  for (int i = 0; i < n; i++)
1879  state[storeIdx * n + i] = std::log10(state[argIdx1 * n + i]);
1880  }
1881  virtual void run_once()
1882  {
1883  state[storeIdx] = std::log10(state[argIdx1]);
1884  }
1885  };
1886  struct EvalRad : public EvaluationStep
1887  {
1888  EvalRad(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1889  : EvaluationStep(rn, i, l, r, s, c, p, v)
1890  {
1891  }
1892  virtual void run_many(ci n)
1893  {
1894  for (int i = 0; i < n; i++)
1895  state[storeIdx * n + i] =
1896  rad(state[argIdx1 * n + i], state[argIdx2 * n + i]);
1897  }
1898  virtual void run_once()
1899  {
1901  }
1902  };
1903  struct EvalSin : public EvaluationStep
1904  {
1905  EvalSin(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1906  : EvaluationStep(rn, i, l, r, s, c, p, v)
1907  {
1908  }
1909  virtual void run_many(ci n)
1910  {
1911  for (int i = 0; i < n; i++)
1912  state[storeIdx * n + i] = std::sin(state[argIdx1 * n + i]);
1913  }
1914  virtual void run_once()
1915  {
1916  state[storeIdx] = std::sin(state[argIdx1]);
1917  }
1918  };
1919  struct EvalSinh : public EvaluationStep
1920  {
1921  EvalSinh(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1922  : EvaluationStep(rn, i, l, r, s, c, p, v)
1923  {
1924  }
1925  virtual void run_many(ci n)
1926  {
1927  for (int i = 0; i < n; i++)
1928  state[storeIdx * n + i] = std::sinh(state[argIdx1 * n + i]);
1929  }
1930  virtual void run_once()
1931  {
1932  state[storeIdx] = std::sinh(state[argIdx1]);
1933  }
1934  };
1935  struct EvalSqrt : public EvaluationStep
1936  {
1937  EvalSqrt(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1938  : EvaluationStep(rn, i, l, r, s, c, p, v)
1939  {
1940  }
1941  virtual void run_many(ci n)
1942  {
1943  for (int i = 0; i < n; i++)
1944  state[storeIdx * n + i] = std::sqrt(state[argIdx1 * n + i]);
1945  }
1946  virtual void run_once()
1947  {
1949  }
1950  };
1951  struct EvalTan : public EvaluationStep
1952  {
1953  EvalTan(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1954  : EvaluationStep(rn, i, l, r, s, c, p, v)
1955  {
1956  }
1957  virtual void run_many(ci n)
1958  {
1959  for (int i = 0; i < n; i++)
1960  state[storeIdx * n + i] = std::tan(state[argIdx1 * n + i]);
1961  }
1962  virtual void run_once()
1963  {
1964  state[storeIdx] = std::tan(state[argIdx1]);
1965  }
1966  };
1967  struct EvalTanh : public EvaluationStep
1968  {
1969  EvalTanh(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1970  : EvaluationStep(rn, i, l, r, s, c, p, v)
1971  {
1972  }
1973  virtual void run_many(ci n)
1974  {
1975  for (int i = 0; i < n; i++)
1976  state[storeIdx * n + i] = std::tanh(state[argIdx1 * n + i]);
1977  }
1978  virtual void run_once()
1979  {
1980  state[storeIdx] = std::tanh(state[argIdx1]);
1981  }
1982  };
1983  struct EvalAWGN : public EvaluationStep
1984  {
1985  EvalAWGN(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
1986  : EvaluationStep(rn, i, l, r, s, c, p, v)
1987  {
1988  }
1989  virtual void run_many(ci n)
1990  {
1991  // assuming the argument to AWGN does not depend on spatial
1992  // variables =>
1993  boost::variate_generator<boost::mt19937 &,
1994  boost::normal_distribution<>>
1995  _normal(rng,
1996  boost::normal_distribution<>(0, state[storeIdx * n]));
1997  for (int i = 0; i < n; i++)
1998  {
1999  state[storeIdx * n + i] = _normal();
2000  }
2001  }
2002  virtual void run_once()
2003  {
2004  boost::variate_generator<boost::mt19937 &,
2005  boost::normal_distribution<>>
2006  _normal(rng, boost::normal_distribution<>(0, state[storeIdx]));
2007  state[storeIdx] = _normal();
2008  }
2009  };
2010 };
2011 
2013 {
2014  m_impl = std::unique_ptr<ExpressionEvaluator>(new ExpressionEvaluator());
2015 }
2016 
2018 {
2019 }
2020 
2021 Interpreter::Interpreter(Interpreter &&r) : m_impl(std::move(r.m_impl))
2022 {
2023 }
2024 
2026 {
2027  m_impl = std::move(r.m_impl);
2028  return *this;
2029 }
2030 
2031 void Interpreter::SetRandomSeed(unsigned int seed)
2032 {
2033  m_impl->SetRandomSeed(seed);
2034 }
2035 
2037  std::map<std::string, NekDouble> const &constants)
2038 {
2039  m_impl->AddConstants(constants);
2040 }
2041 
2042 int Interpreter::AddConstant(std::string const &name, NekDouble value)
2043 {
2044  return m_impl->AddConstant(name, value);
2045 }
2046 
2048 {
2049  return m_impl->GetConstant(name);
2050 }
2051 
2052 void Interpreter::SetParameters(std::map<std::string, NekDouble> const &params)
2053 {
2054  m_impl->SetParameters(params);
2055 }
2056 
2057 void Interpreter::SetParameter(std::string const &name, NekDouble value)
2058 {
2059  m_impl->SetParameter(name, value);
2060 }
2061 
2063 {
2064  return m_impl->GetParameter(name);
2065 }
2066 
2068 {
2069  return m_impl->GetTime();
2070 }
2071 
2072 int Interpreter::DefineFunction(const std::string &vlist,
2073  const std::string &function)
2074 {
2075  return m_impl->DefineFunction(vlist, function);
2076 }
2077 
2078 NekDouble Interpreter::Evaluate(const int AnalyticExpression_id)
2079 {
2080  return m_impl->Evaluate(AnalyticExpression_id);
2081 }
2082 
2083 NekDouble Interpreter::Evaluate(const int AnalyticExpression_id,
2084  const NekDouble x, const NekDouble y,
2085  const NekDouble z, const NekDouble t)
2086 {
2087  return m_impl->Evaluate(AnalyticExpression_id, x, y, z, t);
2088 }
2089 
2090 NekDouble Interpreter::EvaluateAtPoint(const int AnalyticExpression_id,
2091  std::vector<NekDouble> point)
2092 {
2093  return m_impl->EvaluateAtPoint(AnalyticExpression_id, point);
2094 }
2095 
2096 void Interpreter::Evaluate(const int expression_id,
2101  Array<OneD, NekDouble> &result)
2102 {
2103  m_impl->Evaluate(expression_id, x, y, z, t, result);
2104 }
2105 
2107  const int expression_id,
2108  const std::vector<Array<OneD, const NekDouble>> &points,
2109  Array<OneD, NekDouble> &result)
2110 {
2111  m_impl->Evaluate(expression_id, points, result);
2112 }
2113 
2114 } // namespace LibUtilities
2115 } // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
Definition: ErrorUtil.hpp:250
#define LIB_UTILITIES_EXPORT
AnalyticExpression(const bsp::symbols< NekDouble > *constants, const std::vector< std::string > &variables)
Nektar::LibUtilities::Interpreter::ExpressionEvaluator::AnalyticExpression::variables variables_p
Concrete implementation of the interface defined in Interpreter.
void Evaluate(const int id, const Array< OneD, const NekDouble > &x, const Array< OneD, const NekDouble > &y, const Array< OneD, const NekDouble > &z, const Array< OneD, const NekDouble > &t, Array< OneD, NekDouble > &result)
Evaluate a function which depends only on constants and/or parameters.
int AddConstant(std::string const &name, NekDouble value)
Set constants to be evaluated.
void SetParameters(std::map< std::string, NekDouble > const &params)
Set parameter values.
EvaluationStep * makeStep(ci dest, ci src_left=0, ci src_right=0)
Factory method which makes code little less messy.
std::vector< int > m_state_sizes
Vector of state sizes per each.
int DefineFunction(const std::string &vlist, const std::string &expr)
Defines a function for the purposes of evaluation.
NekDouble GetConstant(std::string const &name)
Return the value of a constant.
NekDouble Evaluate(const int id)
Evaluate a function which depends only on constants and/or parameters.
Timer m_timer
Timer and sum of evaluation times.
std::vector< const Array< OneD, const NekDouble > * > VariableArray
NekDouble(* TwoArgFunc)(NekDouble, NekDouble)
std::vector< VariableMap > m_stackVariableMap
Keeping map of variables individually per each analytic expression allows correctly handling expressi...
bsp::tree_match< std::string::const_iterator, bsp::node_val_data_factory< NekDouble > >::tree_iterator ParsedTreeIterator
NekDouble EvaluateAtPoint(const int id, const std::vector< NekDouble > point)
Evaluate a function which depends on zero or more variables.
NekDouble Evaluate(const int id, const NekDouble x, const NekDouble y, const NekDouble z, const NekDouble t)
Evaluate a function which depends only on constants and/or parameters.
void SetParameter(std::string const &name, NekDouble value)
Set parameter values.
ParameterMap m_parameterMapNameToId
The following data structures hold input data to be used on evaluation stage. There are three types o...
int m_state_size
This counter is used by PrepareExecutionAsYouParse for finding the minimal state size necessary for e...
NekDouble GetTime() const
Returns the total walltime spent in evaluation procedures in seconds.
NekDouble GetParameter(std::string const &name)
Get the value of a parameter.
bsp::tree_parse_info< std::string::const_iterator, bsp::node_val_data_factory< NekDouble > > ParsedTreeInfo
std::vector< NekDouble > & vr
Short names to minimise the infractructural code mess in defining functors below.
void SetRandomSeed(unsigned int seed)
Sets the random seed for the pseudorandom number generator.
std::vector< NekDouble > m_state
This vector stores the execution state (memory) used by the sequential execution process.
PrecomputedValue PrepareExecutionAsYouParse(const ParsedTreeIterator &location, ExecutionStack &stack, VariableMap &variableMap, int stateIndex)
Prepares an execution stack for the evaluation of a function.
void AddConstants(std::map< std::string, NekDouble > const &constants)
Set constants to be evaluated.
~ExpressionEvaluator(void)
Destructor that removes all entries from the execution stack.
void Evaluate(const int id, const std::vector< Array< OneD, const NekDouble >> &points, Array< OneD, NekDouble > &result)
Evaluate a function which depends only on constants and/or parameters.
ExpressionMap m_parsedMapExprToExecStackId
These vector and map store pre-processed evaluation sequences for the analytic expressions....
Interpreter class for the evaluation of mathematical expressions.
Definition: Interpreter.h:78
NekDouble GetTime() const
Returns the total walltime spent in evaluation procedures in seconds.
void AddConstants(std::map< std::string, NekDouble > const &constants)
Set constants to be evaluated.
Interpreter()
Default constructor.
std::unique_ptr< ExpressionEvaluator > m_impl
Concrete implementation of the above API calls.
Definition: Interpreter.h:320
Interpreter & operator=(Interpreter &&)
Default assignment operator.
NekDouble GetConstant(std::string const &name)
Return the value of a constant.
int AddConstant(std::string const &name, NekDouble value)
Set constants to be evaluated.
NekDouble EvaluateAtPoint(const int id, std::vector< NekDouble > point)
Evaluate a function which depends on zero or more variables.
int DefineFunction(const std::string &vlist, const std::string &expr)
Defines a function for the purposes of evaluation.
~Interpreter()
Default destructor.
void SetParameters(std::map< std::string, NekDouble > const &params)
Set parameter values.
void SetParameter(std::string const &name, NekDouble value)
Set parameter values.
NekDouble Evaluate(const int id)
Evaluate a function which depends only on constants and/or parameters.
NekDouble GetParameter(std::string const &name)
Get the value of a parameter.
void SetRandomSeed(unsigned int seed=123u)
Sets the random seed for the pseudorandom number generator.
NekDouble TimePerTest(unsigned int n)
Returns amount of seconds per iteration in a test with n iterations.
Definition: Timer.cpp:62
NekDouble(* PFD1)(NekDouble)
NekDouble(* PFD2)(NekDouble, NekDouble)
static NekDouble rad(NekDouble x, NekDouble y)
Definition: Interpreter.cpp:86
NekDouble awgn(NekDouble sigma)
Definition: Interpreter.cpp:78
static NekDouble ang(NekDouble x, NekDouble y)
Definition: Interpreter.cpp:91
NekDouble(* PFD4)(NekDouble, NekDouble, NekDouble, NekDouble)
NekDouble(* PFD3)(NekDouble, NekDouble, NekDouble)
NekDouble(* PFD)()
NekDouble sign(NekDouble arg)
Definition: Interpreter.cpp:70
Nektar::LibUtilities::functions functions_p
InputIterator find(InputIterator first, InputIterator last, InputIterator startingpoint, const EqualityComparable &value)
Definition: StdRegions.hpp:362
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:1
double NekDouble
scalarT< T > log(scalarT< T > in)
Definition: scalar.hpp:278
scalarT< T > abs(scalarT< T > in)
Definition: scalar.hpp:272
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:267
bsp::rule< ScannerT, bsp::parser_context<>, bsp::parser_tag< N > > bsp_rule
CopyState(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalAWGN(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalAbs(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
EvalAcos(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalAng(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalAsin(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
EvalAtan2(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalAtan(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalBessel(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalCeil(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
EvalCos(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalCosh(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
EvalDiv(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalExp(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
EvalFabs(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalFloor(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalLog10(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalLog(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
EvalLogicalEqual(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalLogicalGeq(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalLogicalGreater(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalLogicalLeq(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalLogicalLess(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalMul(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalNeg(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
EvalPow(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalRad(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalSign(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalSin(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalSinh(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
EvalSqrt(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalSub(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalSum(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
EvalTan(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
EvalTanh(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)=0
declaring this guy pure virtual shortens virtual table. It saves some execution time.
ci storeIdx
indices in the above arrays uniquely defining actual command arguments
EvaluationStep(rgt rn, ci i, ci l, ci r, vr s, cvr c, cvr p, cvr v)
vr state
references to arrays holding the common state
StoreConst(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.
StorePrm(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
StoreVar(rgt rn, vr s, cvr c, cvr p, cvr v, ci i, ci l, ci r)
virtual void run_many(ci n)
declaring this guy pure virtual shortens virtual table. It saves some execution time.