Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://mooseframework.inl.gov
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 <vector>
13 : #include <ostream>
14 : #include <sstream>
15 : #include <iomanip>
16 :
17 : #include "MooseError.h"
18 : #include "libmesh/libmesh_common.h"
19 :
20 : using namespace libMesh;
21 :
22 : /**
23 : * ExpressionBuilder adds an interface to derived classes that enables
24 : * convenient construction of FParser expressions through operator overloading.
25 : * It exposes the new types EBTerm and EBFunction
26 : * Variables used in your expressions are of type EBTerm. The following declares
27 : * three variables that can be used in an expression:
28 : *
29 : * EBTerm c1("c1"), c2("c3"), phi("phi");
30 : *
31 : * Declare a function 'G' and define it. Note the double bracket syntax '(())'':
32 : *
33 : * EBFunction G;
34 : * G((c1, c2, c3)) = c1 + 2 * c2 + 3 * pow(c3, 2);
35 : *
36 : * Performing a substitution is as easy as:
37 : * EBFunction H;
38 : * H((c1, c2)) = G((c1, c2, 1-c1-c2))
39 : *
40 : * Use the ```<<``` io operator to output functions or terms. Or use explicit or
41 : * implicit casts from EBFunction to std::string``` to pass a function to the
42 : * FParser Parse method. FParser variables are built using the ```args()``` method.
43 : *
44 : * FunctionParserADBase<Real> GParser;
45 : * GParser.Parse(G, G.args);
46 : */
47 : class ExpressionBuilder
48 : {
49 : public:
50 : ExpressionBuilder(){};
51 :
52 : // forward delcarations
53 : class EBTerm;
54 : class EBTermNode;
55 : class EBFunction;
56 : class EBSubstitutionRule;
57 : typedef std::vector<EBTerm> EBTermList;
58 : typedef std::vector<EBTermNode *> EBTermNodeList;
59 : typedef std::vector<const EBSubstitutionRule *> EBSubstitutionRuleList;
60 :
61 : /// Base class for nodes in the expression tree
62 : class EBTermNode
63 : {
64 : public:
65 : virtual ~EBTermNode(){};
66 : virtual EBTermNode * clone() const = 0;
67 :
68 : virtual std::string stringify() const = 0;
69 8451 : virtual unsigned int substitute(const EBSubstitutionRuleList & /*rule*/) { return 0; }
70 : virtual int precedence() const = 0;
71 38124 : friend std::ostream & operator<<(std::ostream & os, const EBTermNode & node)
72 : {
73 76248 : return os << node.stringify();
74 : }
75 : };
76 :
77 : /// Template class for leaf nodes holding numbers in the expression tree
78 : template <typename T>
79 : class EBNumberNode : public EBTermNode
80 : {
81 : T _value;
82 :
83 : public:
84 87754 : EBNumberNode(T value) : _value(value){};
85 77368 : virtual EBNumberNode<T> * clone() const { return new EBNumberNode(_value); }
86 :
87 : virtual std::string stringify() const;
88 14809 : virtual int precedence() const { return 0; }
89 : };
90 :
91 : /// Template class for leaf nodes holding symbols (i.e. variables) in the expression tree
92 : class EBSymbolNode : public EBTermNode
93 : {
94 : std::string _symbol;
95 :
96 : public:
97 94995 : EBSymbolNode(std::string symbol) : _symbol(symbol){};
98 185202 : virtual EBSymbolNode * clone() const { return new EBSymbolNode(_symbol); }
99 :
100 : virtual std::string stringify() const;
101 14736 : virtual int precedence() const { return 0; }
102 : };
103 :
104 : /**
105 : * Template class for leaf nodes holding anonymous IDs in the expression tree.
106 : * No such node must be left in the final expression that is serialized and passed to FParser
107 : */
108 : class EBTempIDNode : public EBTermNode
109 : {
110 : unsigned long _id;
111 :
112 : public:
113 2220 : EBTempIDNode(unsigned int id) : _id(id){};
114 0 : virtual EBTempIDNode * clone() const { return new EBTempIDNode(_id); }
115 :
116 : virtual std::string stringify() const; // returns "[idnumber]"
117 0 : virtual int precedence() const { return 0; }
118 : };
119 :
120 : /// Base class for nodes with a single sub node (i.e. functions or operators taking one argument)
121 : class EBUnaryTermNode : public EBTermNode
122 : {
123 : public:
124 4408 : EBUnaryTermNode(EBTermNode * subnode) : _subnode(subnode){};
125 4408 : virtual ~EBUnaryTermNode() { delete _subnode; };
126 :
127 : virtual unsigned int substitute(const EBSubstitutionRuleList & rule);
128 49 : const EBTermNode * getSubnode() const { return _subnode; }
129 :
130 : protected:
131 : EBTermNode * _subnode;
132 : };
133 :
134 : /// Node representing a function with two arguments
135 : class EBUnaryFuncTermNode : public EBUnaryTermNode
136 : {
137 : public:
138 : enum NodeType
139 : {
140 : SIN,
141 : COS,
142 : TAN,
143 : ABS,
144 : LOG,
145 : LOG2,
146 : LOG10,
147 : EXP,
148 : SINH,
149 : COSH,
150 : TANH
151 : } _type;
152 :
153 : EBUnaryFuncTermNode(EBTermNode * subnode, NodeType type)
154 4033 : : EBUnaryTermNode(subnode), _type(type){};
155 3408 : virtual EBUnaryFuncTermNode * clone() const
156 : {
157 3408 : return new EBUnaryFuncTermNode(_subnode->clone(), _type);
158 : };
159 :
160 : virtual std::string stringify() const;
161 1128 : virtual int precedence() const { return 2; }
162 : };
163 :
164 : /// Node representing a unary operator
165 : class EBUnaryOpTermNode : public EBUnaryTermNode
166 : {
167 : public:
168 : enum NodeType
169 : {
170 : NEG,
171 : LOGICNOT
172 : } _type;
173 :
174 : EBUnaryOpTermNode(EBTermNode * subnode, NodeType type)
175 375 : : EBUnaryTermNode(subnode), _type(type){};
176 325 : virtual EBUnaryOpTermNode * clone() const
177 : {
178 325 : return new EBUnaryOpTermNode(_subnode->clone(), _type);
179 : };
180 :
181 : virtual std::string stringify() const;
182 101 : virtual int precedence() const { return 3; }
183 : };
184 :
185 : /// Base class for nodes with two sub nodes (i.e. functions or operators taking two arguments)
186 : class EBBinaryTermNode : public EBTermNode
187 : {
188 : public:
189 141266 : EBBinaryTermNode(EBTermNode * left, EBTermNode * right) : _left(left), _right(right){};
190 141266 : virtual ~EBBinaryTermNode()
191 141266 : {
192 141266 : delete _left;
193 141266 : delete _right;
194 141266 : };
195 :
196 : virtual unsigned int substitute(const EBSubstitutionRuleList & rule);
197 :
198 : protected:
199 : EBTermNode * _left;
200 : EBTermNode * _right;
201 : };
202 :
203 : /// Node representing a binary operator
204 : class EBBinaryOpTermNode : public EBBinaryTermNode
205 : {
206 : public:
207 : enum NodeType
208 : {
209 : ADD,
210 : SUB,
211 : MUL,
212 : DIV,
213 : MOD,
214 : POW,
215 : LESS,
216 : GREATER,
217 : LESSEQ,
218 : GREATEREQ,
219 : EQ,
220 : NOTEQ
221 : };
222 :
223 : EBBinaryOpTermNode(EBTermNode * left, EBTermNode * right, NodeType type)
224 140949 : : EBBinaryTermNode(left, right), _type(type){};
225 122875 : virtual EBBinaryOpTermNode * clone() const
226 : {
227 122875 : return new EBBinaryOpTermNode(_left->clone(), _right->clone(), _type);
228 : };
229 :
230 : virtual std::string stringify() const;
231 : virtual int precedence() const;
232 :
233 : protected:
234 : NodeType _type;
235 : };
236 :
237 : /// Node representing a function with two arguments
238 : class EBBinaryFuncTermNode : public EBBinaryTermNode
239 : {
240 : public:
241 : enum NodeType
242 : {
243 : MIN,
244 : MAX,
245 : ATAN2,
246 : HYPOT,
247 : PLOG
248 : } _type;
249 :
250 : EBBinaryFuncTermNode(EBTermNode * left, EBTermNode * right, NodeType type)
251 49 : : EBBinaryTermNode(left, right), _type(type){};
252 240 : virtual EBBinaryFuncTermNode * clone() const
253 : {
254 240 : return new EBBinaryFuncTermNode(_left->clone(), _right->clone(), _type);
255 : };
256 :
257 : virtual std::string stringify() const;
258 120 : virtual int precedence() const { return 2; }
259 : };
260 :
261 : /// Base class for nodes with two sub nodes (i.e. functions or operators taking two arguments)
262 : class EBTernaryTermNode : public EBBinaryTermNode
263 : {
264 : public:
265 : EBTernaryTermNode(EBTermNode * left, EBTermNode * middle, EBTermNode * right)
266 3 : : EBBinaryTermNode(left, right), _middle(middle){};
267 3 : virtual ~EBTernaryTermNode() { delete _middle; };
268 :
269 : virtual unsigned int substitute(const EBSubstitutionRuleList & rule);
270 :
271 : protected:
272 : EBTermNode * _middle;
273 : };
274 :
275 : /// Node representing a function with three arguments
276 : class EBTernaryFuncTermNode : public EBTernaryTermNode
277 : {
278 : public:
279 : enum NodeType
280 : {
281 : CONDITIONAL
282 : } _type;
283 :
284 : EBTernaryFuncTermNode(EBTermNode * left, EBTermNode * middle, EBTermNode * right, NodeType type)
285 3 : : EBTernaryTermNode(left, middle, right), _type(type){};
286 0 : virtual EBTernaryFuncTermNode * clone() const
287 : {
288 0 : return new EBTernaryFuncTermNode(_left->clone(), _middle->clone(), _right->clone(), _type);
289 : };
290 :
291 : virtual std::string stringify() const;
292 0 : virtual int precedence() const { return 2; }
293 : };
294 :
295 : /**
296 : * Substitution rule functor base class to perform flexible term substitutions
297 : */
298 : class EBSubstitutionRule
299 : {
300 : public:
301 : virtual EBTermNode * apply(const EBTermNode *) const = 0;
302 : virtual ~EBSubstitutionRule() {}
303 : };
304 :
305 : /**
306 : * Substitution rule base class that applies to nodes of type Node_T
307 : */
308 : template <class Node_T>
309 : class EBSubstitutionRuleTyped : public EBSubstitutionRule
310 : {
311 : public:
312 : virtual EBTermNode * apply(const EBTermNode *) const;
313 :
314 : protected:
315 : // on successful substitution this returns a new node to replace the old one, otherwise it
316 : // returns NULL
317 : virtual EBTermNode * substitute(const Node_T &) const = 0;
318 : };
319 :
320 : /**
321 : * Generic Substitution rule to replace all occurences of a given symbol node
322 : * term with a user defined term. This is used by EBFunction.
323 : */
324 : class EBTermSubstitution : public EBSubstitutionRuleTyped<EBSymbolNode>
325 : {
326 : public:
327 : EBTermSubstitution(const EBTerm & find, const EBTerm & replace);
328 3077 : virtual ~EBTermSubstitution() { delete _replace; }
329 :
330 : protected:
331 : virtual EBTermNode * substitute(const EBSymbolNode &) const;
332 : std::string _find;
333 : EBTermNode * _replace;
334 : };
335 :
336 : /**
337 : * Substitution rule to replace all occurences of log(x) with plog(x, epsilon)
338 : * with a user defined term for epsilon.
339 : */
340 : class EBLogPlogSubstitution : public EBSubstitutionRuleTyped<EBUnaryFuncTermNode>
341 : {
342 : public:
343 25 : EBLogPlogSubstitution(const EBTerm & epsilon) : _epsilon(epsilon.cloneRoot())
344 : {
345 : mooseAssert(_epsilon != NULL, "Epsilon must not be an empty term in EBLogPlogSubstitution");
346 : }
347 25 : virtual ~EBLogPlogSubstitution() { delete _epsilon; }
348 :
349 : protected:
350 : virtual EBTermNode * substitute(const EBUnaryFuncTermNode &) const;
351 : EBTermNode * _epsilon;
352 : };
353 :
354 : /**
355 : * User facing host object for an expression tree. Each EBTerm contains a _root
356 : * node pointer to an EBTermNode object. The _root pointer should never be NULL,
357 : * but it should be safe if it ever is. The default constructor assigns a
358 : * EBTempIDNode to _root with a unique ID.
359 : */
360 : class EBTerm
361 : {
362 : public:
363 : // the default constructor assigns a temporary id node to root we use the address of the
364 : // current EBTerm object as the ID. This could be problematic if we create and destroy terms,
365 : // but then we should not expect the substitution to do sane things anyways.
366 2220 : __attribute__((noinline)) EBTerm()
367 2220 : : _root(new EBTempIDNode(reinterpret_cast<unsigned long long>(this))) {};
368 :
369 7039 : EBTerm(const EBTerm & term) : _root(term.cloneRoot()){};
370 32824 : ~EBTerm() { delete _root; };
371 :
372 : private:
373 : // construct a term from a node
374 18777 : EBTerm(EBTermNode * root) : _root(root){};
375 :
376 : public:
377 : // construct from number or string
378 1 : EBTerm(int number) : _root(new EBNumberNode<int>(number)) {}
379 2041 : EBTerm(Real number) : _root(new EBNumberNode<Real>(number)) {}
380 4788 : EBTerm(const char * symbol) : _root(new EBSymbolNode(symbol)) {}
381 :
382 : // concatenate terms to form a parameter list with (()) syntax (those need to be out-of-class!)
383 : friend EBTermList operator,(const ExpressionBuilder::EBTerm & larg,
384 : const ExpressionBuilder::EBTerm & rarg);
385 : friend EBTermList operator,(const ExpressionBuilder::EBTerm & larg,
386 : const ExpressionBuilder::EBTermList & rargs);
387 : friend EBTermList operator,(const ExpressionBuilder::EBTermList & largs,
388 : const ExpressionBuilder::EBTerm & rarg);
389 :
390 : // dump term as FParser expression
391 : friend std::ostream & operator<<(std::ostream & os, const EBTerm & term);
392 : // cast into a string
393 277 : operator std::string() const { return _root->stringify(); }
394 :
395 : // assign a term
396 2231 : EBTerm & operator=(const EBTerm & term)
397 : {
398 2231 : delete _root;
399 2231 : _root = term.cloneRoot();
400 2231 : return *this;
401 : }
402 :
403 : // perform a substitution (returns substituton count)
404 : unsigned int substitute(const EBSubstitutionRule & rule);
405 : unsigned int substitute(const EBSubstitutionRuleList & rules);
406 :
407 3080 : const EBTermNode * getRoot() const { return _root; }
408 39725 : EBTermNode * cloneRoot() const { return _root == NULL ? NULL : _root->clone(); }
409 :
410 : protected:
411 : EBTermNode * _root;
412 :
413 : public:
414 : /**
415 : * Unary operators
416 : */
417 : #define UNARY_OP_IMPLEMENT(op, OP) \
418 : EBTerm operator op() const \
419 : { \
420 : mooseAssert(_root != NULL, "Empty term provided for unary operator " #op); \
421 : return EBTerm(new EBUnaryOpTermNode(cloneRoot(), EBUnaryOpTermNode::OP)); \
422 : }
423 50 : UNARY_OP_IMPLEMENT(-, NEG)
424 : UNARY_OP_IMPLEMENT(!, LOGICNOT)
425 :
426 : /**
427 : * Unary functions
428 : */
429 : friend EBTerm sin(const EBTerm &);
430 : friend EBTerm cos(const EBTerm &);
431 : friend EBTerm tan(const EBTerm &);
432 : friend EBTerm abs(const EBTerm &);
433 : friend EBTerm log(const EBTerm &);
434 : friend EBTerm log2(const EBTerm &);
435 : friend EBTerm log10(const EBTerm &);
436 : friend EBTerm exp(const EBTerm &);
437 : friend EBTerm sinh(const EBTerm &);
438 : friend EBTerm cosh(const EBTerm &);
439 : friend EBTerm tanh(const EBTerm &);
440 :
441 : /*
442 : * Binary operators (including number,term operations)
443 : */
444 : #define BINARY_OP_IMPLEMENT(op, OP) \
445 : EBTerm operator op(const EBTerm & term) const \
446 : { \
447 : mooseAssert(_root != NULL, "Empty term provided on left side of operator " #op); \
448 : mooseAssert(term._root != NULL, "Empty term provided on right side of operator " #op); \
449 : return EBTerm(new EBBinaryOpTermNode(cloneRoot(), term.cloneRoot(), EBBinaryOpTermNode::OP)); \
450 : } \
451 : friend EBTerm operator op(int left, const EBTerm & right) \
452 : { \
453 : mooseAssert(right._root != NULL, "Empty term provided on right side of operator " #op); \
454 : return EBTerm(new EBBinaryOpTermNode( \
455 : new EBNumberNode<int>(left), right.cloneRoot(), EBBinaryOpTermNode::OP)); \
456 : } \
457 : friend EBTerm operator op(Real left, const EBTerm & right) \
458 : { \
459 : mooseAssert(right._root != NULL, "Empty term provided on right side of operator " #op); \
460 : return EBTerm(new EBBinaryOpTermNode( \
461 : new EBNumberNode<Real>(left), right.cloneRoot(), EBBinaryOpTermNode::OP)); \
462 : } \
463 : friend EBTerm operator op(const EBFunction & left, const EBTerm & right) \
464 : { \
465 : mooseAssert(EBTerm(left)._root != NULL, "Empty term provided on left side of operator " #op); \
466 : mooseAssert(right._root != NULL, "Empty term provided on right side of operator " #op); \
467 : return EBTerm(new EBBinaryOpTermNode( \
468 : EBTerm(left).cloneRoot(), right.cloneRoot(), EBBinaryOpTermNode::OP)); \
469 : } \
470 : friend EBTerm operator op(const EBFunction & left, const EBFunction & right); \
471 : friend EBTerm operator op(int left, const EBFunction & right); \
472 : friend EBTerm operator op(Real left, const EBFunction & right);
473 3472 : BINARY_OP_IMPLEMENT(+, ADD)
474 3150 : BINARY_OP_IMPLEMENT(-, SUB)
475 8435 : BINARY_OP_IMPLEMENT(*, MUL)
476 819 : BINARY_OP_IMPLEMENT(/, DIV)
477 1 : BINARY_OP_IMPLEMENT(%, MOD)
478 4 : BINARY_OP_IMPLEMENT(<, LESS)
479 1 : BINARY_OP_IMPLEMENT(>, GREATER)
480 1 : BINARY_OP_IMPLEMENT(<=, LESSEQ)
481 1 : BINARY_OP_IMPLEMENT(>=, GREATEREQ)
482 1 : BINARY_OP_IMPLEMENT(==, EQ)
483 1 : BINARY_OP_IMPLEMENT(!=, NOTEQ)
484 :
485 : /*
486 : * Compound assignment operators
487 : */
488 : #define BINARYCOMP_OP_IMPLEMENT(op, OP) \
489 : EBTerm & operator op(const EBTerm & term) \
490 : { \
491 : mooseAssert(_root != NULL, "Empty term provided on left side of operator " #op); \
492 : mooseAssert(term._root != NULL, "Empty term provided on right side of operator " #op); \
493 : if (dynamic_cast<EBTempIDNode *>(_root)) \
494 : mooseError("Using compound assignment operator on anonymous term. Set it to 0 first!"); \
495 : _root = new EBBinaryOpTermNode(_root, term.cloneRoot(), EBBinaryOpTermNode::OP); \
496 : return *this; \
497 : }
498 : BINARYCOMP_OP_IMPLEMENT(+=, ADD)
499 : BINARYCOMP_OP_IMPLEMENT(-=, SUB)
500 : BINARYCOMP_OP_IMPLEMENT(*=, MUL)
501 : BINARYCOMP_OP_IMPLEMENT(/=, DIV)
502 : BINARYCOMP_OP_IMPLEMENT(%=, MOD)
503 :
504 : /**
505 : * @{
506 : * Binary functions
507 : */
508 : friend EBTerm min(const EBTerm &, const EBTerm &);
509 : friend EBTerm max(const EBTerm &, const EBTerm &);
510 : friend EBTerm pow(const EBTerm &, const EBTerm &);
511 : template <typename T>
512 : friend EBTerm pow(const EBTerm &, T exponent);
513 : friend EBTerm atan2(const EBTerm &, const EBTerm &);
514 : friend EBTerm hypot(const EBTerm &, const EBTerm &);
515 : friend EBTerm plog(const EBTerm &, const EBTerm &);
516 : ///@}
517 :
518 : /**
519 : * Ternary functions
520 : */
521 : friend EBTerm conditional(const EBTerm &, const EBTerm &, const EBTerm &);
522 : };
523 :
524 : /// User facing host object for a function. This combines a term with an argument list.
525 : class EBFunction
526 : {
527 : public:
528 974 : EBFunction(){};
529 :
530 : /// @{
531 : /// set the temporary argument list which is either used for evaluation
532 : /// or committed to the argument list upon function definition (assignment)
533 : EBFunction & operator()(const EBTerm & arg);
534 : EBFunction & operator()(const EBTermList & args);
535 : /// @}
536 :
537 : /// @{
538 : /// convenience operators to allow single bracket syntax
539 48 : EBFunction & operator()(const EBTerm & a1, const EBTerm & a2) { return (*this)((a1, a2)); }
540 244 : EBFunction & operator()(const EBTerm & a1, const EBTerm & a2, const EBTerm & a3)
541 : {
542 244 : return (*this)((a1, a2, a3));
543 : }
544 : EBFunction &
545 : operator()(const EBTerm & a1, const EBTerm & a2, const EBTerm & a3, const EBTerm & a4)
546 : {
547 : return (*this)((a1, a2, a3, a4));
548 : }
549 : EBFunction & operator()(const EBTerm & a1,
550 : const EBTerm & a2,
551 : const EBTerm & a3,
552 : const EBTerm & a4,
553 : const EBTerm & a5)
554 : {
555 : return (*this)((a1, a2, a3, a4, a5));
556 : }
557 5 : EBFunction & operator()(const EBTerm & a1,
558 : const EBTerm & a2,
559 : const EBTerm & a3,
560 : const EBTerm & a4,
561 : const EBTerm & a5,
562 : const EBTerm & a6)
563 : {
564 5 : return (*this)((a1, a2, a3, a4, a5, a6));
565 : }
566 : EBFunction & operator()(const EBTerm & a1,
567 : const EBTerm & a2,
568 : const EBTerm & a3,
569 : const EBTerm & a4,
570 : const EBTerm & a5,
571 : const EBTerm & a6,
572 : const EBTerm & a7)
573 : {
574 : return (*this)((a1, a2, a3, a4, a5, a6, a7));
575 : }
576 : EBFunction & operator()(const EBTerm & a1,
577 : const EBTerm & a2,
578 : const EBTerm & a3,
579 : const EBTerm & a4,
580 : const EBTerm & a5,
581 : const EBTerm & a6,
582 : const EBTerm & a7,
583 : const EBTerm & a8)
584 : {
585 : return (*this)((a1, a2, a3, a4, a5, a6, a7, a8));
586 : }
587 : EBFunction & operator()(const EBTerm & a1,
588 : const EBTerm & a2,
589 : const EBTerm & a3,
590 : const EBTerm & a4,
591 : const EBTerm & a5,
592 : const EBTerm & a6,
593 : const EBTerm & a7,
594 : const EBTerm & a8,
595 : const EBTerm & a9)
596 : {
597 : return (*this)((a1, a2, a3, a4, a5, a6, a7, a8, a9));
598 : }
599 : /// @}
600 :
601 : /// cast an EBFunction into an EBTerm
602 : operator EBTerm() const;
603 :
604 : /// cast into a string (via the cast into a term above)
605 : operator std::string() const;
606 :
607 : /// @{
608 : /// function definition (assignment)
609 : EBFunction & operator=(const EBTerm &);
610 : EBFunction & operator=(const EBFunction &);
611 : /// @}
612 :
613 : /// get the list of arguments and check if they are all symbols
614 : std::string args();
615 :
616 : /// @{
617 : /// Unary operators on functions
618 1 : EBTerm operator-() { return -EBTerm(*this); }
619 : EBTerm operator!() { return !EBTerm(*this); }
620 : /// @}
621 :
622 : // perform a substitution (returns substituton count)
623 : unsigned int substitute(const EBSubstitutionRule & rule);
624 : unsigned int substitute(const EBSubstitutionRuleList & rules);
625 :
626 : protected:
627 : /// argument list the function is declared with
628 : EBTermList _arguments;
629 : /// argument list passed in when evaluating the function
630 : EBTermList _eval_arguments;
631 :
632 : // underlying term that the _eval_arguments are substituted in
633 : EBTerm _term;
634 : };
635 :
636 : /*
637 : * Binary operators
638 : */
639 : #define BINARYFUNC_OP_IMPLEMENT(op, OP) \
640 : friend EBTerm operator op(const EBFunction & left, const EBFunction & right) \
641 : { \
642 : mooseAssert(EBTerm(left)._root != NULL, "Empty term provided on left side of operator " #op); \
643 : mooseAssert(EBTerm(right)._root != NULL, \
644 : "Empty term provided on right side of operator " #op); \
645 : return EBTerm(new EBBinaryOpTermNode( \
646 : EBTerm(left).cloneRoot(), EBTerm(right).cloneRoot(), EBBinaryOpTermNode::OP)); \
647 : } \
648 : friend EBTerm operator op(int left, const EBFunction & right) \
649 : { \
650 : mooseAssert(EBTerm(right)._root != NULL, \
651 : "Empty term provided on right side of operator " #op); \
652 : return EBTerm(new EBBinaryOpTermNode( \
653 : new EBNumberNode<int>(left), EBTerm(right).cloneRoot(), EBBinaryOpTermNode::OP)); \
654 : } \
655 : friend EBTerm operator op(Real left, const EBFunction & right) \
656 : { \
657 : mooseAssert(EBTerm(right)._root != NULL, \
658 : "Empty term provided on right side of operator " #op); \
659 : return EBTerm(new EBBinaryOpTermNode( \
660 : new EBNumberNode<Real>(left), EBTerm(right).cloneRoot(), EBBinaryOpTermNode::OP)); \
661 : }
662 1 : BINARYFUNC_OP_IMPLEMENT(+, ADD)
663 0 : BINARYFUNC_OP_IMPLEMENT(-, SUB)
664 : BINARYFUNC_OP_IMPLEMENT(*, MUL)
665 : BINARYFUNC_OP_IMPLEMENT(/, DIV)
666 : BINARYFUNC_OP_IMPLEMENT(%, MOD)
667 : BINARYFUNC_OP_IMPLEMENT(<, LESS)
668 : BINARYFUNC_OP_IMPLEMENT(>, GREATER)
669 : BINARYFUNC_OP_IMPLEMENT(<=, LESSEQ)
670 : BINARYFUNC_OP_IMPLEMENT(>=, GREATEREQ)
671 : BINARYFUNC_OP_IMPLEMENT(==, EQ)
672 : BINARYFUNC_OP_IMPLEMENT(!=, NOTEQ)
673 : };
674 :
675 : // convenience function for numeric exponent
676 : template <typename T>
677 : ExpressionBuilder::EBTerm
678 2185 : pow(const ExpressionBuilder::EBTerm & left, T exponent)
679 : {
680 : return ExpressionBuilder::EBTerm(
681 4370 : new ExpressionBuilder::EBBinaryOpTermNode(left.cloneRoot(),
682 2185 : new ExpressionBuilder::EBNumberNode<T>(exponent),
683 2185 : ExpressionBuilder::EBBinaryOpTermNode::POW));
684 : }
685 :
686 : // convert a number node into a string
687 : template <typename T>
688 : std::string
689 10538 : ExpressionBuilder::EBNumberNode<T>::stringify() const
690 : {
691 10538 : std::ostringstream s;
692 10538 : s << std::setprecision(12) << _value;
693 10538 : return s.str();
694 10538 : }
695 :
696 : template <class Node_T>
697 : ExpressionBuilder::EBTermNode *
698 68503 : ExpressionBuilder::EBSubstitutionRuleTyped<Node_T>::apply(
699 : const ExpressionBuilder::EBTermNode * node) const
700 : {
701 68503 : const Node_T * match_node = dynamic_cast<const Node_T *>(node);
702 68503 : if (match_node == NULL)
703 : return NULL;
704 : else
705 14105 : return substitute(*match_node);
706 : }
|