Flow123d
field_formula_impl.hh
Go to the documentation of this file.
1  /*
2  * field_formula_impl.hh
3  *
4  * Created on: Jan 2, 2013
5  * Author: jb
6  */
7 
8 #ifndef FIELD_FORMULA_IMPL_HH_
9 #define FIELD_FORMULA_IMPL_HH_
10 
11 
12 #include "fields/field_formula.hh"
13 #include "fparser.hh"
14 #include "input/input_type.hh"
15 #include <boost/foreach.hpp>
16 
17 /// Implementation.
18 
19 namespace it = Input::Type;
20 
21 template <int spacedim, class Value>
23 
24 template <int spacedim, class Value>
26  Input::Type::AbstractRecord &a_type, const typename Value::ElementInputType *eit
27  )
28 {
29  it::Record type
30  = it::Record("FieldFormula", FieldBase<spacedim,Value>::template_name()+" Field given by runtime interpreted formula.")
31  .derive_from(a_type)
32  .declare_key("value", StringValue::get_input_type(NULL), it::Default::obligatory(),
33  "String, array of strings, or matrix of strings with formulas for individual "
34  "entries of scalar, vector, or tensor value respectively.\n"
35  "For vector values, you can use just one string to enter homogeneous vector.\n"
36  "For square NxN-matrix values, you can use:\n"
37  "* array of strings of size N to enter diagonal matrix\n"
38  "* array of strings of size (N+1)*N/2 to enter symmetric matrix (upper triangle, row by row)\n"
39  "* just one string to enter (spatially variable) multiple of the unit matrix.\n"
40  "Formula can contain variables x,y,z,t and usual operators and functions." );
41 
42  return type;
43 }
44 
45 
46 
47 
48 template <int spacedim, class Value>
50 : FieldBase<spacedim, Value>(n_comp),
51  formula_matrix_(this->value_.n_rows(), this->value_.n_cols()),
52  formula_matrix_helper_(formula_matrix_), parser_matrix_(this->value_.n_rows())
53 {
54  for(unsigned int row=0; row < this->value_.n_rows(); row++) {
55  parser_matrix_[row].resize(this->value_.n_cols());
56  }
57 }
58 
59 
60 
61 template <int spacedim, class Value>
63  // read formulas form input
64  formula_matrix_helper_.init_from_input( rec.val<typename StringValue::AccessType>("value") );
65  value_input_address_ = rec.address_string();
66 }
67 
68 
69 template <int spacedim, class Value>
71 
72 
73  bool any_parser_changed = false;
74 
75 
76  std::string vars = string("x,y,z").substr(0, 2*spacedim-1);
77  // update parsers
78  for(unsigned int row=0; row < this->value_.n_rows(); row++)
79  for(unsigned int col=0; col < this->value_.n_cols(); col++) {
80  // get all variable names from the formula
81  std::vector<std::string> var_list;
82 
83  FunctionParser tmp_parser;
84  int err=tmp_parser.ParseAndDeduceVariables(formula_matrix_.at(row,col), var_list);
85  ASSERT( err != FunctionParser::FP_NO_ERROR, "ParseAndDeduceVariables error: %s\n", tmp_parser.ErrorMsg() );
86 
87  bool time_dependent = false;
88  BOOST_FOREACH(std::string &var_name, var_list ) {
89  if (var_name == std::string("t") ) time_dependent=true;
90  else if (var_name == "x" || var_name == "y" || var_name == "z") continue;
91  else
92  xprintf(Warn, "Unknown variable '%s' in the FieldFormula[%d][%d] == '%s'\n at the input address:\n %s \n",
93  var_name.c_str(), row, col, formula_matrix_.at(row,col).c_str(),
94  value_input_address_.c_str() );
95  }
96  if (time_dependent) {
97  parser_matrix_[row][col].AddConstant("t", time);
98  }
99 
100  // TODO:
101  // - possibly add user defined constants and units here ...
102  // - optimization; possibly parse only if time_dependent || formula_matrix[][] has changed ...
103 
104  if (time_dependent || this->time_ == -numeric_limits<double>::infinity() ) {
105  parser_matrix_[row][col].Parse(formula_matrix_.at(row,col), vars);
106 
107  if ( parser_matrix_[row][col].GetParseErrorType() != FunctionParser::FP_NO_ERROR ) {
108  xprintf(UsrErr, "ParserError: %s\n in the FieldFormula[%d][%d] == '%s'\n at the input address:\n %s \n",
109  parser_matrix_[row][col].ErrorMsg(),
110  row,col,formula_matrix_.at(row,col).c_str(),
111  value_input_address_.c_str());
112  }
113 
114  parser_matrix_[row][col].Optimize();
115  any_parser_changed = true;
116  }
117 
118 
119  }
120 
121  this->time_=time;
122  return any_parser_changed;
123 }
124 
125 
126 /**
127  * Returns one value in one given point. ResultType can be used to avoid some costly calculation if the result is trivial.
128  */
129 template <int spacedim, class Value>
130 typename Value::return_type const & FieldFormula<spacedim, Value>::value(const Point &p, const ElementAccessor<spacedim> &elm)
131 {
132  for(unsigned int row=0; row < this->value_.n_rows(); row++)
133  for(unsigned int col=0; col < this->value_.n_cols(); col++) {
134  this->value_(row,col) = parser_matrix_[row][col].Eval(p.memptr());
135  }
136  return this->r_value_;
137 }
138 
139 
140 /**
141  * Returns std::vector of scalar values in several points at once.
142  */
143 template <int spacedim, class Value>
146 {
147  ASSERT_EQUAL( point_list.size(), value_list.size() );
148  for(unsigned int i=0; i< point_list.size(); i++) {
149  Value envelope(value_list[i]);
150 
151  for(unsigned int row=0; row < this->value_.n_rows(); row++)
152  for(unsigned int col=0; col < this->value_.n_cols(); col++) {
153  envelope(row,col) = parser_matrix_[row][col].Eval(point_list[i].memptr());
154  }
155  }
156 }
157 
158 
159 template <int spacedim, class Value>
161 }
162 
163 
164 #endif /* FIELD_FORMULA_IMPL_HH_ */