parsed_function.h
Go to the documentation of this file.00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2012 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 #ifndef LIBMESH_PARSED_FUNCTION_H 00019 #define LIBMESH_PARSED_FUNCTION_H 00020 00021 #include "libmesh/libmesh_config.h" 00022 #include "libmesh/function_base.h" 00023 00024 #ifdef LIBMESH_HAVE_FPARSER 00025 00026 // Local includes 00027 #include "libmesh/dense_vector.h" 00028 #include "libmesh/point.h" 00029 00030 // FParser includes 00031 #include "fparser.hh" 00032 00033 // C++ includes 00034 #include <algorithm> // std::find 00035 #include <cmath> 00036 #include <cmath> 00037 #include <cstddef> 00038 #include <string> 00039 00040 namespace libMesh { 00041 00042 template <typename Output=Number> 00043 class ParsedFunction : public FunctionBase<Output> 00044 { 00045 public: 00046 explicit 00047 ParsedFunction (const std::string& expression, const std::vector<std::string>* additional_vars=NULL, 00048 const std::vector<Output>* initial_vals=NULL) 00049 : _expression(expression) 00050 // Size the spacetime vector to account for space, time, and any additional 00051 // variables passed 00052 //_spacetime(LIBMESH_DIM+1 + (additional_vars ? additional_vars->size() : 0)), 00053 { 00054 std::string variables = "x"; 00055 #if LIBMESH_DIM > 1 00056 variables += ",y"; 00057 #endif 00058 #if LIBMESH_DIM > 2 00059 variables += ",z"; 00060 #endif 00061 variables += ",t"; 00062 00063 _spacetime.resize(LIBMESH_DIM+1 + (additional_vars ? additional_vars->size() : 0)); 00064 00065 // If additional vars were passed, append them to the string 00066 // that we send to the function parser. Also add them to the 00067 // end of our spacetime vector 00068 if (additional_vars) 00069 { 00070 if (initial_vals) 00071 std::copy(initial_vals->begin(), initial_vals->end(), std::back_inserter(_initial_vals)); 00072 00073 std::copy(additional_vars->begin(), additional_vars->end(), std::back_inserter(_additional_vars)); 00074 00075 for (unsigned int i=0; i < additional_vars->size(); ++i) 00076 { 00077 variables += "," + (*additional_vars)[i]; 00078 // Initialize extra variables to the vector passed in or zero 00079 // Note: The initial_vals vector can be shorter than the additional_vars vector 00080 _spacetime[LIBMESH_DIM+1 + i] = (initial_vals && i < initial_vals->size()) ? (*initial_vals)[i] : 0; 00081 } 00082 } 00083 00084 size_t nextstart = 0, end = 0; 00085 00086 while (end != std::string::npos) 00087 { 00088 // If we're past the end of the string, we can't make any more 00089 // subparsers 00090 if (nextstart >= expression.size()) 00091 break; 00092 00093 // If we're at the start of a brace delimited section, then we 00094 // parse just that section: 00095 if (expression[nextstart] == '{') 00096 { 00097 nextstart++; 00098 end = expression.find('}', nextstart); 00099 } 00100 // otherwise we parse the whole thing 00101 else 00102 end = std::string::npos; 00103 00104 // We either want the whole end of the string (end == npos) or 00105 // a substring in the middle. 00106 std::string subexpression = 00107 expression.substr(nextstart, (end == std::string::npos) ? 00108 std::string::npos : end - nextstart); 00109 00110 // fparser can crash on empty expressions 00111 libmesh_assert(!subexpression.empty()); 00112 00113 // Parse (and optimize if possible) the subexpression. 00114 // Add some basic constants, to Real precision. 00115 FunctionParserBase<Output> fp; 00116 fp.AddConstant("pi", std::acos(Real(-1))); 00117 fp.AddConstant("e", std::exp(Real(1))); 00118 fp.Parse(subexpression, variables); 00119 fp.Optimize(); 00120 parsers.push_back(fp); 00121 00122 // If at end, use nextstart=maxSize. Else start at next 00123 // character. 00124 nextstart = (end == std::string::npos) ? 00125 std::string::npos : end + 1; 00126 } 00127 00128 this->_initialized = true; 00129 } 00130 00131 virtual Output operator() (const Point& p, 00132 const Real time = 0) 00133 { 00134 _spacetime[0] = p(0); 00135 #if LIBMESH_DIM > 1 00136 _spacetime[1] = p(1); 00137 #endif 00138 #if LIBMESH_DIM > 2 00139 _spacetime[2] = p(2); 00140 #endif 00141 _spacetime[LIBMESH_DIM] = time; 00142 00143 // The remaining locations in _spacetime are currently fixed at construction 00144 // but could potentially be made dynamic 00145 return parsers[0].Eval(&_spacetime[0]); 00146 } 00147 00148 virtual void operator() (const Point& p, 00149 const Real time, 00150 DenseVector<Output>& output) 00151 { 00152 _spacetime[0] = p(0); 00153 #if LIBMESH_DIM > 1 00154 _spacetime[1] = p(1); 00155 #endif 00156 #if LIBMESH_DIM > 2 00157 _spacetime[2] = p(2); 00158 #endif 00159 _spacetime[LIBMESH_DIM] = time; 00160 00161 unsigned int size = output.size(); 00162 00163 libmesh_assert_equal_to (size, parsers.size()); 00164 00165 // The remaining locations in _spacetime are currently fixed at construction 00166 // but could potentially be made dynamic 00167 for (unsigned int i=0; i != size; ++i) 00168 output(i) = parsers[i].Eval(&_spacetime[0]); 00169 } 00170 00175 virtual Output component (unsigned int i, 00176 const Point& p, 00177 Real time) 00178 { 00179 _spacetime[0] = p(0); 00180 #if LIBMESH_DIM > 1 00181 _spacetime[1] = p(1); 00182 #endif 00183 #if LIBMESH_DIM > 2 00184 _spacetime[2] = p(2); 00185 #endif 00186 _spacetime[LIBMESH_DIM] = time; 00187 00188 libmesh_assert_less (i, parsers.size()); 00189 00190 // The remaining locations in _spacetime are currently fixed at construction 00191 // but could potentially be made dynamic 00192 return parsers[i].Eval(&_spacetime[0]); 00193 } 00194 00198 virtual Output & getVarAddress(const std::string & variable_name) 00199 { 00200 const std::vector<std::string>::iterator it = 00201 std::find(_additional_vars.begin(), _additional_vars.end(), variable_name); 00202 00203 if (it == _additional_vars.end()) 00204 { 00205 std::cerr << "ERROR: Requested variable not found in parsed function\n" << std::endl; 00206 libmesh_error(); 00207 } 00208 00209 // Iterator Arithmetic (How far from the end of the array is our target address?) 00210 return _spacetime[_spacetime.size() - (_additional_vars.end() - it)]; 00211 } 00212 00213 00214 virtual AutoPtr<FunctionBase<Output> > clone() const { 00215 return AutoPtr<FunctionBase<Output> > 00216 (new ParsedFunction(_expression, &_additional_vars, &_initial_vals)); 00217 } 00218 00219 private: 00220 std::string _expression; 00221 std::vector<FunctionParserBase<Output> > parsers; 00222 std::vector<Output> _spacetime; 00223 00224 // Additional variables/values that can be parsed and handled by the function parser 00225 std::vector<std::string> _additional_vars; 00226 std::vector<Output> _initial_vals; 00227 }; 00228 00229 00230 } // namespace libMesh 00231 00232 00233 #else // LIBMESH_HAVE_FPARSER 00234 00235 00236 namespace libMesh { 00237 00238 00239 template <typename Output> 00240 class ParsedFunction : public FunctionBase<Output> 00241 { 00242 public: 00243 ParsedFunction (std::string /* expression */) : _dummy(0) 00244 { 00245 libmesh_not_implemented(); 00246 } 00247 00248 virtual Output operator() (const Point&, 00249 const Real /* time */ = 0) 00250 { return 0.; } 00251 00252 virtual void operator() (const Point&, 00253 const Real /* time */, 00254 DenseVector<Output>& /* output */) {} 00255 00256 virtual void init() {} 00257 virtual void clear() {} 00258 virtual Output & getVarAddress(const std::string & /*variable_name*/) { return _dummy; } 00259 virtual AutoPtr<FunctionBase<Output> > clone() const { 00260 return AutoPtr<FunctionBase<Output> > 00261 (new ParsedFunction<Output>("")); 00262 } 00263 private: 00264 Output _dummy; 00265 }; 00266 00267 00268 } // namespace libMesh 00269 00270 00271 #endif // LIBMESH_HAVE_FPARSER 00272 00273 #endif // LIBMESH_PARSED_FUNCTION_H
Site Created By: libMesh Developers
Last modified: February 05 2013 19:54:48 UTC
Hosted By: