Flow123d  release_1.8.2-1603-g0109a2b
field_formula.impl.hh
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file field_formula.impl.hh
15  * @brief
16  */
17 
18 #ifndef FIELD_FORMULA_IMPL_HH_
19 #define FIELD_FORMULA_IMPL_HH_
20 
21 
22 #include "fields/field_formula.hh"
23 #include "fparser.hh"
24 #include "input/input_type.hh"
25 #include <boost/foreach.hpp>
26 
27 /// Implementation.
28 
29 namespace it = Input::Type;
30 
31 FLOW123D_FORCE_LINK_IN_CHILD(field_formula)
32 
33 
34 template <int spacedim, class Value>
35 const Input::Type::Record & FieldFormula<spacedim, Value>::get_input_type()
36 {
37 
38  return it::Record("FieldFormula", FieldAlgorithmBase<spacedim,Value>::template_name()+" Field given by runtime interpreted formula.")
40  .declare_key("value", STI::get_input_type() , it::Default::obligatory(),
41  "String, array of strings, or matrix of strings with formulas for individual "
42  "entries of scalar, vector, or tensor value respectively.\n"
43  "For vector values, you can use just one string to enter homogeneous vector.\n"
44  "For square (($N\\times N$))-matrix values, you can use:\n\n"
45  " - array of strings of size (($N$)) to enter diagonal matrix\n"
46  " - array of strings of size (($\\frac12N(N+1)$)) to enter symmetric matrix (upper triangle, row by row)\n"
47  " - just one string to enter (spatially variable) multiple of the unit matrix.\n"
48  "Formula can contain variables ```x,y,z,t``` and usual operators and functions." )
49  .close();
50 }
51 
52 
53 
54 template <int spacedim, class Value>
56  Input::register_class< FieldFormula<spacedim, Value>, unsigned int >("FieldFormula") +
58 
59 
60 
61 template <int spacedim, class Value>
63 : FieldAlgorithmBase<spacedim, Value>(n_comp),
64  formula_matrix_(this->value_.n_rows(), this->value_.n_cols())
65 {
66  parser_matrix_.resize(this->value_.n_rows());
67  for(unsigned int row=0; row < this->value_.n_rows(); row++) {
68  parser_matrix_[row].resize(this->value_.n_cols());
69  }
70 }
71 
72 
73 
74 template <int spacedim, class Value>
76  // read formulas form input
77  STI::init_from_input( formula_matrix_, rec.val<typename STI::AccessType>("value") );
79 }
80 
81 
82 template <int spacedim, class Value>
84 
85 
86  bool any_parser_changed = false;
87 
88 
89  std::string vars = string("x,y,z").substr(0, 2*spacedim-1);
90  // update parsers
91  for(unsigned int row=0; row < this->value_.n_rows(); row++)
92  for(unsigned int col=0; col < this->value_.n_cols(); col++) {
93  // get all variable names from the formula
94  std::vector<std::string> var_list;
95 
96  FunctionParser tmp_parser;
97 #pragma GCC diagnostic push
98 #pragma GCC diagnostic ignored "-Wunused-variable"
99  {
100  int err=tmp_parser.ParseAndDeduceVariables(formula_matrix_.at(row,col), var_list);
101  OLD_ASSERT( err != FunctionParser::FP_NO_ERROR, "ParseAndDeduceVariables error: %s\n", tmp_parser.ErrorMsg() );
102  }
103 #pragma GCC diagnostic pop
104 
105  bool time_dependent = false;
106  BOOST_FOREACH(std::string &var_name, var_list ) {
107  if (var_name == std::string("t") ) time_dependent=true;
108  else if (var_name == "x" || var_name == "y" || var_name == "z") continue;
109  else
110  xprintf(Warn, "Unknown variable '%s' in the FieldFormula[%d][%d] == '%s'\n at the input address:\n %s \n",
111  var_name.c_str(), row, col, formula_matrix_.at(row,col).c_str(),
112  value_input_address_.c_str() );
113  }
114  if (time_dependent) {
115  parser_matrix_[row][col].AddConstant("t", time.end());
116  }
117 
118  // TODO:
119  // - possibly add user defined constants and units here ...
120  // - optimization; possibly parse only if time_dependent || formula_matrix[][] has changed ...
121 
122  if (time_dependent || this->time_ == TimeStep() ) {
123  parser_matrix_[row][col].Parse(formula_matrix_.at(row,col), vars);
124 
125  if ( parser_matrix_[row][col].GetParseErrorType() != FunctionParser::FP_NO_ERROR ) {
126  xprintf(UsrErr, "ParserError: %s\n in the FieldFormula[%d][%d] == '%s'\n at the input address:\n %s \n",
127  parser_matrix_[row][col].ErrorMsg(),
128  row,col,formula_matrix_.at(row,col).c_str(),
129  value_input_address_.c_str());
130  }
131 
132  parser_matrix_[row][col].Optimize();
133  any_parser_changed = true;
134  }
135 
136 
137  }
138 
139  this->time_=time;
140  return any_parser_changed;
141 }
142 
143 
144 /**
145  * Returns one value in one given point. ResultType can be used to avoid some costly calculation if the result is trivial.
146  */
147 template <int spacedim, class Value>
148 typename Value::return_type const & FieldFormula<spacedim, Value>::value(const Point &p, const ElementAccessor<spacedim> &elm)
149 {
150  for(unsigned int row=0; row < this->value_.n_rows(); row++)
151  for(unsigned int col=0; col < this->value_.n_cols(); col++) {
152  this->value_(row,col) = parser_matrix_[row][col].Eval(p.memptr());
153  }
154  return this->r_value_;
155 }
156 
157 
158 /**
159  * Returns std::vector of scalar values in several points at once.
160  */
161 template <int spacedim, class Value>
164 {
165  OLD_ASSERT_EQUAL( point_list.size(), value_list.size() );
166  for(unsigned int i=0; i< point_list.size(); i++) {
167  Value envelope(value_list[i]);
168  OLD_ASSERT( envelope.n_rows()==this->value_.n_rows(),
169  "value_list[%d] has wrong number of rows: %d; should match number of components: %d\n",
170  i, envelope.n_rows(),this->value_.n_rows());
171 
172  for(unsigned int row=0; row < this->value_.n_rows(); row++)
173  for(unsigned int col=0; col < this->value_.n_cols(); col++) {
174  envelope(row,col) = parser_matrix_[row][col].Eval(point_list[i].memptr());
175  }
176  }
177 }
178 
179 
180 template <int spacedim, class Value>
182 }
183 
184 
185 #endif /* FIELD_FORMULA_IMPL_HH_ */
TimeStep time_
Actual time level; initial value is -infinity.
std::string value_input_address_
Accessor to input data conforming to declared Array.
Definition: accessors.hh:552
static void init_from_input(StringTensor &tensor, AccessType input)
virtual ~FieldFormula()
FieldFormula(unsigned int n_comp=0)
static Default obligatory()
The factory function to make an empty default value which is obligatory.
Definition: type_record.hh:99
StringTensor formula_matrix_
Value::return_type r_value_
bool set_time(const TimeStep &time) override
virtual Record & derive_from(Abstract &parent)
Method to derive new Record from an AbstractRecord parent.
Definition: type_record.cc:193
#define OLD_ASSERT(...)
Definition: global_defs.h:128
Definition: system.hh:59
virtual void init_from_input(const Input::Record &rec)
Accessor to the data with type Type::Record.
Definition: accessors.hh:277
const Ret val(const string &key) const
#define xprintf(...)
Definition: system.hh:87
Record & declare_key(const string &key, std::shared_ptr< TypeBase > type, const Default &default_value, const string &description, TypeBase::attribute_map key_attributes=TypeBase::attribute_map())
Declares a new key of the Record.
Definition: type_record.cc:459
const Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:271
double end() const
Space< spacedim >::Point Point
Definition: system.hh:59
std::string & at(unsigned int row)
Value value_
Last value, prevents passing large values (vectors) by value.
virtual Value::return_type const & value(const Point &p, const ElementAccessor< spacedim > &elm)
#define OLD_ASSERT_EQUAL(a, b)
Definition: global_defs.h:130
std::vector< std::vector< FunctionParser > > parser_matrix_
Record type proxy class.
Definition: type_record.hh:171
Representation of one time step..
virtual void value_list(const std::vector< Point > &point_list, const ElementAccessor< spacedim > &elm, std::vector< typename Value::return_type > &value_list)
#define FLOW123D_FORCE_LINK_IN_CHILD(x)
Definition: global_defs.h:246
string address_string() const
Definition: accessors.cc:199