$extrastylesheet
parsed_fem_function.h
Go to the documentation of this file.
00001 // The libMesh Finite Element Library.
00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
00003 
00004 // This library is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU Lesser General Public
00006 // License as published by the Free Software Foundation; either
00007 // version 2.1 of the License, or (at your option) any later version.
00008 
00009 // This library is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 // Lesser General Public License for more details.
00013 
00014 // You should have received a copy of the GNU Lesser General Public
00015 // License along with this library; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018 
00019 
00020 #ifndef LIBMESH_PARSED_FEM_FUNCTION_H
00021 #define LIBMESH_PARSED_FEM_FUNCTION_H
00022 
00023 #include "libmesh/libmesh_config.h"
00024 
00025 // Local Includes
00026 #include "libmesh/fem_function_base.h"
00027 #include "libmesh/point.h"
00028 #include "libmesh/system.h"
00029 
00030 #ifdef LIBMESH_HAVE_FPARSER
00031 // FParser includes
00032 #include "libmesh/fparser.hh"
00033 #endif
00034 
00035 // C++ includes
00036 
00037 namespace libMesh
00038 {
00039 
00040 // ------------------------------------------------------------
00041 // ParsedFEMFunction class definition
00042 template <typename Output=Number>
00043 class ParsedFEMFunction : public FEMFunctionBase<Output>
00044 {
00045 public:
00046 
00050   explicit
00051   ParsedFEMFunction (const System& sys,
00052                      const std::string& expression,
00053                      const std::vector<std::string>* additional_vars=NULL,
00054                      const std::vector<Output>* initial_vals=NULL)
00055     : _sys(sys),
00056       _expression(expression),
00057       _n_vars(sys.n_vars())
00058   {
00059     std::string variables = "x";
00060 #if LIBMESH_DIM > 1
00061     variables += ",y";
00062 #endif
00063 #if LIBMESH_DIM > 2
00064     variables += ",z";
00065 #endif
00066     variables += ",t";
00067 
00068     _spacetime.resize(LIBMESH_DIM+1 + _n_vars + (additional_vars ? additional_vars->size() : 0));
00069 
00070     for (unsigned int v=0; v != _n_vars; ++v)
00071       {
00072         variables += ',';
00073         variables += sys.variable_name(v);
00074       }
00075 
00076     // If additional vars were passed, append them to the string
00077     // that we send to the function parser. Also add them to the
00078     // end of our spacetime vector
00079     if (additional_vars)
00080       {
00081         if (initial_vals)
00082           std::copy(initial_vals->begin(), initial_vals->end(), std::back_inserter(_initial_vals));
00083 
00084         std::copy(additional_vars->begin(), additional_vars->end(), std::back_inserter(_additional_vars));
00085 
00086         for (unsigned int i=0; i < additional_vars->size(); ++i)
00087           {
00088             variables += "," + (*additional_vars)[i];
00089             // Initialize extra variables to the vector passed in or zero
00090             // Note: The initial_vals vector can be shorter than the additional_vars vector
00091             _spacetime[LIBMESH_DIM+1+_n_vars + i] = (initial_vals && i < initial_vals->size()) ? (*initial_vals)[i] : 0;
00092           }
00093       }
00094 
00095     size_t nextstart = 0, end = 0;
00096 
00097     while (end != std::string::npos)
00098       {
00099         // If we're past the end of the string, we can't make any more
00100         // subparsers
00101         if (nextstart >= expression.size())
00102           break;
00103 
00104         // If we're at the start of a brace delimited section, then we
00105         // parse just that section:
00106         if (expression[nextstart] == '{')
00107           {
00108             nextstart++;
00109             end = expression.find('}', nextstart);
00110           }
00111         // otherwise we parse the whole thing
00112         else
00113           end = std::string::npos;
00114 
00115         // We either want the whole end of the string (end == npos) or
00116         // a substring in the middle.
00117         std::string subexpression =
00118           expression.substr(nextstart, (end == std::string::npos) ?
00119                             std::string::npos : end - nextstart);
00120 
00121         // fparser can crash on empty expressions
00122         if (subexpression.empty())
00123           libmesh_error_msg("ERROR: FunctionParser is unable to parse empty expression.\n");
00124 
00125 
00126 #ifdef LIBMESH_HAVE_FPARSER
00127         // Parse (and optimize if possible) the subexpression.
00128         // Add some basic constants, to Real precision.
00129         FunctionParserBase<Output> fp;
00130         fp.AddConstant("NaN", std::numeric_limits<Real>::quiet_NaN());
00131         fp.AddConstant("pi", std::acos(Real(-1)));
00132         fp.AddConstant("e", std::exp(Real(1)));
00133         if (fp.Parse(subexpression, variables) != -1) // -1 for success
00134           libmesh_error_msg("ERROR: FunctionParser is unable to parse expression: " << subexpression << '\n' << fp.ErrorMsg());
00135         fp.Optimize();
00136         parsers.push_back(fp);
00137 #else
00138         libmesh_error_msg("ERROR: This functionality requires fparser!");
00139 #endif
00140 
00141         // If at end, use nextstart=maxSize.  Else start at next
00142         // character.
00143         nextstart = (end == std::string::npos) ?
00144           std::string::npos : end + 1;
00145       }
00146   }
00147 
00151   virtual ~ParsedFEMFunction () {}
00152 
00156   virtual void init_context (const FEMContext &c) {
00157     for (unsigned int v=0; v != _n_vars; ++v)
00158       {
00159         FEBase* elem_fe;
00160         c.get_element_fe(v, elem_fe);
00161         elem_fe->get_phi();
00162       }
00163   }
00164 
00170   virtual UniquePtr<FEMFunctionBase<Output> > clone () const {
00171     return UniquePtr<FEMFunctionBase<Output> >
00172       (new ParsedFEMFunction
00173        (_sys, _expression, &_additional_vars, &_initial_vals));
00174   }
00175 
00176   // ------------------------------------------------------
00177   // misc
00184   virtual Output operator() (const FEMContext& c, const Point& p,
00185                              const Real time = 0.)
00186   {
00187     _spacetime[0] = p(0);
00188 #if LIBMESH_DIM > 1
00189     _spacetime[1] = p(1);
00190 #endif
00191 #if LIBMESH_DIM > 2
00192     _spacetime[2] = p(2);
00193 #endif
00194     _spacetime[LIBMESH_DIM] = time;
00195 
00196     for (unsigned int v=0; v != _n_vars; ++v)
00197       {
00198         c.point_value(v, p, _spacetime[LIBMESH_DIM+1+v]);
00199       }
00200 
00201     // The remaining locations in _spacetime are currently fixed at construction
00202     // but could potentially be made dynamic
00203 #if LIBMESH_HAVE_FPARSER
00204     return parsers[0].Eval(&_spacetime[0]);
00205 #else
00206     libmesh_error_msg("ERROR: This functionality requires fparser!");
00207     return Output(0);
00208 #endif
00209   }
00210 
00211 
00212 
00218   void operator() (const FEMContext& c, const Point& p,
00219                    const Real time,
00220                    DenseVector<Output>& output)
00221   {
00222     _spacetime[0] = p(0);
00223 #if LIBMESH_DIM > 1
00224     _spacetime[1] = p(1);
00225 #endif
00226 #if LIBMESH_DIM > 2
00227     _spacetime[2] = p(2);
00228 #endif
00229     _spacetime[LIBMESH_DIM] = time;
00230 
00231     for (unsigned int v=0; v != _n_vars; ++v)
00232       {
00233         c.point_value(v, p, _spacetime[LIBMESH_DIM+1+v]);
00234       }
00235 
00236     unsigned int size = output.size();
00237 
00238 #ifdef LIBMESH_HAVE_FPARSER
00239     libmesh_assert_equal_to (size, parsers.size());
00240 
00241     // The remaining locations in _spacetime are currently fixed at construction
00242     // but could potentially be made dynamic
00243     for (unsigned int i=0; i != size; ++i)
00244       output(i) = parsers[i].Eval(&_spacetime[0]);
00245 #else
00246     libmesh_error_msg("ERROR: This functionality requires fparser!");
00247 #endif
00248   }
00249 
00250 
00255   virtual Output component(const FEMContext& c, unsigned int i,
00256                            const Point& p,
00257                            Real time=0.)
00258   {
00259     _spacetime[0] = p(0);
00260 #if LIBMESH_DIM > 1
00261     _spacetime[1] = p(1);
00262 #endif
00263 #if LIBMESH_DIM > 2
00264     _spacetime[2] = p(2);
00265 #endif
00266     _spacetime[LIBMESH_DIM] = time;
00267 
00268     for (unsigned int v=0; v != _n_vars; ++v)
00269       {
00270         c.point_value(v, p, _spacetime[LIBMESH_DIM+1+v]);
00271       }
00272 #ifdef LIBMESH_HAVE_FPARSER
00273     libmesh_assert_less (i, parsers.size());
00274 
00275     // The remaining locations in _spacetime are currently fixed at construction
00276     // but could potentially be made dynamic
00277     return parsers[i].Eval(&_spacetime[0]);
00278 #else
00279     libmesh_error_msg("ERROR: This functionality requires fparser!");
00280     return Output(0);
00281 #endif
00282   }
00283 
00284 private:
00285   const System& _sys;
00286   std::string _expression;
00287   unsigned int _n_vars;
00288 #ifdef LIBMESH_HAVE_FPARSER
00289   std::vector<FunctionParserBase<Output> > parsers;
00290 #endif
00291   std::vector<Output> _spacetime;
00292 
00293   // Additional variables/values that can be parsed and handled by the function parser
00294   std::vector<std::string> _additional_vars;
00295   std::vector<Output> _initial_vals;
00296 };
00297 
00298 } // namespace libMesh
00299 
00300 #endif // LIBMESH_PARSED_FEM_FUNCTION_H