Flow123d  jenkins-Flow123d-linux-release-multijob-282
field_values.hh
Go to the documentation of this file.
1 /*
2  * field_values.hh
3  *
4  * Created on: Dec 6, 2012
5  * Author: jb
6  *
7  *
8  */
9 
10 #ifndef FIELD_VALUES_HH_
11 #define FIELD_VALUES_HH_
12 
13 #include <armadillo>
14 #include <boost/format.hpp>
15 #include <system/exceptions.hh>
16 #include "input/input_type.hh"
17 #include "input/accessors.hh"
18 #include <ostream>
19 
20 namespace IT=Input::Type;
21 
22 /**
23  * @file
24  *
25  * This file contains various dispatch classes to simplify implementation of Fields. Essential is class template
26  * @p FieldValues_ which provides unified access and initialization to scalar, vector and matrix type object in Armadillo library
27  */
28 
29 TYPEDEF_ERR_INFO( EI_InputMsg, const string );
30 DECLARE_INPUT_EXCEPTION( ExcFV_Input, << "Wrong field value input: " << EI_InputMsg::val );
31 
32 
33 /**
34  * Mimics arma::mat<std::string>.
35  */
36 class StringTensor {
37 public:
38  StringTensor( unsigned int n_rows, unsigned int n_cols )
39  : n_rows(n_rows),n_cols(n_cols),n_elem(n_rows*n_cols), values_(n_elem) {}
40 
41  StringTensor(const std::string &value)
42  : n_rows(1), n_cols(1), n_elem(1), values_(1, value) {}
43 
44  std::string & at(unsigned int row) { return at(row,0); }
45  std::string & at(unsigned int row, unsigned int col) { return values_[col*n_rows+row]; }
46  void zeros() {
47  for( auto &elem: values_) elem = "0.0";
48  }
49  unsigned int n_rows;
50  unsigned int n_cols;
51  unsigned int n_elem;
52  operator std::string() {
53  ASSERT_EQUAL( n_elem, 1);
54  return values_[0];
55  }
56  const std::string * memptr() {
57  return &(values_[0]);
58  }
59 private:
61 
62 };
63 
64 
65 typedef unsigned int FieldEnum;
66 
67 
68 
69 namespace internal {
70 
71 // Helper functions to get scalar type name
72 std::string type_name_(double);
73 std::string type_name_(int);
74 std::string type_name_(std::string);
75 std::string type_name_(FieldEnum);
76 
77 
78 inline double &scalar_value_conversion(double &ref) {return ref;}
79 inline int &scalar_value_conversion(int &ref) {return ref;}
80 inline FieldEnum &scalar_value_conversion(FieldEnum &ref) {return ref;}
81 inline std::string &scalar_value_conversion(StringTensor &ref) {
82  ASSERT( ref.n_rows==1 , "Converting StringTensor(n,m) too std::string with m!=1 or n!=1.");
83  return ref.at(0,0);
84 }
85 
86 
87 /**
88  * InputType dispatch from elementary type @p ET of FieldValues_ to elementary Input::Type, i.e. descendant of Input::Type::Scalar.
89  */
90 template <class ET>
91 struct InputType { typedef Input::Type::Double type; };
92 
93 template <>
94 struct InputType<int> { typedef Input::Type::Integer type; };
95 
96 template <>
97 struct InputType<std::string> { typedef Input::Type::String type; }; // for FieldFormula
98 
99 template <>
101 
102 
103 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
104 // resolution of Value::return_type
105 
106 // general element type
107 template<int NRows, int NCols, class ET>
108 struct ReturnType { typedef typename arma::Mat<ET>::template fixed<NRows, NCols> return_type; };
109 
110 template<class ET>
111 struct ReturnType<1,1,ET> { typedef ET return_type; };
112 
113 template <class ET>
114 struct ReturnType<0,1,ET> { typedef arma::Col<ET> return_type; };
115 
116 template <int NRows, class ET>
117 struct ReturnType<NRows,1,ET> { typedef typename arma::Col<ET>::template fixed<NRows> return_type; };
118 
119 
120 // string element type (for FieldFormula)
121 template<int NRows, int NCols>
122 struct ReturnType<NRows, NCols, std::string> { typedef StringTensor return_type; };
123 
124 template<>
125 struct ReturnType<1,1, std::string> { typedef StringTensor return_type; };
126 
127 template <>
128 struct ReturnType<0,1, std::string> { typedef StringTensor return_type; };
129 
130 template <int NRows>
131 struct ReturnType<NRows,1, std::string> { typedef StringTensor return_type; };
132 
133 
134 // FiledEnum element type - this just returns types with ET=unsigned int, however input should be different
135 template<int NRows, int NCols>
136 struct ReturnType<NRows, NCols, FieldEnum> { typedef typename arma::Mat<unsigned int>::template fixed<NRows, NCols> return_type; };
137 
138 template<>
139 struct ReturnType<1,1, FieldEnum> { typedef unsigned int return_type; };
140 
141 template <>
142 struct ReturnType<0,1, FieldEnum> { typedef arma::Col<unsigned int> return_type; };
143 
144 template <int NRows>
145 struct ReturnType<NRows,1, FieldEnum> { typedef typename arma::Col<unsigned int>::template fixed<NRows> return_type; };
146 
147 
148 // Resolution of helper functions for raw constructor
149 template <class RT> inline RT & set_raw_scalar(RT &val, double *raw_data) { return *raw_data;}
150 template <class RT> inline RT & set_raw_scalar(RT &val, int *raw_data) { return *raw_data;}
151 template <class RT> inline RT & set_raw_scalar(RT &val, string *raw_data) { return val;}
152 template <class RT> inline RT & set_raw_scalar(RT &val, FieldEnum *raw_data) { return *raw_data;}
153 
154 template <class RT> inline RT & set_raw_vec(RT &val, double *raw_data) { arma::access::rw(val.mem) = raw_data; return val;}
155 template <class RT> inline RT & set_raw_vec(RT &val, int *raw_data) { arma::access::rw(val.mem) = raw_data; return val;}
156 template <class RT> inline RT & set_raw_vec(RT &val, string *raw_data) { return val;}
157 template <class RT> inline RT & set_raw_vec(RT &val, FieldEnum *raw_data) { arma::access::rw(val.mem) = raw_data; return val;}
158 
159 template <class RT> inline RT & set_raw_fix(RT &val, double *raw_data) { val = RT(raw_data); return val;}
160 template <class RT> inline RT & set_raw_fix(RT &val, int *raw_data) { val = RT(raw_data); return val;}
161 template <class RT> inline RT & set_raw_fix(RT &val, string *raw_data) { return val;}
162 template <class RT> inline RT & set_raw_fix(RT &val, FieldEnum *raw_data) { val = RT(raw_data); return val;}
163 
164 } // namespace internal
165 
166 
167 
168 /**
169  * Template for class representing all possible Filed values. It is just common interface to
170  * scalar (double, int) values, vector and tensor values with fixed size and vector/tensor values with variable size.
171  *
172  * ET is type of elements, n_cols and n_rows gives fixed dimensions of the tensor value (nx1 is vector, 1x1 is scalar,
173  * 0x1 is variable size vector, 0x0 is variable size tensor (not implemented yet) )
174  *
175  * TODO:
176  * This wrapper serves at least to several different things:
177  * - Unified reading of input values (for FieldConstant, FieldFormula, etc.)
178  * provided by init_from_input
179  * - Unified InputType objects, provided by type_name(), get_input_type()
180  *
181  * - For unified matrix-like access even to scalar and vector values, without compromising performance.
182  * provided by operator(); n_cols, n_rows, from_raw, ...
183  *
184  * Maybe it could be better to split these two functions into two distinguish but related classes.
185  *
186  */
187 template <int NRows, int NCols, class ET>
188 class FieldValue_ {
189 public:
190  typedef ET element_type;
194  const static int NRows_ = NRows;
195  const static int NCols_ = NCols;
196 
197  static std::string type_name() { return boost::str(boost::format("%s[%d,%d]") % internal::type_name_( ET() ) % NRows % NCols); }
198  static IT::Array get_input_type(const ElementInputType *element_input_type=nullptr) {
199  if (element_input_type) {
200  // has sense only for ET==FieldEnum
201  if (NRows == NCols)
202  // for square tensors allow initialization by diagonal vector, etc.
203  return IT::Array( IT::Array( *element_input_type, 1), 1 );
204  else
205  return IT::Array( IT::Array( *element_input_type, NCols, NCols), NRows, NRows );
206 
207  } else {
208  if (NRows == NCols)
209  // for square tensors allow initialization by diagonal vector, etc.
210  return IT::Array( IT::Array( ElementInputType(), 1), 1 );
211  else
212  return IT::Array( IT::Array( ElementInputType(), NCols, NCols), NRows, NRows );
213  }
214  }
215 
216 
217  inline FieldValue_(return_type &val) : value_(val) {}
218  inline static const return_type &from_raw(return_type &val, ET *raw_data) {return internal::set_raw_fix(val, raw_data);}
219  const ET * mem_ptr() { return value_.memptr(); }
220 
221 
224  if (it->size() == 1 && NRows == NCols) {
225  // square tensor
226  // input = 3 expands to [ [ 3 ] ]; init to 3 * (identity matrix)
227  // input = [1, 2, 3] expands to [[1], [2], [3]]; init to diag. matrix
228  // input = [1, 2, 3, .. , (N+1)*N/2], .... ; init to symmetric matrix [ [1 ,2 ,3], [2, 4, 5], [ 3, 5, 6] ]
229 
230 
231  if (rec.size() == 1) {// scalar times identity
232  value_.zeros();
233  ET scalar=*(it->begin<ET>());
234  for(unsigned int i=0; i< NRows; i++) value_.at(i,i)=scalar;
235  } else if (rec.size() == NRows) { // diagonal vector
236  value_.zeros();
237  for(unsigned int i=0; i< NRows; i++, ++it) value_.at(i,i)=*(it->begin<ET>());
238  } else if (rec.size() == (NRows+1)*NRows/2) { // symmetric part
239  for( unsigned int row=0; row<NRows; row++)
240  for( unsigned int col=0; col<NCols; col++)
241  if (row <= col) {
242  value_.at(row,col) = *(it->begin<ET>());
243  ++it;
244  } else value_.at(row,col) = value_.at(col,row);
245  } else {
246  THROW( ExcFV_Input()
247  << EI_InputMsg(
248  boost::str(boost::format("Initializing symmetric matrix %dx%d by vector of wrong size %d, should be 1, %d, or %d.")
249  % NRows % NCols % rec.size() % NRows % ((NRows+1)*NRows/2)))
250  << rec.ei_address()
251 
252  );
253  }
254 
255  } else {
256  // accept only full tensor
257  if (rec.size() == NRows && it->size() == NCols) {
258 
259  for (unsigned int row = 0; row < NRows; row++, ++it) {
260  if (it->size() != NCols)
261  THROW( ExcFV_Input() << EI_InputMsg("Wrong number of columns.")
262  << rec.ei_address());
263  Input::Iterator<ET> col_it = it->begin<ET>();
264  for (unsigned int col = 0; col < NCols; col++, ++col_it)
265  value_.at(row, col) = *col_it;
266  }
267  } else {
268  THROW( ExcFV_Input()
269  << EI_InputMsg(
270  boost::str(boost::format("Initializing matrix %dx%d by matrix of wrong size %dx%d.")
271  % NRows % NCols % rec.size() % it->size() ))
272  << rec.ei_address()
273  );
274  }
275  }
276  }
277 
278  void set_n_comp(unsigned int) {};
279  inline unsigned int n_cols() const
280  { return NCols; }
281  inline unsigned int n_rows() const
282  { return NRows; }
283  inline ET &operator() ( unsigned int i, unsigned int j)
284  { return value_.at(i,j); }
285  inline ET operator() ( unsigned int i, unsigned int j) const
286  { return value_.at(i,j); }
287  inline operator return_type() const
288  { return value_;}
289 
290 private:
292 };
293 
294 template <class ET>
295 struct AccessTypeDispatch { typedef ET type;};
296 template <>
297 struct AccessTypeDispatch<unsigned int> { typedef Input::Enum type; };
298 
299 
300 
301 /// **********************************************************************
302 /// Specialization for scalars
303 template <class ET>
304 class FieldValue_<1,1,ET> {
305 public:
306  typedef ET element_type;
310  const static int NRows_ = 1;
311  const static int NCols_ = 1;
312 
313  static std::string type_name() { return boost::str(boost::format("%s") % internal::type_name_( ET() ) ); }
314  static ElementInputType get_input_type(const ElementInputType *element_input_type=nullptr)
315  {
316  if (element_input_type)
317  return *element_input_type;
318  else
319  return ElementInputType();
320  }
321 
322  inline FieldValue_(return_type &val) : value_(val) {}
323 
324  /**
325  * Returns reference to the return_type (i.e. double, or arma::vec or arma::mat); with data provided by the parameter @p raw_data.
326  * A reference to a work space @p val has to be provided for efficient work with vector and matrix values.
327  */
328  inline static const return_type &from_raw(return_type &val, ET *raw_data) {return internal::set_raw_scalar(val, raw_data);}
329  const ET * mem_ptr() { return &(internal::scalar_value_conversion(value_)); }
330 
332 
333  void set_n_comp(unsigned int) {};
334  inline unsigned int n_cols() const
335  { return 1; }
336  inline unsigned int n_rows() const
337  { return 1; }
338  inline ET &operator() ( unsigned int, unsigned int )
340  inline ET operator() ( unsigned int i, unsigned int j) const
342 
343  inline operator return_type() const
344  { return value_;}
345 
346 private:
348 };
349 
350 
351 
352 
353 /// **********************************************************************
354 /// Specialization for variable size vectors
355 template <class ET>
356 class FieldValue_<0,1,ET> {
357 public:
358  typedef ET element_type;
362  const static int NRows_ = 0;
363  const static int NCols_ = 1;
364 
365 
366  static std::string type_name() { return boost::str(boost::format("%s[n]") % internal::type_name_( ET() ) ); }
367  static IT::Array get_input_type(const ElementInputType *element_input_type=nullptr) {
368  if (element_input_type) {
369  return IT::Array( *element_input_type, 1);
370  } else {
371  return IT::Array( ElementInputType(), 1);
372  }
373  }
374  inline static const return_type &from_raw(return_type &val, ET *raw_data) {return internal::set_raw_vec(val, raw_data);}
375  const ET * mem_ptr() { return value_.memptr(); }
376 
377  inline FieldValue_(return_type &val) : value_(val) {}
378 
379 
381  typedef typename AccessTypeDispatch<ET>::type InnerType;
382  Input::Iterator<InnerType> it = rec.begin<InnerType>();
383 
384  if ( rec.size() == 1 ) {
385  for(unsigned int i=0; i< n_rows(); i++)
386  value_.at(i)=ET(*it);
387  } else if ( rec.size() == n_rows() ) {
388  for(unsigned int i=0; i< n_rows(); i++, ++it) {
389  value_.at(i)=ET(*it);
390  }
391  } else {
392  THROW( ExcFV_Input()
393  << EI_InputMsg(
394  boost::str(boost::format("Initializing vector of size %d by vector of size %d.")
395  % n_rows() % rec.size() ))
396  << rec.ei_address()
397  );
398  }
399  }
400 
401  void set_n_comp(unsigned int n_comp) { value_ = return_type(n_comp,1); };
402  inline unsigned int n_cols() const
403  { return 1; }
404  inline unsigned int n_rows() const
405  { return value_.n_rows; }
406  inline ET &operator() ( unsigned int i, unsigned int )
407  { return value_.at(i); }
408  inline ET operator() ( unsigned int i, unsigned int j) const
409  { return value_.at(i); }
410 
411  inline operator return_type() const
412  { return value_;}
413 
414 private:
416 };
417 
418 /// **********************************************************************
419 /// Specialization for fixed size vectors
420 template <int NRows, class ET>
421 class FieldValue_<NRows,1,ET> {
422 public:
423  typedef ET element_type;
427  const static int NRows_ = NRows;
428  const static int NCols_ = 1;
429 
430 
431  static std::string type_name() { return boost::str(boost::format("%s[%d]") % internal::type_name_( ET() ) % NRows ); }
432  static IT::Array get_input_type(const ElementInputType *element_input_type=nullptr) {
433  if (element_input_type) {
434  return IT::Array( *element_input_type, 1, NRows);
435  } else {
436  return IT::Array( ElementInputType(), 1, NRows);
437  }
438  }
439 
440  inline FieldValue_(return_type &val) : value_(val) {}
441  inline static const return_type &from_raw(return_type &val, ET *raw_data) {return internal::set_raw_fix(val, raw_data);}
442  const ET * mem_ptr() { return value_.memptr(); }
443 
445  Input::Iterator<ET> it = rec.begin<ET>();
446 
447  if ( rec.size() == 1 ) {
448  for(unsigned int i=0; i< n_rows(); i++)
449  value_.at(i)=*it;
450  } else if ( rec.size() == NRows ) {
451  for(unsigned int i=0; i< NRows; i++, ++it)
452  value_.at(i)=*it;
453  } else {
454  THROW( ExcFV_Input()
455  << EI_InputMsg(
456  boost::str(boost::format("Initializing fixed vector of size %d by vector of size %d.")
457  % n_rows() % rec.size() ))
458  << rec.ei_address()
459  );
460  }
461  }
462 
463  void set_n_comp(unsigned int) {};
464  inline unsigned int n_cols() const
465  { return 1; }
466  inline unsigned int n_rows() const
467  { return NRows; }
468  inline ET &operator() ( unsigned int i, unsigned int )
469  { return value_.at(i); }
470  inline ET operator() ( unsigned int i, unsigned int j) const
471  { return value_.at(i); }
472 
473  inline operator return_type() const
474  { return value_;}
475 
476 private:
478 };
479 
480 
481 
482 
483 
484 
485 /**
486  * Class that provides common template-less interface to all templated Field structes.
487  *
488  * Maybe we can delete this since common interface will be given by "Quantity".
489  */
490 
491 template <int spacedim>
492 struct FieldValue {
493  // typedefs for possible field values
502 };
503 
504 
505 
506 
507 
508 
509 
510 
511 
512 
513 #endif /* FIELD_VALUES_HH_ */
void init_from_input(AccessType val)
internal::ReturnType< 1, 1, ET >::return_type return_type
Iterator< ValueType > begin() const
internal::InputType< ET >::type ElementInputType
static const int NRows_
Accessor to input data conforming to declared Array.
Definition: accessors.hh:558
static const return_type & from_raw(return_type &val, ET *raw_data)
EI_Address ei_address() const
Definition: accessors.cc:297
void set_n_comp(unsigned int)
arma::Col< unsigned int > return_type
std::vector< std::string > values_
Definition: field_values.hh:60
ET & operator()(unsigned int i, unsigned int j)
internal::InputType< ET >::type ElementInputType
FieldValue_< 0, 1, int > IntVector
static const return_type & from_raw(return_type &val, ET *raw_data)
void set_n_comp(unsigned int n_comp)
void set_n_comp(unsigned int)
void init_from_input(AccessType rec)
static std::string type_name()
RT & set_raw_vec(RT &val, double *raw_data)
void set_n_comp(unsigned int)
unsigned int n_cols() const
const ET * mem_ptr()
internal::ReturnType< NRows, NCols, ET >::return_type return_type
FieldValue_(return_type &val)
void init_from_input(AccessType rec)
Input::Type::Selection type
FieldValue_< 1, 1, FieldEnum > Enum
Class for declaration of the integral input data.
Definition: type_base.hh:355
void init_from_input(AccessType rec)
Class for declaration of inputs sequences.
Definition: type_base.hh:239
static const int NCols_
static ElementInputType get_input_type(const ElementInputType *element_input_type=nullptr)
static IT::Array get_input_type(const ElementInputType *element_input_type=nullptr)
arma::Col< unsigned int >::template fixed< NRows > return_type
StringTensor(unsigned int n_rows, unsigned int n_cols)
Definition: field_values.hh:38
internal::InputType< ET >::type ElementInputType
#define ASSERT(...)
Definition: global_defs.h:121
Class for declaration of the input data that are floating point numbers.
Definition: type_base.hh:392
static std::string type_name()
FieldValue_< 0, 1, FieldEnum > EnumVector
unsigned int n_elem
Definition: field_values.hh:51
static IT::Array get_input_type(const ElementInputType *element_input_type=nullptr)
unsigned int FieldEnum
Definition: field_values.hh:65
#define ASSERT_EQUAL(a, b)
Definition: global_defs.h:136
unsigned int n_rows
Definition: field_values.hh:49
internal::InputType< ET >::type ElementInputType
internal::ReturnType< NRows, 1, ET >::return_type return_type
return_type & value_
std::string & at(unsigned int row, unsigned int col)
Definition: field_values.hh:45
FieldValue_< spacedim, 1, double > VectorFixed
AccessTypeDispatch< ET >::type AccessType
#define TYPEDEF_ERR_INFO(EI_Type, Type)
Macro to simplify declaration of error_info types.
Definition: exceptions.hh:171
static std::string type_name()
unsigned int n_rows() const
RT & set_raw_fix(RT &val, double *raw_data)
arma::Mat< ET >::template fixed< NRows, NCols > return_type
internal::ReturnType< 0, 1, ET >::return_type return_type
std::string & at(unsigned int row)
Definition: field_values.hh:44
StringTensor(const std::string &value)
Definition: field_values.hh:41
unsigned int n_cols() const
unsigned int n_rows() const
Input::Type::Integer type
Definition: field_values.hh:94
arma::Mat< unsigned int >::template fixed< NRows, NCols > return_type
unsigned int n_cols() const
Input::Type::Double type
Definition: field_values.hh:91
unsigned int n_cols
Definition: field_values.hh:50
FieldValue_< 1, 1, int > Integer
const std::string * memptr()
Definition: field_values.hh:56
FieldValue_(return_type &val)
FieldValue_< 0, 1, double > Vector
static std::string type_name()
DECLARE_INPUT_EXCEPTION(ExcFV_Input,<< "Wrong field value input: "<< EI_InputMsg::val)
static const return_type & from_raw(return_type &val, ET *raw_data)
FieldValue_(return_type &val)
unsigned int size() const
Input::Array AccessType
static const return_type & from_raw(return_type &val, ET *raw_data)
FieldValue_< spacedim, spacedim, double > TensorFixed
unsigned int n_rows() const
unsigned int n_cols() const
arma::Col< ET >::template fixed< NRows > return_type
double & scalar_value_conversion(double &ref)
Definition: field_values.hh:78
static IT::Array get_input_type(const ElementInputType *element_input_type=nullptr)
RT & set_raw_scalar(RT &val, double *raw_data)
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:34
Template for classes storing finite set of named values.
std::string type_name_(double)
Definition: field_values.cc:13
FieldValue_< 1, 1, double > Scalar
FieldValue_(return_type &val)
unsigned int n_rows() const