@@ -115,6 +115,15 @@ const Cinfo * Function::initCinfo()
115115 &Function::getDoEvalAtReinit
116116 );
117117
118+ static ValueFinfo< Function, bool > allowUnknownVariable (
119+ " allowUnknownVariable" ,
120+ " When *false*, expression can only have ci, xi, yi and t."
121+ " When set to *true*, expression can have arbitrary names."
122+ " Defaults to *true*. \n " ,
123+ &Function::setAllowUnknownVariable,
124+ &Function::getAllowUnknowVariable
125+ );
126+
118127 static ElementValueFinfo< Function, string > expr (
119128 " expr" ,
120129 " Mathematical expression defining the function. The underlying parser\n "
@@ -258,6 +267,7 @@ const Cinfo * Function::initCinfo()
258267 &mode,
259268 &useTrigger,
260269 &doEvalAtReinit,
270+ &allowUnknownVariable,
261271 &expr,
262272 &numVars,
263273 &inputs,
@@ -324,8 +334,9 @@ Function::Function():
324334 , mode_(1 )
325335 , useTrigger_(false )
326336 , doEvalAtReinit_(false )
337+ , allowUnknownVar_(true )
327338 , t_(0.0 )
328- , independent_(" x0 " )
339+ , independent_(" t " )
329340 , stoich_(nullptr )
330341 , parser_(shared_ptr<moose::MooseParser>(new moose::MooseParser()))
331342{
@@ -345,6 +356,8 @@ Function& Function::operator=(const Function& rhs)
345356 value_ = rhs.value_ ;
346357 mode_ = rhs.mode_ ;
347358 useTrigger_ = rhs.useTrigger_ ;
359+ doEvalAtReinit_ = rhs.doEvalAtReinit_ ;
360+ allowUnknownVar_ = rhs.allowUnknownVar_ ;
348361 t_ = rhs.t_ ;
349362 rate_ = rhs.rate_ ;
350363
@@ -357,16 +370,18 @@ Function& Function::operator=(const Function& rhs)
357370 parser_->ClearAll ();
358371 if (rhs.parser_ ->GetExpr ().size () > 0 )
359372 {
373+ // These are alreay indexed. So its OK to add them by name.
360374 for (auto x: rhs.xs_ )
361- addXByName (x->getName ());
375+ {
376+ xs_.push_back (shared_ptr<Variable>(new Variable (x->getName ())));
377+ varIndex_[x->getName ()] = xs_.size ()-1 ;
378+ }
379+ // Add all the Ys now.
362380 for (size_t i=0 ; i < rhs.ys_ .size (); i++)
363- addY (i );
364- parser_->DefineVar ( " t " , &t_);
381+ ys_. push_back (shared_ptr< double >( new double ( 0.0 )) );
382+ parser_->LinkVariables (xs_, ys_ , &t_);
365383 parser_->SetExpr (rhs.parser_ ->GetExpr ());
366384 }
367-
368- numVar_ = rhs.numVar_ ;
369-
370385 return *this ;
371386}
372387
@@ -388,6 +403,9 @@ void Function::addXByIndex(const unsigned int index)
388403{
389404 // We have only xi's in xs_.
390405 string name = ' x' +to_string (index);
406+ if (symbolExists (name))
407+ return ;
408+
391409 if (index >= xs_.size ())
392410 {
393411 for (size_t i = xs_.size (); i <= index; i++)
@@ -403,20 +421,14 @@ void Function::addXByIndex(const unsigned int index)
403421
404422void Function::addXByName (const string& name)
405423{
424+ if (symbolExists (name))
425+ return ;
406426 xs_.push_back (shared_ptr<Variable>(new Variable (name)));
407427 parser_->DefineVar (name, xs_.back ()->ref ());
408428 varIndex_[name] = xs_.size ()-1 ;
409429 numVar_ = varIndex_.size ();
410430}
411431
412- void Function::addCustomVariable (const string& name)
413- {
414- if (name == " t" )
415- parser_->DefineVar (" t" , &t_);
416- else
417- addXByName (name);
418- }
419-
420432void Function::addY (const unsigned int index)
421433{
422434 string name = ' y' +to_string (index);
@@ -446,20 +458,18 @@ void Function::addVariable(const string& name)
446458
447459 if (XVAR_INDEX == vtype)
448460 {
449- addXByName ( name);
461+ addXByIndex ( stoul ( name. substr ( 1 )) );
450462 return ;
451463 }
452-
453464 if (XVAR_NAMED == vtype)
454465 {
455- addCustomVariable (name);
466+ addXByName (name);
456467 return ;
457468 }
458469
459470 if (YVAR == vtype)
460471 {
461- size_t index = (size_t )stoull (name.substr (1 ).c_str ());
462- addY (index);
472+ addY (stoul (name.substr (1 )));
463473 return ;
464474 }
465475
@@ -471,7 +481,8 @@ void Function::addVariable(const string& name)
471481
472482 if (CONSTVAR == vtype)
473483 {
474- // These are constants. Don't add them.
484+ // These are constants. Don't add them. We don't know there value just
485+ // yet.
475486 return ;
476487 }
477488
@@ -533,7 +544,7 @@ void Function::setExpr(const Eref& eref, const string expression)
533544
534545 try
535546 {
536- valid_ = innerSetExpr (eref, expr, true );
547+ valid_ = innerSetExpr (eref, expr);
537548 }
538549 catch (moose::Parser::ParserException& e)
539550 {
@@ -547,7 +558,7 @@ void Function::setExpr(const Eref& eref, const string expression)
547558/* --------------------------------------------------------------------------*/
548559/* *
549560 * @Synopsis Set expression in the parser. This function support two mode:
550- * with dynamic lookup and without it. When `dynamicLookup ` is set to true,
561+ * with dynamic lookup and without it. When `dynamicLookup_ ` is set to true,
551562 * unknown variables are created at the compile time. Otherwise, an error is
552563 * raised.
553564 *
@@ -559,10 +570,18 @@ void Function::setExpr(const Eref& eref, const string expression)
559570 * @Returns True if compilation was successful.
560571 */
561572/* ----------------------------------------------------------------------------*/
562- bool Function::innerSetExpr (const Eref& eref, const string expr, bool dynamicLookup )
573+ bool Function::innerSetExpr (const Eref& eref, const string expr)
563574{
564575 ASSERT_FALSE (expr.empty (), " Empty expression not allowed here." );
565576
577+ // NOTE: Don't clear the expression here. Sometime the user extend the
578+ // expression by calling this function agian. For example:
579+ //
580+ // >>> f.expr = 'x0+x2'
581+ // >>> # connect x0 and x2
582+ // >>> f.expr += '+ 100+y0'
583+ // >>> # connect more etc.
584+
566585 // First, set the xi, yi and t to the symbol table.
567586 set<string> xs;
568587 set<string> ys;
@@ -571,7 +590,7 @@ bool Function::innerSetExpr(const Eref& eref, const string expr, bool dynamicLoo
571590 for (auto &y : ys) addY (std::stoul (y.substr (1 )));
572591 addVariable (" t" );
573592
574- if (dynamicLookup )
593+ if (allowUnknownVar_ )
575594 return parser_->SetExprWithUnknown (expr, this );
576595
577596 // If we are here that mean we have only xi, yi and t in the expression.
@@ -620,6 +639,17 @@ bool Function::getDoEvalAtReinit() const
620639 return doEvalAtReinit_;
621640}
622641
642+ void Function::setAllowUnknownVariable (bool value )
643+ {
644+ allowUnknownVar_ = value;
645+ }
646+
647+ bool Function::getAllowUnknowVariable () const
648+ {
649+ return allowUnknownVar_;
650+ }
651+
652+
623653double Function::getValue () const
624654{
625655 return parser_->Eval ( );
@@ -728,6 +758,11 @@ unsigned int Function::getVarIndex(string name) const
728758 return varIndex_.at (name);
729759}
730760
761+ bool Function::symbolExists (const string& name) const
762+ {
763+ return varIndex_.find (name) != varIndex_.end ();
764+ }
765+
731766void Function::process (const Eref &e, ProcPtr p)
732767{
733768 if (! valid_)
@@ -822,3 +857,11 @@ void Function::reinit(const Eref &e, ProcPtr p)
822857 return ;
823858 }
824859}
860+
861+
862+ void Function::clearAll ()
863+ {
864+ xs_.clear ();
865+ ys_.clear ();
866+ varIndex_.clear ();
867+ }
0 commit comments