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