Panzer  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Panzer_ExprEval.cpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Panzer: A partial differential equation assembly
4 // engine for strongly coupled complex multiphysics systems
5 //
6 // Copyright 2011 NTESS and the Panzer contributors.
7 // SPDX-License-Identifier: BSD-3-Clause
8 // *****************************************************************************
9 // @HEADER
10 
11 #include <Panzer_ExprEval_impl.hpp>
12 
13 #include <cstdlib>
14 
15 #include <Teuchos_MathExpr.hpp>
16 
17 namespace panzer
18 {
19 namespace Expr
20 {
21 
23  : Teuchos::Reader(Teuchos::MathExpr::ask_reader_tables()) {
24 }
25 
26 void EvalBase::set(std::string const& name, Function const& value) {
27  symbol_map[name] = value;
28 }
29 
30 void EvalBase::at_shift(Teuchos::any& result_any, int token, std::string& text) {
31  using std::swap;
32  switch (token) {
33  case Teuchos::MathExpr::TOK_NAME: {
34  std::string& result = Teuchos::make_any_ref<std::string>(result_any);
35  swap(result, text);
36  return;
37  }
38  case Teuchos::MathExpr::TOK_CONST: {
39  this->make_constant(result_any, std::atof(text.c_str()));
40  return;
41  }
42  }
43 }
44 
45 void EvalBase::at_reduce(Teuchos::any& result, int prod, std::vector<Teuchos::any>& rhs) {
46  using std::swap;
47  switch (prod) {
48  case Teuchos::MathExpr::PROD_PROGRAM: {
49  swap(result, rhs.at(1));
50  break;
51  }
52  case Teuchos::MathExpr::PROD_NO_STATEMENTS:
53  case Teuchos::MathExpr::PROD_NO_EXPR:
54  case Teuchos::MathExpr::PROD_NEXT_STATEMENT: {
55  break;
56  }
57  case Teuchos::MathExpr::PROD_ASSIGN: {
58  std::string const& name = Teuchos::any_ref_cast<std::string>(rhs.at(0));
59  swap(symbol_map[name], rhs.at(4));
60  break;
61  }
62  case Teuchos::MathExpr::PROD_YES_EXPR:
63  case Teuchos::MathExpr::PROD_EXPR:
64  case Teuchos::MathExpr::PROD_TERNARY_DECAY:
65  case Teuchos::MathExpr::PROD_OR_DECAY:
66  case Teuchos::MathExpr::PROD_AND_DECAY:
67  case Teuchos::MathExpr::PROD_ADD_SUB_DECAY:
68  case Teuchos::MathExpr::PROD_MUL_DIV_DECAY:
69  case Teuchos::MathExpr::PROD_POW_DECAY:
70  case Teuchos::MathExpr::PROD_NEG_DECAY:
71  case Teuchos::MathExpr::PROD_SOME_ARGS:
72  swap(result, rhs.at(0));
73  break;
74  case Teuchos::MathExpr::PROD_TERNARY:
75  this->ternary_op(result, rhs.at(0), rhs.at(3), rhs.at(6));
76  break;
77  case Teuchos::MathExpr::PROD_OR:
78  this->binary_op(BinaryOpCode::OR, result, rhs.at(0), rhs.at(3));
79  break;
80  case Teuchos::MathExpr::PROD_AND:
81  this->binary_op(BinaryOpCode::AND, result, rhs.at(0), rhs.at(3));
82  break;
83  case Teuchos::MathExpr::PROD_GT:
84  this->binary_op(BinaryOpCode::GT, result, rhs.at(0), rhs.at(3));
85  break;
86  case Teuchos::MathExpr::PROD_LT:
87  this->binary_op(BinaryOpCode::LT, result, rhs.at(0), rhs.at(3));
88  break;
89  case Teuchos::MathExpr::PROD_GEQ:
90  this->binary_op(BinaryOpCode::GEQ, result, rhs.at(0), rhs.at(3));
91  break;
92  case Teuchos::MathExpr::PROD_LEQ:
93  this->binary_op(BinaryOpCode::LEQ, result, rhs.at(0), rhs.at(3));
94  break;
95  case Teuchos::MathExpr::PROD_EQ:
96  this->binary_op(BinaryOpCode::EQ, result, rhs.at(0), rhs.at(3));
97  break;
98  case Teuchos::MathExpr::PROD_BOOL_PARENS:
99  swap(result, rhs.at(2));
100  break;
101  case Teuchos::MathExpr::PROD_ADD:
102  this->binary_op(BinaryOpCode::ADD, result, rhs.at(0), rhs.at(3));
103  break;
104  case Teuchos::MathExpr::PROD_SUB:
105  this->binary_op(BinaryOpCode::SUB, result, rhs.at(0), rhs.at(3));
106  break;
107  case Teuchos::MathExpr::PROD_MUL:
108  this->binary_op(BinaryOpCode::MUL, result, rhs.at(0), rhs.at(3));
109  break;
110  case Teuchos::MathExpr::PROD_DIV:
111  this->binary_op(BinaryOpCode::DIV, result, rhs.at(0), rhs.at(3));
112  break;
113  case Teuchos::MathExpr::PROD_POW:
114  this->binary_op(BinaryOpCode::POW, result, rhs.at(0), rhs.at(3));
115  break;
116  case Teuchos::MathExpr::PROD_CALL: {
117  std::string const& name = Teuchos::any_ref_cast<std::string>(rhs.at(0));
118  auto it = symbol_map.find(name);
120  "symbol \"" << name << "\" being called doesn't exist!");
121  Function& func = Teuchos::any_ref_cast<Function>(it->second);
122  std::vector<Teuchos::any>& args = Teuchos::any_ref_cast<std::vector<Teuchos::any>>(rhs.at(4));
123  func(name, result, args);
124  break;
125  }
126  case Teuchos::MathExpr::PROD_NO_ARGS: {
127  result = std::vector<Teuchos::any>{};
128  break;
129  }
130  case Teuchos::MathExpr::PROD_FIRST_ARG: {
131  std::vector<Teuchos::any>& args = Teuchos::make_any_ref<std::vector<Teuchos::any>>(result);
132  args.push_back(Teuchos::any{});
133  swap(args.back(), rhs.at(0));
134  break;
135  }
136  case Teuchos::MathExpr::PROD_NEXT_ARG: {
137  swap(result, rhs.at(0));
138  std::vector<Teuchos::any>& args = Teuchos::any_ref_cast<std::vector<Teuchos::any>>(result);
139  args.push_back(Teuchos::any{});
140  swap(args.back(), rhs.at(3));
141  break;
142  }
143  case Teuchos::MathExpr::PROD_NEG:
144  this->neg_op(result, rhs.at(2));
145  break;
146  case Teuchos::MathExpr::PROD_VAL_PARENS:
147  swap(result, rhs.at(2));
148  break;
149  case Teuchos::MathExpr::PROD_CONST:
150  swap(result, rhs.at(0));
151  break;
152  case Teuchos::MathExpr::PROD_VAR:
153  std::string const& name = Teuchos::any_ref_cast<std::string>(rhs.at(0));
154  auto it = symbol_map.find(name);
156  "symbol " << name << " being referenced doesn't exist!");
157  result = it->second;
158  break;
159  }
160 }
161 
163  bool cond_is_many;
164  bool cond_is_bool;
165  this->inspect_arg(cond, cond_is_many, cond_is_bool);
167  "Ternary condition is not of boolean type!");
168  bool is_many[2];
169  bool is_bool[2];
170  this->inspect_arg(left, is_many[0], is_bool[0]);
171  this->inspect_arg(right, is_many[1], is_bool[1]);
173  "Boolean values in ternary operator not yet supported");
174  if (!cond_is_many) {
175  auto cond_value = Teuchos::any_cast<Kokkos::View<bool const>>(cond);
176  auto host_cond_value = Kokkos::create_mirror_view(cond_value);
177  Kokkos::deep_copy(host_cond_value, cond_value);
178  if (host_cond_value()) {
179  swap(result, left);
180  } else {
181  swap(result, right);
182  }
183  } else {
184  if (!is_many[0] && !is_many[1]) {
185  this->single_single_ternary_op(result, cond, left, right);
186  } else if (!is_many[0] && is_many[1]) {
187  this->single_many_ternary_op(result, cond, left, right);
188  } else if (is_many[0] && !is_many[1]) {
189  this->many_single_ternary_op(result, cond, left, right);
190  } else if (is_many[0] && is_many[1]) {
191  this->many_many_ternary_op(result, cond, left, right);
192  }
193  }
194 }
195 
196 static const char* get_op_syntax(BinaryOpCode code) {
197  switch (code) {
198  case BinaryOpCode::OR: return "||";
199  case BinaryOpCode::AND: return "&&";
200  case BinaryOpCode::GT: return ">";
201  case BinaryOpCode::LT: return "<";
202  case BinaryOpCode::GEQ: return ">=";
203  case BinaryOpCode::LEQ: return "<=";
204  case BinaryOpCode::EQ: return "==";
205  case BinaryOpCode::ADD: return "+";
206  case BinaryOpCode::SUB: return "-";
207  case BinaryOpCode::MUL: return "*";
208  case BinaryOpCode::DIV: return "/";
209  case BinaryOpCode::POW: return "^";
210  }
211  return "";
212 }
213 
215  bool is_many[2];
216  bool is_bool[2];
217  this->inspect_arg(left, is_many[0], is_bool[0]);
218  this->inspect_arg(right, is_many[1], is_bool[1]);
219  bool expect_booleans = (code == BinaryOpCode::AND || code == BinaryOpCode::OR);
220  TEUCHOS_TEST_FOR_EXCEPTION(is_bool[0] != expect_booleans, Teuchos::ParserFail,
221  "Left argument to '" << get_op_syntax(code) << "' is " << (is_bool[0] ? "" : "not") << " boolean!");
222  TEUCHOS_TEST_FOR_EXCEPTION(is_bool[1] != expect_booleans, Teuchos::ParserFail,
223  "Right argument to '" << get_op_syntax(code) << "' is " << (is_bool[0] ? "" : "not") << " boolean!");
224  if (!is_many[0] && !is_many[1]) {
225  this->single_single_binary_op(code, result, left, right);
226  } else if (!is_many[0] && is_many[1]) {
227  this->single_many_binary_op(code, result, left, right);
228  } else if (is_many[0] && !is_many[1]) {
229  this->many_single_binary_op(code, result, left, right);
230  } else if (is_many[0] && is_many[1]) {
231  this->many_many_binary_op(code, result, left, right);
232  }
233 }
234 
236  bool is_many;
237  bool is_bool;
238  this->inspect_arg(right, is_many, is_bool);
240  "Can't negate a boolean");
241  if (is_many) {
242  this->many_neg_op(result, right);
243  } else {
244  this->single_neg_op(result, right);
245  }
246 }
247 
248 }} // end namespace panzer::Expr
virtual void many_many_binary_op(BinaryOpCode code, Teuchos::any &result, Teuchos::any &left, Teuchos::any &right)=0
virtual void make_constant(Teuchos::any &result, double const &value)=0
BinaryOpCode
Denotes the native binary operators in the Teuchos::MathExpr language.
virtual void many_many_ternary_op(Teuchos::any &result, Teuchos::any &cond, Teuchos::any &left, Teuchos::any &right)=0
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
virtual void single_single_ternary_op(Teuchos::any &result, Teuchos::any &cond, Teuchos::any &left, Teuchos::any &right)=0
std::function< void(std::string const &name, Teuchos::any &, std::vector< Teuchos::any > &rhs)> Function
The type of user-defined functions which are callable in the math language.
virtual void many_neg_op(Teuchos::any &result, Teuchos::any &right)=0
virtual void inspect_arg(Teuchos::any const &arg, bool &is_many, bool &is_bool)=0
void ternary_op(Teuchos::any &result, Teuchos::any &cond, Teuchos::any &left, Teuchos::any &right)
Executes the ternary operator, e.g. (a &gt; b) ? a : b.
void at_reduce(Teuchos::any &result, int prod, std::vector< Teuchos::any > &rhs) override
Called at every reduced production in the math language.
void binary_op(BinaryOpCode code, Teuchos::any &result, Teuchos::any &left, Teuchos::any &right)
Executes a binary operator.
void set(std::string const &name, Function const &value)
Registers an EvalBase::Function, binding it to a name and making it callable.
PHX::MDField< ScalarT, panzer::Cell, panzer::IP > result
A field that will be used to build up the result of the integral we&#39;re performing.
virtual void single_single_binary_op(BinaryOpCode code, Teuchos::any &result, Teuchos::any &left, Teuchos::any &right)=0
virtual void many_single_ternary_op(Teuchos::any &result, Teuchos::any &cond, Teuchos::any &left, Teuchos::any &right)=0
std::map< std::string, Teuchos::any > symbol_map
Stores all current symbols including variables and functions.
static const char * get_op_syntax(BinaryOpCode code)
virtual void single_neg_op(Teuchos::any &result, Teuchos::any &right)=0
virtual void single_many_binary_op(BinaryOpCode code, Teuchos::any &result, Teuchos::any &left, Teuchos::any &right)=0
void neg_op(Teuchos::any &result, Teuchos::any &right)
Executes the only native unary operator in the math language, numeric negation via a minus sign...
void at_shift(Teuchos::any &result, int token, std::string &text) override
Called at every parsed token in the math language.
virtual void many_single_binary_op(BinaryOpCode code, Teuchos::any &result, Teuchos::any &left, Teuchos::any &right)=0
virtual void single_many_ternary_op(Teuchos::any &result, Teuchos::any &cond, Teuchos::any &left, Teuchos::any &right)=0