$extrastylesheet
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