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 //
4 // Panzer: A partial differential equation assembly
5 // engine for strongly coupled complex multiphysics systems
6 // Copyright (2011) Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact Roger P. Pawlowski (rppawlo@sandia.gov) and
39 // Eric C. Cyr (eccyr@sandia.gov)
40 // ***********************************************************************
41 // @HEADER
42 
43 #include <Panzer_ExprEval_impl.hpp>
44 
45 #include <cstdlib>
46 
47 #include <Teuchos_MathExpr.hpp>
48 
49 namespace panzer
50 {
51 namespace Expr
52 {
53 
55  : Teuchos::Reader(Teuchos::MathExpr::ask_reader_tables()) {
56 }
57 
58 void EvalBase::set(std::string const& name, Function const& value) {
59  symbol_map[name] = value;
60 }
61 
62 void EvalBase::at_shift(Teuchos::any& result_any, int token, std::string& text) {
63  using std::swap;
64  switch (token) {
65  case Teuchos::MathExpr::TOK_NAME: {
66  std::string& result = Teuchos::make_any_ref<std::string>(result_any);
67  swap(result, text);
68  return;
69  }
70  case Teuchos::MathExpr::TOK_CONST: {
71  this->make_constant(result_any, std::atof(text.c_str()));
72  return;
73  }
74  }
75 }
76 
77 void EvalBase::at_reduce(Teuchos::any& result, int prod, std::vector<Teuchos::any>& rhs) {
78  using std::swap;
79  switch (prod) {
80  case Teuchos::MathExpr::PROD_PROGRAM: {
81  swap(result, rhs.at(1));
82  break;
83  }
84  case Teuchos::MathExpr::PROD_NO_STATEMENTS:
85  case Teuchos::MathExpr::PROD_NO_EXPR:
86  case Teuchos::MathExpr::PROD_NEXT_STATEMENT: {
87  break;
88  }
89  case Teuchos::MathExpr::PROD_ASSIGN: {
90  std::string const& name = Teuchos::any_ref_cast<std::string>(rhs.at(0));
91  swap(symbol_map[name], rhs.at(4));
92  break;
93  }
94  case Teuchos::MathExpr::PROD_YES_EXPR:
95  case Teuchos::MathExpr::PROD_EXPR:
96  case Teuchos::MathExpr::PROD_TERNARY_DECAY:
97  case Teuchos::MathExpr::PROD_OR_DECAY:
98  case Teuchos::MathExpr::PROD_AND_DECAY:
99  case Teuchos::MathExpr::PROD_ADD_SUB_DECAY:
100  case Teuchos::MathExpr::PROD_MUL_DIV_DECAY:
101  case Teuchos::MathExpr::PROD_POW_DECAY:
102  case Teuchos::MathExpr::PROD_NEG_DECAY:
103  case Teuchos::MathExpr::PROD_SOME_ARGS:
104  swap(result, rhs.at(0));
105  break;
106  case Teuchos::MathExpr::PROD_TERNARY:
107  this->ternary_op(result, rhs.at(0), rhs.at(3), rhs.at(6));
108  break;
109  case Teuchos::MathExpr::PROD_OR:
110  this->binary_op(BinaryOpCode::OR, result, rhs.at(0), rhs.at(3));
111  break;
112  case Teuchos::MathExpr::PROD_AND:
113  this->binary_op(BinaryOpCode::AND, result, rhs.at(0), rhs.at(3));
114  break;
115  case Teuchos::MathExpr::PROD_GT:
116  this->binary_op(BinaryOpCode::GT, result, rhs.at(0), rhs.at(3));
117  break;
118  case Teuchos::MathExpr::PROD_LT:
119  this->binary_op(BinaryOpCode::LT, result, rhs.at(0), rhs.at(3));
120  break;
121  case Teuchos::MathExpr::PROD_GEQ:
122  this->binary_op(BinaryOpCode::GEQ, result, rhs.at(0), rhs.at(3));
123  break;
124  case Teuchos::MathExpr::PROD_LEQ:
125  this->binary_op(BinaryOpCode::LEQ, result, rhs.at(0), rhs.at(3));
126  break;
127  case Teuchos::MathExpr::PROD_EQ:
128  this->binary_op(BinaryOpCode::EQ, result, rhs.at(0), rhs.at(3));
129  break;
130  case Teuchos::MathExpr::PROD_BOOL_PARENS:
131  swap(result, rhs.at(2));
132  break;
133  case Teuchos::MathExpr::PROD_ADD:
134  this->binary_op(BinaryOpCode::ADD, result, rhs.at(0), rhs.at(3));
135  break;
136  case Teuchos::MathExpr::PROD_SUB:
137  this->binary_op(BinaryOpCode::SUB, result, rhs.at(0), rhs.at(3));
138  break;
139  case Teuchos::MathExpr::PROD_MUL:
140  this->binary_op(BinaryOpCode::MUL, result, rhs.at(0), rhs.at(3));
141  break;
142  case Teuchos::MathExpr::PROD_DIV:
143  this->binary_op(BinaryOpCode::DIV, result, rhs.at(0), rhs.at(3));
144  break;
145  case Teuchos::MathExpr::PROD_POW:
146  this->binary_op(BinaryOpCode::POW, result, rhs.at(0), rhs.at(3));
147  break;
148  case Teuchos::MathExpr::PROD_CALL: {
149  std::string const& name = Teuchos::any_ref_cast<std::string>(rhs.at(0));
150  auto it = symbol_map.find(name);
152  "symbol \"" << name << "\" being called doesn't exist!");
153  Function& func = Teuchos::any_ref_cast<Function>(it->second);
154  std::vector<Teuchos::any>& args = Teuchos::any_ref_cast<std::vector<Teuchos::any>>(rhs.at(4));
155  func(name, result, args);
156  break;
157  }
158  case Teuchos::MathExpr::PROD_NO_ARGS: {
159  result = std::vector<Teuchos::any>{};
160  break;
161  }
162  case Teuchos::MathExpr::PROD_FIRST_ARG: {
163  std::vector<Teuchos::any>& args = Teuchos::make_any_ref<std::vector<Teuchos::any>>(result);
164  args.push_back(Teuchos::any{});
165  swap(args.back(), rhs.at(0));
166  break;
167  }
168  case Teuchos::MathExpr::PROD_NEXT_ARG: {
169  swap(result, rhs.at(0));
170  std::vector<Teuchos::any>& args = Teuchos::any_ref_cast<std::vector<Teuchos::any>>(result);
171  args.push_back(Teuchos::any{});
172  swap(args.back(), rhs.at(3));
173  break;
174  }
175  case Teuchos::MathExpr::PROD_NEG:
176  this->neg_op(result, rhs.at(2));
177  break;
178  case Teuchos::MathExpr::PROD_VAL_PARENS:
179  swap(result, rhs.at(2));
180  break;
181  case Teuchos::MathExpr::PROD_CONST:
182  swap(result, rhs.at(0));
183  break;
184  case Teuchos::MathExpr::PROD_VAR:
185  std::string const& name = Teuchos::any_ref_cast<std::string>(rhs.at(0));
186  auto it = symbol_map.find(name);
188  "symbol " << name << " being referenced doesn't exist!");
189  result = it->second;
190  break;
191  }
192 }
193 
195  bool cond_is_many;
196  bool cond_is_bool;
197  this->inspect_arg(cond, cond_is_many, cond_is_bool);
199  "Ternary condition is not of boolean type!");
200  bool is_many[2];
201  bool is_bool[2];
202  this->inspect_arg(left, is_many[0], is_bool[0]);
203  this->inspect_arg(right, is_many[1], is_bool[1]);
205  "Boolean values in ternary operator not yet supported");
206  if (!cond_is_many) {
207  auto cond_value = Teuchos::any_cast<Kokkos::View<bool const>>(cond);
208  auto host_cond_value = Kokkos::create_mirror_view(cond_value);
209  Kokkos::deep_copy(host_cond_value, cond_value);
210  if (host_cond_value()) {
211  swap(result, left);
212  } else {
213  swap(result, right);
214  }
215  } else {
216  if (!is_many[0] && !is_many[1]) {
217  this->single_single_ternary_op(result, cond, left, right);
218  } else if (!is_many[0] && is_many[1]) {
219  this->single_many_ternary_op(result, cond, left, right);
220  } else if (is_many[0] && !is_many[1]) {
221  this->many_single_ternary_op(result, cond, left, right);
222  } else if (is_many[0] && is_many[1]) {
223  this->many_many_ternary_op(result, cond, left, right);
224  }
225  }
226 }
227 
228 static const char* get_op_syntax(BinaryOpCode code) {
229  switch (code) {
230  case BinaryOpCode::OR: return "||";
231  case BinaryOpCode::AND: return "&&";
232  case BinaryOpCode::GT: return ">";
233  case BinaryOpCode::LT: return "<";
234  case BinaryOpCode::GEQ: return ">=";
235  case BinaryOpCode::LEQ: return "<=";
236  case BinaryOpCode::EQ: return "==";
237  case BinaryOpCode::ADD: return "+";
238  case BinaryOpCode::SUB: return "-";
239  case BinaryOpCode::MUL: return "*";
240  case BinaryOpCode::DIV: return "/";
241  case BinaryOpCode::POW: return "^";
242  }
243  return "";
244 }
245 
247  bool is_many[2];
248  bool is_bool[2];
249  this->inspect_arg(left, is_many[0], is_bool[0]);
250  this->inspect_arg(right, is_many[1], is_bool[1]);
251  bool expect_booleans = (code == BinaryOpCode::AND || code == BinaryOpCode::OR);
252  TEUCHOS_TEST_FOR_EXCEPTION(is_bool[0] != expect_booleans, Teuchos::ParserFail,
253  "Left argument to '" << get_op_syntax(code) << "' is " << (is_bool[0] ? "" : "not") << " boolean!");
254  TEUCHOS_TEST_FOR_EXCEPTION(is_bool[1] != expect_booleans, Teuchos::ParserFail,
255  "Right argument to '" << get_op_syntax(code) << "' is " << (is_bool[0] ? "" : "not") << " boolean!");
256  if (!is_many[0] && !is_many[1]) {
257  this->single_single_binary_op(code, result, left, right);
258  } else if (!is_many[0] && is_many[1]) {
259  this->single_many_binary_op(code, result, left, right);
260  } else if (is_many[0] && !is_many[1]) {
261  this->many_single_binary_op(code, result, left, right);
262  } else if (is_many[0] && is_many[1]) {
263  this->many_many_binary_op(code, result, left, right);
264  }
265 }
266 
268  bool is_many;
269  bool is_bool;
270  this->inspect_arg(right, is_many, is_bool);
272  "Can't negate a boolean");
273  if (is_many) {
274  this->many_neg_op(result, right);
275  } else {
276  this->single_neg_op(result, right);
277  }
278 }
279 
280 }} // 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