Flow123d  release_2.2.0-41-g0958a8d
field_formula.cc
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.cc
15  * @brief
16  */
17 
18 
19 #include "fields/field_formula.hh"
20 #include "fields/field_instances.hh" // for instantiation macros
21 #include "fparser.hh"
22 #include "input/input_type.hh"
23 #include <boost/foreach.hpp>
24 
25 /// Implementation.
26 
27 namespace it = Input::Type;
28 
29 FLOW123D_FORCE_LINK_IN_CHILD(field_formula)
30 
31 
32 template <int spacedim, class Value>
33 const Input::Type::Record & FieldFormula<spacedim, Value>::get_input_type()
34 {
35 
36  return it::Record("FieldFormula", FieldAlgorithmBase<spacedim,Value>::template_name()+" Field given by runtime interpreted formula.")
39  .declare_key("value", STI::get_input_type() , it::Default::obligatory(),
40  "String, array of strings, or matrix of strings with formulas for individual "
41  "entries of scalar, vector, or tensor value respectively.\n"
42  "For vector values, you can use just one string to enter homogeneous vector.\n"
43  "For square (($N\\times N$))-matrix values, you can use:\n\n"
44  " - array of strings of size (($N$)) to enter diagonal matrix\n"
45  " - array of strings of size (($\\frac12N(N+1)$)) to enter symmetric matrix (upper triangle, row by row)\n"
46  " - just one string to enter (spatially variable) multiple of the unit matrix.\n"
47  "Formula can contain variables ```x,y,z,t``` and usual operators and functions." )
48  //.declare_key("unit", FieldAlgorithmBase<spacedim, Value>::get_input_type_unit_si(), it::Default::optional(),
49  // "Definition of unit.")
50  .allow_auto_conversion("value")
51  .close();
52 }
53 
54 
55 
56 template <int spacedim, class Value>
58  Input::register_class< FieldFormula<spacedim, Value>, unsigned int >("FieldFormula") +
60 
61 
62 
63 template <int spacedim, class Value>
65 : FieldAlgorithmBase<spacedim, Value>(n_comp),
66  formula_matrix_(this->value_.n_rows(), this->value_.n_cols())
67 {
68  parser_matrix_.resize(this->value_.n_rows());
69  for(unsigned int row=0; row < this->value_.n_rows(); row++) {
70  parser_matrix_[row].resize(this->value_.n_cols());
71  }
72 }
73 
74 
75 
76 template <int spacedim, class Value>
78  this->init_unit_conversion_coefficient(rec, init_data);
79 
80  // read formulas form input
81  STI::init_from_input( formula_matrix_, rec.val<typename STI::AccessType>("value") );
83 }
84 
85 
86 template <int spacedim, class Value>
88 
89 
90  bool any_parser_changed = false;
91 
92 
93  std::string vars = string("x,y,z").substr(0, 2*spacedim-1);
94  // update parsers
95  for(unsigned int row=0; row < this->value_.n_rows(); row++)
96  for(unsigned int col=0; col < this->value_.n_cols(); col++) {
97  // get all variable names from the formula
98  std::vector<std::string> var_list;
99 
100  FunctionParser tmp_parser;
101  tmp_parser.AddConstant("Pi", 3.14159265358979323846);
102  tmp_parser.AddConstant("E", 2.71828182845904523536);
103 
104 
105 #pragma GCC diagnostic push
106 #pragma GCC diagnostic ignored "-Wunused-variable"
107  {
108  int err=tmp_parser.ParseAndDeduceVariables(formula_matrix_.at(row,col), var_list);
109  OLD_ASSERT( err != FunctionParser::FP_NO_ERROR, "ParseAndDeduceVariables error: %s\n", tmp_parser.ErrorMsg() );
110  }
111 #pragma GCC diagnostic pop
112 
113  bool time_dependent = false;
114  BOOST_FOREACH(std::string &var_name, var_list ) {
115  if (var_name == std::string("t") ) time_dependent=true;
116  else if (var_name == "x" || var_name == "y" || var_name == "z") continue;
117  else
118  WarningOut().fmt("Unknown variable '{}' in the FieldFormula[{}][{}] == '{}'\n at the input address:\n {} \n",
119  var_name, row, col, formula_matrix_.at(row,col), value_input_address_ );
120  }
121 
122  // Seems that we can not just add 't' constant to tmp_parser, since it was already Parsed.
123  parser_matrix_[row][col].AddConstant("Pi", 3.14159265358979323846);
124  parser_matrix_[row][col].AddConstant("E", 2.71828182845904523536);
125  if (time_dependent) {
126  parser_matrix_[row][col].AddConstant("t", time.end());
127  }
128 
129  // TODO:
130  // - possibly add user defined constants and units here ...
131  // - optimization; possibly parse only if time_dependent || formula_matrix[][] has changed ...
132  //parser_matrix_[row][col] = tmp_parser;
133  if (time_dependent || this->time_ == TimeStep() ) {
134  parser_matrix_[row][col].Parse(formula_matrix_.at(row,col), vars);
135 
136  if ( parser_matrix_[row][col].GetParseErrorType() != FunctionParser::FP_NO_ERROR ) {
137  xprintf(UsrErr, "ParserError: %s\n in the FieldFormula[%d][%d] == '%s'\n at the input address:\n %s \n",
138  parser_matrix_[row][col].ErrorMsg(),
139  row,col,formula_matrix_.at(row,col).c_str(),
140  value_input_address_.c_str());
141  }
142 
143  parser_matrix_[row][col].Optimize();
144  any_parser_changed = true;
145  }
146 
147 
148  }
149 
150  this->time_=time;
151  return any_parser_changed;
152 }
153 
154 
155 /**
156  * Returns one value in one given point. ResultType can be used to avoid some costly calculation if the result is trivial.
157  */
158 template <int spacedim, class Value>
159 typename Value::return_type const & FieldFormula<spacedim, Value>::value(const Point &p, const ElementAccessor<spacedim> &elm)
160 {
161  for(unsigned int row=0; row < this->value_.n_rows(); row++)
162  for(unsigned int col=0; col < this->value_.n_cols(); col++) {
163  this->value_(row,col) = this->unit_conversion_coefficient_ * parser_matrix_[row][col].Eval(p.memptr());
164  }
165  return this->r_value_;
166 }
167 
168 
169 /**
170  * Returns std::vector of scalar values in several points at once.
171  */
172 template <int spacedim, class Value>
175 {
176  OLD_ASSERT_EQUAL( point_list.size(), value_list.size() );
177  for(unsigned int i=0; i< point_list.size(); i++) {
178  Value envelope(value_list[i]);
179  OLD_ASSERT( envelope.n_rows()==this->value_.n_rows(),
180  "value_list[%d] has wrong number of rows: %d; should match number of components: %d\n",
181  i, envelope.n_rows(),this->value_.n_rows());
182 
183  for(unsigned int row=0; row < this->value_.n_rows(); row++)
184  for(unsigned int col=0; col < this->value_.n_cols(); col++) {
185  envelope(row,col) = this->unit_conversion_coefficient_ * parser_matrix_[row][col].Eval(point_list[i].memptr());
186  }
187  }
188 }
189 
190 
191 template <int spacedim, class Value>
193 }
194 
195 
196 // Instantiations of FieldFormula
TimeStep time_
Actual time level; initial value is -infinity.
void init_unit_conversion_coefficient(const Input::Record &rec, const struct FieldAlgoBaseInitData &init_data)
Init value of unit_conversion_coefficient_ from input.
std::string value_input_address_
Accessor to input data conforming to declared Array.
Definition: accessors.hh:567
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:110
#define INSTANCE_ALL(field)
Helper struct stores data for initizalize descentants of FieldAlgorithmBase.
StringTensor formula_matrix_
Value::return_type r_value_
Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:303
bool set_time(const TimeStep &time) override
virtual void init_from_input(const Input::Record &rec, const struct FieldAlgoBaseInitData &init_data)
double unit_conversion_coefficient_
Coeficient of conversion of user-defined unit.
virtual Record & derive_from(Abstract &parent)
Method to derive new Record from an AbstractRecord parent.
Definition: type_record.cc:195
#define OLD_ASSERT(...)
Definition: global_defs.h:131
virtual Record & allow_auto_conversion(const string &from_key)
Allows shorter input of the Record providing only value of the from_key given as the parameter...
Definition: type_record.cc:132
Accessor to the data with type Type::Record.
Definition: accessors.hh:292
const Ret val(const string &key) const
#define xprintf(...)
Definition: system.hh:92
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:490
double end() const
Space< spacedim >::Point Point
Record & copy_keys(const Record &other)
Copy keys from other record.
Definition: type_record.cc:215
Definition: system.hh:64
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 WarningOut()
Macro defining &#39;warning&#39; record of log.
Definition: logger.hh:236
#define OLD_ASSERT_EQUAL(a, b)
Definition: global_defs.h:133
std::vector< std::vector< FunctionParser > > parser_matrix_
Record type proxy class.
Definition: type_record.hh:182
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:180
string address_string() const
Definition: accessors.cc:184