https://mooseframework.inl.gov
KokkosFunctionParser.h
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 #pragma once
11 
12 #include "KokkosTypes.h"
13 #include "KokkosVariableValue.h"
14 #include "KokkosMaterialProperty.h"
16 #include "KokkosFunction.h"
17 
18 #include "ConsoleStreamInterface.h"
19 
20 #include "peglib.h"
21 
22 namespace Moose::Kokkos
23 {
24 
25 class FunctionBase;
26 
30 class PEGParser
31 {
32 public:
38  PEGParser(const std::string & expression, const ConsoleStream * console = nullptr);
39 
44  auto ast() const { return _ast; }
49  const std::string & expression() const { return _expression; }
50 
51 private:
55  peg::parser _parser;
59  std::shared_ptr<peg::Ast> _ast;
63  const std::string _expression;
64 };
65 
70 {
71 public:
77  RPNBuilder(const std::string & expression, const ConsoleStream * console = nullptr)
78  : _parser(expression, console)
79  {
80  }
81 
85  enum class Opcode
86  {
87  NUM,
88  VAR,
89  NEG,
90  NOT,
91  // Binary operators
92  ADD,
93  SUB,
94  MUL,
95  DIV,
96  AND,
97  OR,
98  EQ,
99  NEQ,
100  LT,
101  LEQ,
102  GT,
103  GEQ,
104  // Functions
105  ABS,
106  ACOS,
107  ACOSH,
108  ASIN,
109  ASINH,
110  ATAN,
111  ATAN2,
112  ATANH,
113  CBRT,
114  CEIL,
115  COS,
116  COSH,
117  COT,
118  CSC,
119  EXP,
120  EXP2,
121  FLOOR,
122  HYPOT,
123  IF,
124  INT,
125  LOG,
126  LOG2,
127  LOG10,
128  MAX,
129  MIN,
130  POW,
131  SEC,
132  SIN,
133  SINH,
134  SQRT,
135  TAN,
136  TANH,
137  TRUNC
138  };
139 
143  struct Instruction
144  {
145  // Opcode
147  // Original string
148  std::string text;
149  // Constant of variable index
150  unsigned int arg = libMesh::invalid_uint;
151  };
152 
156  struct Variable
157  {
158  // Variable index
159  unsigned int idx;
160  // Pointer to a scalar value
161  const Real * scalar = nullptr;
162  // Pointer to a field variable
163  const VariableValue * field = nullptr;
164  // Pointer to a material property
165  const MaterialProperty<Real> * property = nullptr;
166  // Pointer to a function
167  const Function * function = nullptr;
168  // Whether the variable was associated
169  bool associated() const { return scalar || field || property || function; }
170  };
171 
176  void build(const peg::Ast & ast);
178  void build() { build(*_parser.ast()); }
180 
185  void printRPN(const ConsoleStream & console) const;
190  const std::vector<Instruction> & getRPN() const { return _rpn; }
191 
195  void addDefaultVariables();
201 
207  unsigned int addNumber(Real number);
213  unsigned int addVariable(const std::string & name);
219  void associateScalar(const std::string & name, const Real * scalar);
225  void associateField(const std::string & name, const VariableValue * field);
231  void associateProperty(const std::string & name, const MaterialProperty<Real> * property);
237  void associateFunction(const std::string & name, const Function * function);
238 
243  const std::vector<Real> & getNumbers() const { return _numbers; }
248  const std::unordered_map<std::string, Variable> & getVariables() const { return _variables; }
249 
253  void finalize() { _finalized = true; }
258  bool finalized() const { return _finalized; }
259 
260 private:
264  static inline const std::map<std::string, Opcode> _unary_opcode_map = {{"-", Opcode::NEG},
265  {"!", Opcode::NOT}};
266 
270  static inline const std::map<std::string, Opcode> _binary_opcode_map = {{"+", Opcode::ADD},
271  {"-", Opcode::SUB},
272  {"*", Opcode::MUL},
273  {"/", Opcode::DIV},
274  {"^", Opcode::POW},
275  {"&", Opcode::AND},
276  {"|", Opcode::OR},
277  {"=", Opcode::EQ},
278  {"!=", Opcode::NEQ},
279  {"<", Opcode::LT},
280  {"<=", Opcode::LEQ},
281  {">", Opcode::GT},
282  {">=", Opcode::GEQ}};
283 
287  static inline const std::map<std::string, std::pair<Opcode, unsigned int>> _function_opcode_map =
288  {{"abs", {Opcode::ABS, 1}}, {"acos", {Opcode::ACOS, 1}}, {"acosh", {Opcode::ACOSH, 1}},
289  {"asin", {Opcode::ASIN, 1}}, {"asinh", {Opcode::ASINH, 1}}, {"atan", {Opcode::ATAN, 1}},
290  {"atan2", {Opcode::ATAN2, 2}}, {"atanh", {Opcode::ATANH, 1}}, {"cbrt", {Opcode::CBRT, 1}},
291  {"ceil", {Opcode::CEIL, 1}}, {"cos", {Opcode::COS, 1}}, {"cosh", {Opcode::COSH, 1}},
292  {"cot", {Opcode::COT, 1}}, {"csc", {Opcode::CSC, 1}}, {"exp", {Opcode::EXP, 1}},
293  {"exp2", {Opcode::EXP2, 1}}, {"floor", {Opcode::FLOOR, 1}}, {"hypot", {Opcode::HYPOT, 2}},
294  {"if", {Opcode::IF, 3}}, {"int", {Opcode::INT, 1}}, {"log", {Opcode::LOG, 1}},
295  {"log2", {Opcode::LOG2, 1}}, {"log10", {Opcode::LOG10, 1}}, {"max", {Opcode::MAX, 2}},
296  {"min", {Opcode::MIN, 2}}, {"pow", {Opcode::POW, 2}}, {"sec", {Opcode::SEC, 1}},
297  {"sin", {Opcode::SIN, 1}}, {"sinh", {Opcode::SINH, 1}}, {"sqrt", {Opcode::SQRT, 1}},
298  {"tan", {Opcode::TAN, 1}}, {"tanh", {Opcode::TANH, 1}}, {"trunc", {Opcode::TRUNC, 1}}};
299 
307  std::vector<Instruction> _rpn;
311  std::vector<Real> _numbers;
315  std::unordered_map<std::string, Variable> _variables;
323  bool _finalized = false;
324 
330  [[noreturn]] void builderError(const peg::Ast & ast, const std::string & message) const;
331 
335  void checkFinalized();
336 };
337 
342 {
344 
345 public:
349  RPNEvaluator() = default;
353  RPNEvaluator(const RPNEvaluator & evaluator);
354 
359  void init(const RPNBuilder & builder);
360 
369  KOKKOS_FUNCTION Real eval(const Real t,
370  const Real3 p,
371  const unsigned int qp = 0,
372  Datum * datum = nullptr) const;
373 
374 private:
378  struct Instruction
379  {
380  // Opcode
382  // Constant of variable index
383  unsigned int arg = libMesh::invalid_uint;
384  };
388  enum class VariableType
389  {
390  SCALAR,
391  FIELD,
392  MATERIAL,
393  FUNCTION
394  };
395 
427  std::vector<const void *> _pointers;
428 
432  unsigned int _num_scalars = 0;
436  unsigned int _num_fields = 0;
440  unsigned int _num_properties = 0;
444  unsigned int _num_functions = 0;
445 
449  static constexpr unsigned int _stack_size = 10;
453  static constexpr double _epsilon = 1.0e-12;
454 };
455 
456 #define KOKKOS_FPARSER_COMPARE(code, op, epsilon) \
457  case Opcode::code: \
458  stack[head - 2] = stack[head - 2] - stack[head - 1] op epsilon; \
459  --head; \
460  break
461 
462 #define KOKKOS_FPARSER_BINARY(code, op) \
463  case Opcode::code: \
464  stack[head - 2] = stack[head - 2] op stack[head - 1]; \
465  --head; \
466  break
467 
468 #define KOKKOS_FPARSER_FUNCTION_1(code, func) \
469  case Opcode::code: \
470  stack[head - 1] = ::Kokkos::func(stack[head - 1]); \
471  break
472 
473 #define KOKKOS_FPARSER_FUNCTION_2(code, func) \
474  case Opcode::code: \
475  stack[head - 2] = ::Kokkos::func(stack[head - 2], stack[head - 1]); \
476  --head; \
477  break
478 
479 #define KOKKOS_FPARSER_FUNCTION_INV_1(code, func) \
480  case Opcode::code: \
481  stack[head - 1] = 1.0 / ::Kokkos::func(stack[head - 1]); \
482  break
483 
484 KOKKOS_FUNCTION inline Real
485 RPNEvaluator::eval(const Real t, const Real3 p, const unsigned int qp, Datum * datum) const
486 {
487  Real stack[_stack_size];
488 
489  // Stack head position
490  unsigned int head = 0;
491 
492  for (unsigned int pos = 0; pos < _rpn.size(); ++pos)
493  {
494  KOKKOS_ASSERT(head < _stack_size);
495 
496  const auto inst = _rpn[pos];
497 
498  switch (_rpn[pos].op)
499  {
500  case Opcode::NUM:
501  stack[head] = _numbers[inst.arg];
502  ++head;
503  break;
504  case Opcode::VAR:
505  if (inst.arg < 3)
506  stack[head] = p(inst.arg);
507  else if (inst.arg == 3)
508  stack[head] = t;
509  else
510  {
511  const auto type = _variables[inst.arg].first;
512  const auto idx = _variables[inst.arg].second;
513 
514  switch (type)
515  {
517  stack[head] = _scalars[idx];
518  break;
519  case VariableType::FIELD:
520  {
521  KOKKOS_ASSERT(datum);
522 
523  stack[head] = _fields[idx](*datum, qp);
524  break;
525  }
527  {
528  KOKKOS_ASSERT(datum);
529 
530  stack[head] = _properties[idx](*datum, qp);
531  break;
532  }
534  stack[head] = _functions[idx].value(t, p);
535  break;
536  }
537  }
538  ++head;
539  break;
540  case Opcode::NEG:
541  stack[head - 1] = -stack[head - 1];
542  break;
543  case Opcode::NOT:
544  stack[head - 1] = !::Kokkos::round(stack[head - 1]);
545  break;
546  case Opcode::EQ:
547  stack[head - 2] = ::Kokkos::abs(stack[head - 2] - stack[head - 1]) <= _epsilon;
548  --head;
549  break;
550  case Opcode::NEQ:
551  stack[head - 2] = ::Kokkos::abs(stack[head - 2] - stack[head - 1]) > _epsilon;
552  --head;
553  break;
554  case Opcode::AND:
555  stack[head - 2] = ::Kokkos::round(stack[head - 2]) && ::Kokkos::round(stack[head - 1]);
556  --head;
557  break;
558  case Opcode::OR:
559  stack[head - 2] = ::Kokkos::round(stack[head - 2]) || ::Kokkos::round(stack[head - 1]);
560  --head;
561  break;
562  case Opcode::IF:
563  stack[head - 3] = ::Kokkos::round(stack[head - 3]) ? stack[head - 2] : stack[head - 1];
564  head -= 2;
565  break;
566  KOKKOS_FPARSER_COMPARE(LT, <, -_epsilon);
567  KOKKOS_FPARSER_COMPARE(LEQ, <=, _epsilon);
568  KOKKOS_FPARSER_COMPARE(GT, >, _epsilon);
569  KOKKOS_FPARSER_COMPARE(GEQ, >=, -_epsilon);
570  KOKKOS_FPARSER_BINARY(ADD, +);
571  KOKKOS_FPARSER_BINARY(SUB, -);
572  KOKKOS_FPARSER_BINARY(MUL, *);
573  KOKKOS_FPARSER_BINARY(DIV, /);
574  KOKKOS_FPARSER_FUNCTION_1(ABS, abs);
575  KOKKOS_FPARSER_FUNCTION_1(ACOS, acos);
576  KOKKOS_FPARSER_FUNCTION_1(ACOSH, acosh);
577  KOKKOS_FPARSER_FUNCTION_1(ASIN, asin);
578  KOKKOS_FPARSER_FUNCTION_1(ASINH, asinh);
579  KOKKOS_FPARSER_FUNCTION_1(ATAN, atan);
580  KOKKOS_FPARSER_FUNCTION_2(ATAN2, atan2);
581  KOKKOS_FPARSER_FUNCTION_1(ATANH, atanh);
582  KOKKOS_FPARSER_FUNCTION_1(CBRT, cbrt);
583  KOKKOS_FPARSER_FUNCTION_1(CEIL, ceil);
584  KOKKOS_FPARSER_FUNCTION_1(COS, cos);
585  KOKKOS_FPARSER_FUNCTION_1(COSH, cosh);
586  KOKKOS_FPARSER_FUNCTION_INV_1(COT, tan);
587  KOKKOS_FPARSER_FUNCTION_INV_1(CSC, sin);
588  KOKKOS_FPARSER_FUNCTION_1(EXP, exp);
589  KOKKOS_FPARSER_FUNCTION_1(EXP2, exp2);
590  KOKKOS_FPARSER_FUNCTION_1(FLOOR, floor);
591  KOKKOS_FPARSER_FUNCTION_2(HYPOT, hypot);
592  KOKKOS_FPARSER_FUNCTION_1(INT, round);
593  KOKKOS_FPARSER_FUNCTION_1(LOG, log);
594  KOKKOS_FPARSER_FUNCTION_1(LOG2, log2);
595  KOKKOS_FPARSER_FUNCTION_1(LOG10, log10);
596  KOKKOS_FPARSER_FUNCTION_2(MAX, max);
597  KOKKOS_FPARSER_FUNCTION_2(MIN, min);
598  KOKKOS_FPARSER_FUNCTION_2(POW, pow);
599  KOKKOS_FPARSER_FUNCTION_INV_1(SEC, cos);
600  KOKKOS_FPARSER_FUNCTION_1(SIN, sin);
601  KOKKOS_FPARSER_FUNCTION_1(SINH, sinh);
602  KOKKOS_FPARSER_FUNCTION_1(SQRT, sqrt);
603  KOKKOS_FPARSER_FUNCTION_1(TAN, tan);
604  KOKKOS_FPARSER_FUNCTION_1(TANH, tanh);
605  KOKKOS_FPARSER_FUNCTION_1(TRUNC, trunc);
606  }
607  }
608 
609  KOKKOS_ASSERT(head == 1);
610 
611  return stack[head - 1];
612 }
613 
614 } // namespace Moose::Kokkos
void associateFunction(const std::string &name, const Function *function)
Associate a variable with a function.
PEGParser(const std::string &expression, const ConsoleStream *console=nullptr)
Constructor.
const std::unordered_map< std::string, Variable > & getVariables() const
Get variables used in the expression.
The Kokkos array class.
Definition: KokkosArray.h:64
MetaPhysicL::DualNumber< V, D, asd > abs(const MetaPhysicL::DualNumber< V, D, asd > &a)
Definition: EigenADReal.h:50
A helper class for re-directing output streams to Console output objects form MooseObjects.
Definition: ConsoleStream.h:30
void addDefaultVariables()
Add default variables.
KOKKOS_FUNCTION Real eval(const Real t, const Real3 p, const unsigned int qp=0, Datum *datum=nullptr) const
Evaluate RPN at point (t,x,y,z)
The Kokkos object that holds thread-private data in the parallel operations of any Kokkos object...
Definition: KokkosDatum.h:23
void finalize()
Finalize the builder and prevent further changes.
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template * sin(_arg) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(tan
unsigned int _num_functions
Number of functions.
const unsigned int invalid_uint
auto exp(const T &)
const std::vector< Real > & getNumbers() const
Get numbers used in the expression.
static constexpr double _epsilon
Epsilon for equality comparison.
bool _has_default_variables
Whether default variables were added.
std::vector< Instruction > _rpn
RPN sequence.
static const std::map< std::string, Opcode > _unary_opcode_map
Map from unary operators to opcodes.
unsigned int addNumber(Real number)
Add a parsed function constant.
const std::vector< Instruction > & getRPN() const
Get RPN sequence.
Array< Function > _functions
Functions used in the function.
KOKKOS_FUNCTION T & first() const
Get the first element.
Definition: KokkosArray.h:228
const std::string & expression() const
Get input expression.
unsigned int _num_scalars
Number of scalar variables.
Array< VariableValue > _fields
Field variables used in the function.
void builderError(const peg::Ast &ast, const std::string &message) const
Print a pretty error showing the position of error.
Array< Real > _numbers
Numbers used in the function.
static const std::map< std::string, std::pair< Opcode, unsigned int > > _function_opcode_map
Map from functions to opcodes and the expected number of arguments.
Parsing Expression Grammar (PEG)
std::shared_ptr< peg::Ast > _ast
Abstract Syntax Tree (AST)
auto max(const L &left, const R &right)
static const std::map< std::string, Opcode > _binary_opcode_map
Map from binary operators to opcodes.
The abstract class that provides polymorphic interfaces for a function.
Array< Real > _scalars
Scalar variables used in the function.
peg::parser _parser
Parser object.
T pow(const T &x)
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template cos(_arg) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(cos
RPNEvaluator()=default
Default constructor.
T round(T x)
Definition: MathUtils.h:77
Reverse Polish Notation (RPN) builder.
void init(const RPNBuilder &builder)
Initialize RPN evaluator from an RPN builder.
unsigned int addVariable(const std::string &name)
Add a parsed function variable.
bool finalized() const
Get whether the builder was finalized.
RPNBuilder(const std::string &expression, const ConsoleStream *console=nullptr)
Constructor.
The Kokkos wrapper classes for MOOSE-like variable value access.
Reverse Polish Notation (RPN) evaluator.
static constexpr unsigned int _stack_size
Fixed stack size.
void associateScalar(const std::string &name, const Real *scalar)
Associate a variable with a scalar value.
auto log(const T &)
std::vector< const void * > _pointers
Pointers to the associated quantities of variables.
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template sinh(_arg) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(erf
unsigned int _num_properties
Number of material properties.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
bool hasDefaultVariables() const
Get whether default variables were added.
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template * sqrt(_arg)) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(tanh
std::vector< Real > _numbers
Numbers used in the function.
Array< Instruction > _rpn
RPN sequence.
void associateProperty(const std::string &name, const MaterialProperty< Real > *property)
Associate a variable with a material property.
bool _finalized
Whether builder was finalized.
void checkFinalized()
Error on attempts to update the builder after finalization.
const std::string _expression
Input expression.
auto ast() const
Get AST.
void printRPN(const ConsoleStream &console) const
Print RPN sequence for debugging.
Array< MaterialProperty< Real > > _properties
Material properties used in the function.
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template cosh(_arg) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(cosh
Array<::Kokkos::pair< VariableType, unsigned int > > _variables
Types of variables and indices.
auto min(const L &left, const R &right)
unsigned int _num_fields
Number of field variables.
void associateField(const std::string &name, const VariableValue *field)
Associate a variable with a field variable.
unsigned int idx(const ElemType type, const unsigned int nx, const unsigned int i, const unsigned int j)
std::unordered_map< std::string, Variable > _variables
Variables used in the function.
PEGParser _parser
PEG parser.