25 #include "include/arena_alloc.hh"
26 #include <boost/algorithm/string/replace.hpp>
27 #include <boost/regex.hpp>
38 template <
int spacedim,
class Value>
46 "String, array of strings, or matrix of strings with formulas for individual "
47 "entries of scalar, vector, or tensor value respectively.\n"
48 "For vector values, you can use just one string to enter homogeneous vector.\n"
49 "For square (($N\\times N$))-matrix values, you can use:\n\n"
50 " - array of strings of size (($N$)) to enter diagonal matrix\n"
51 " - array of strings of size (($\\frac12N(N+1)$)) to enter symmetric matrix (upper triangle, row by row)\n"
52 " - just one string to enter (spatially variable) multiple of the unit matrix.\n"
53 "Formula can contain variables ```x,y,z,t,d``` and usual operators and functions." )
57 "The vector used to project evaluation point onto the surface.")
59 "The name of region set considered as the surface. You have to set surface region if you "
60 "want to use formula variable ```d```.")
67 template <
int spacedim,
class Value>
69 Input::register_class< FieldFormula<spacedim, Value>,
unsigned int >(
"FieldFormula") +
74 template <
int spacedim,
class Value>
77 formula_matrix_(this->value_.n_rows(), this->value_.n_cols()),
78 first_time_set_(true), arena_alloc_(nullptr)
82 for(
unsigned int row=0; row < this->
value_.n_rows(); row++) {
86 for(
unsigned int i=0; i < this->
value_.n_rows()*this->
value_.n_cols(); i++) {
93 template <
int spacedim,
class Value>
95 this->init_unit_conversion_coefficient(rec, init_data);
103 template <
int spacedim,
class Value>
108 this->is_constant_in_space_ =
false;
113 bool any_parser_changed =
false;
114 std::string value_input_address = in_rec_.address_string();
115 has_depth_var_ =
false;
116 this->is_constant_in_space_ =
true;
119 std::string vars = string(
"x,y,z").substr(0, 2*spacedim-1);
120 std::vector<bool> time_dependent(this->value_.n_rows() * this->value_.n_cols(),
false);
122 for(
unsigned int row=0; row < this->value_.n_rows(); row++)
123 for(
unsigned int col=0; col < this->value_.n_cols(); col++) {
127 FunctionParser tmp_parser;
128 tmp_parser.AddConstant(
"Pi", 3.14159265358979323846);
129 tmp_parser.AddConstant(
"E", 2.71828182845904523536);
132 #pragma GCC diagnostic push
133 #pragma GCC diagnostic ignored "-Wunused-variable"
135 int err=tmp_parser.ParseAndDeduceVariables(formula_matrix_.at(row,col), var_list);
136 ASSERT_PERMANENT(err != FunctionParser::FP_NO_ERROR)(tmp_parser.ErrorMsg()).error(
"ParseAndDeduceVariables error\n");
138 #pragma GCC diagnostic pop
140 for(std::string &var_name : var_list ) {
141 if (var_name == std::string(
"t") ) time_dependent[row*this->value_.n_rows()+col]=
true;
142 else if (var_name == std::string(
"d") ) {
143 this->is_constant_in_space_ =
false;
147 WarningOut().fmt(
"Unset surface region. Variable '{}' in the FieldFormula[{}][{}] == '{}' will be set to zero\n at the input address:\n {} \n",
148 var_name, row, col, formula_matrix_.at(row,col), value_input_address );
150 else if (var_name ==
"x" || var_name ==
"y" || var_name ==
"z") {
151 this->is_constant_in_space_ =
false;
155 WarningOut().fmt(
"Unknown variable '{}' in the FieldFormula[{}][{}] == '{}'\n at the input address:\n {} \n",
156 var_name, row, col, formula_matrix_.at(row,col), value_input_address );
160 parser_matrix_[row][col].AddConstant(
"Pi", 3.14159265358979323846);
161 parser_matrix_[row][col].AddConstant(
"E", 2.71828182845904523536);
162 if (time_dependent[row*this->value_.n_rows()+col]) {
163 parser_matrix_[row][col].AddConstant(
"t", time.
end());
168 vars += string(
",d");
171 for(
unsigned int row=0; row < this->value_.n_rows(); row++)
172 for(
unsigned int col=0; col < this->value_.n_cols(); col++) {
177 if (time_dependent[row*this->value_.n_rows()+col] || first_time_set_ ) {
178 parser_matrix_[row][col].Parse(formula_matrix_.at(row,col), vars);
180 if ( parser_matrix_[row][col].GetParseErrorType() != FunctionParser::FP_NO_ERROR ) {
181 THROW( ExcFParserError() << EI_FParserMsg(parser_matrix_[row][col].ErrorMsg()) << EI_Row(row)
182 << EI_Col(col) << EI_Formula(formula_matrix_.at(row,col)) );
185 parser_matrix_[row][col].Optimize();
186 any_parser_changed =
true;
192 first_time_set_ =
false;
194 return any_parser_changed;
198 template <
int spacedim,
class Value>
201 std::string surface_region;
202 if ( in_rec_.opt_val(
"surface_region", surface_region) ) {
203 surface_depth_ = std::make_shared<SurfaceDepth>(mesh, surface_region, in_rec_.val<std::string>(
"surface_direction"));
211 template <
int spacedim,
class Value>
215 auto p_depth = this->eval_depth_var(p);
216 for(
unsigned int row=0; row < this->value_.n_rows(); row++)
217 for(
unsigned int col=0; col < this->value_.n_cols(); col++) {
218 this->value_(row,col) = this->unit_conversion_coefficient_ * parser_matrix_[row][col].Eval(p_depth.memptr());
220 return this->r_value_;
227 template <
int spacedim,
class Value>
232 ASSERT( point_list.
n_rows() == spacedim && point_list.
n_cols() == 1).error(
"Invalid point size.\n");
233 for(
unsigned int i=0; i< point_list.
size(); i++) {
234 Value envelope(value_list[i]);
235 ASSERT_EQ( envelope.n_rows(), this->value_.n_rows() )(i)(envelope.n_rows())(this->value_.n_rows())
236 .error(
"value_list['i'] has wrong number of rows\n");
237 auto p_depth = this->eval_depth_var(point_list.
vec<spacedim>(i));
239 for(
unsigned int row=0; row < this->value_.n_rows(); row++)
240 for(
unsigned int col=0; col < this->value_.n_cols(); col++) {
241 envelope(row,col) = this->unit_conversion_coefficient_ * parser_matrix_[row][col].Eval(p_depth.memptr());
247 template <
int spacedim,
class Value>
254 for (
unsigned int i=reg_chunk_begin; i<reg_chunk_end; ++i) {
257 for (
auto it : eval_field_data_) {
260 auto value_cache =
it.first->value_cache();
261 for (
unsigned int i=reg_chunk_begin; i<reg_chunk_end; ++i) {
262 if (
it.first->name() ==
"X") {
263 x_[i] = value_cache->template vec<3>(i)(0);
264 y_[i] = value_cache->template vec<3>(i)(1);
265 z_[i] = value_cache->template vec<3>(i)(2);
267 it.second[i] = value_cache->data_[i];
275 subset_vec.assign(subsets_ + subsets_begin, subsets_ + subsets_end);
277 for(
unsigned int row=0; row < this->value_.n_rows(); row++)
278 for(
unsigned int col=0; col < this->value_.n_cols(); col++) {
279 b_parser_[row*this->value_.n_cols()+col].set_subset(subset_vec);
280 b_parser_[row*this->value_.n_cols()+col].run();
281 for (
unsigned int i=reg_chunk_begin; i<reg_chunk_end; ++i) {
282 auto cache_val = data_cache.template mat<Value::NRows_, Value::NCols_>(i);
283 cache_val(row, col) = res_[i];
284 data_cache.
set(i) = cache_val;
290 template <
int spacedim,
class Value>
293 if (surface_depth_ && has_depth_var_) {
296 p_depth.subvec(0,spacedim-1) = p;
298 p_depth(spacedim) = surface_depth_->compute_distance(p);
299 }
catch (SurfaceDepth::ExcTooLargeSnapDistance &e) {
300 e << SurfaceDepth::EI_FieldTime(this->time_.end());
301 e << in_rec_.ei_address();
310 template <
int spacedim,
class Value>
312 required_fields_.clear();
315 for(
unsigned int row=0; row < this->value_.n_rows(); row++)
316 for(
unsigned int col=0; col < this->value_.n_cols(); col++) {
318 unsigned int i_p = row*this->value_.n_cols()+col;
320 std::string expr = formula_matrix_.at(row,col);
323 boost::replace_all(expr,
"^",
"**");
324 boost::replace_all(expr,
"max(",
"maximum(");
325 boost::replace_all(expr,
"min(",
"minimum(");
326 boost::replace_all(expr,
"Pi",
"pi");
327 boost::replace_all(expr,
"E",
"e");
328 boost::replace_all(expr,
"!",
"not");
329 boost::replace_all(expr,
"=",
"==");
330 boost::replace_all(expr,
"<==",
"<=");
331 boost::replace_all(expr,
">==",
">=");
332 boost::replace_all(expr,
":=",
"=");
333 boost::replace_all(expr,
"&",
" and ");
334 boost::replace_all(expr,
"|",
" or ");
338 boost::regex r(R
"((.*)(if\()((?<RR>(?:[^()]*)|((?:[^()]*)\((?&RR)\)(?:[^()]*))*)),((?&RR)),((?&RR))(\))(.*))");
341 if (! boost::regex_match(expr, res, r))
break;
342 std::string tmp = res[1].str() +
"((" + res[6].str() +
") if (" + res[3].str() +
") else (" + res[7].str() +
"))" + res[9].str();
345 DebugOut() <<
"After fparser translation to BParser: " << expr <<
"\n";
365 b_parser_[i_p].parse( expr );
366 }
catch (std::exception
const& e) {
367 if (
typeid(e) ==
typeid(bparser::Exception))
368 THROW( ExcParserError() << EI_BParserMsg(e.what()) << EI_Formula(expr) << Input::EI_Address( in_rec_.address_string() ) );
371 auto list = b_parser_[i_p].free_symbols();
372 variables.insert(variables.end(),
list.begin(),
list.end());
375 std::sort( variables.begin(), variables.end() );
376 variables.erase( std::unique( variables.begin(), variables.end() ), variables.end() );
379 for (
auto var : variables) {
380 if (var ==
"x" || var ==
"y" || var ==
"z") {
381 required_fields_.push_back( field_set.
field(
"X") );
382 sum_shape_sizes_ += spacedim;
384 else if (var ==
"t") has_time_ =
true;
386 auto field_ptr = field_set.
field(var);
387 if (field_ptr !=
nullptr) required_fields_.push_back( field_ptr );
388 else THROW( ExcUnknownField() << EI_Field(var) << Input::EI_Address( in_rec_.address_string() ) );
390 if (field_ptr->value_cache() ==
nullptr)
THROW( ExcNotDoubleField() << EI_Field(var) << Input::EI_Address( in_rec_.address_string() ) );
393 sum_shape_sizes_ += field_ptr->n_shape();
400 return required_fields_;
404 template <
int spacedim,
class Value>
407 if (arena_alloc_!=
nullptr) {
410 eval_field_data_.clear();
415 uint n_vectors = sum_shape_sizes_ + 1;
417 res_ = arena_alloc_->create_array<
double>(vec_size);
418 for (
auto field : required_fields_) {
419 std::string field_name = field->name();
420 eval_field_data_[field] = arena_alloc_->create_array<
double>(field->n_shape() * vec_size);
421 if (field_name ==
"X") {
422 x_ = eval_field_data_[field] + 0;
423 y_ = eval_field_data_[field] + vec_size;
424 z_ = eval_field_data_[field] + 2*vec_size;
427 subsets_ = arena_alloc_->create_array<
uint>(n_subsets);
429 for(
unsigned int row=0; row < this->value_.n_rows(); row++)
430 for(
unsigned int col=0; col < this->value_.n_cols(); col++) {
432 unsigned int i_p = row*this->value_.n_cols()+col;
434 b_parser_[i_p].set_constant(
"t", {}, {this->time_.end()});
436 for (
auto field : required_fields_) {
437 std::string field_name = field->name();
438 if (field_name ==
"X") {
439 b_parser_[i_p].set_variable(
"x", {}, x_);
440 b_parser_[i_p].set_variable(
"y", {}, y_);
441 b_parser_[i_p].set_variable(
"z", {}, z_);
443 b_parser_[i_p].set_variable(field_name, {}, eval_field_data_[field]);
445 b_parser_[i_p].set_variable(
"_result_", {}, res_);
446 b_parser_[i_p].compile();
448 for (
uint i=0; i<n_subsets; ++i)
453 template <
int spacedim,
class Value>