Flow123d  release_3.0.0-1094-g626f1a1
element_data_cache.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 element_data_cache.cc
15  * @brief
16  */
17 
18 
19 #include <limits>
20 #include <ostream>
21 #include "io/element_data_cache.hh"
22 #include "io/msh_basereader.hh"
23 #include "la/distribution.hh"
25 #include "system/system.hh"
26 #include "system/tokenizer.hh"
27 #include "boost/lexical_cast.hpp"
28 
29 
30 
31 template <typename T>
34  check_scale_data_(CheckScaleData::none) {}
35 
36 
37 template <typename T>
38 ElementDataCache<T>::ElementDataCache(std::string field_name, double time, unsigned int size_of_cache, unsigned int row_vec_size)
40 {
41  this->time_ = time;
42  this->field_input_name_ = field_name;
43  this->data_ = create_data_cache(size_of_cache, row_vec_size);
44 }
45 
46 
47 template <typename T>
48 ElementDataCache<T>::ElementDataCache(std::string field_name, unsigned int n_comp, unsigned int size)
50 {
51  this->set_vtk_type<T>();
52  this->field_name_ = field_name;
53  this->field_input_name_ = this->field_name_;
54 
55  this->n_values_ = size;
56  ASSERT_GT(n_comp, 0)(field_name).error("Output field returning variable size vectors. Try convert to MultiField.");
57  this->n_comp_ = n_comp;
58 
60 }
61 
62 
63 template <typename T>
65 
66 
67 template <typename T>
69  ASSERT_LT(component_idx, data_.size()).error("Index of component is out of range.\n");
70  return data_[component_idx];
71 }
72 
73 
74 template <typename T>
75 typename ElementDataCache<T>::CacheData ElementDataCache<T>::create_data_cache(unsigned int size_of_cache, unsigned int row_vec_size) {
76  typename ElementDataCache<T>::CacheData data_cache(size_of_cache);
77  for (unsigned int i=0; i<size_of_cache; ++i) {
78  typename ElementDataCache<T>::ComponentDataPtr row_vec = std::make_shared<std::vector<T>>();
79  row_vec->resize(row_vec_size, numeric_limits<T>::signaling_NaN());
80  data_cache[i] = row_vec;
81  }
82 
83  return data_cache;
84 }
85 
86 
87 template <typename T>
88 void ElementDataCache<T>::read_ascii_data(Tokenizer &tok, unsigned int n_components, unsigned int i_row) {
89  unsigned int idx;
90  for (unsigned int i_vec=0; i_vec<data_.size(); ++i_vec) {
91  idx = i_row * n_components;
92  std::vector<T> &vec = *( data_[i_vec].get() );
93  for (unsigned int i_col=0; i_col < n_components; ++i_col, ++idx) {
94  vec[idx] = boost::lexical_cast<T>(*tok);
95  ++tok;
96  }
97  }
98 }
99 
100 
101 template <typename T>
102 void ElementDataCache<T>::read_binary_data(std::istream &data_stream, unsigned int n_components, unsigned int i_row) {
103  unsigned int idx;
104  for (unsigned int i_vec=0; i_vec<data_.size(); ++i_vec) {
105  idx = i_row * n_components;
106  std::vector<T> &vec = *( data_[i_vec].get() );
107  for (unsigned int i_col=0; i_col < n_components; ++i_col, ++idx) {
108  data_stream.read(reinterpret_cast<char *>(&vec[idx]), sizeof(T));
109  }
110  }
111 }
112 
113 
114 /**
115  * Output data element on given index @p idx. Method for writing data
116  * to output stream.
117  *
118  * \note This method is used only by MSH file format.
119  */
120 template <typename T>
121 void ElementDataCache<T>::print_ascii(ostream &out_stream, unsigned int idx)
122 {
123  ASSERT_LT(idx, this->n_values_).error();
124  std::vector<T> &vec = *( this->data_[0].get() );
125  for(unsigned int i = n_comp_*idx; i < n_comp_*(idx+1); ++i )
126  out_stream << vec[i] << " ";
127 }
128 
129 /**
130  * \brief Print all data stored in output data
131  *
132  * TODO: indicate if the tensor data are output in column-first or raw-first order
133  * and possibly implement transposition. Set such property for individual file formats.
134  * Class OutputData stores always in raw-first order.
135  */
136 template <typename T>
137 void ElementDataCache<T>::print_ascii_all(ostream &out_stream)
138 {
139  std::vector<T> &vec = *( this->data_[0].get() );
140  for(unsigned int idx = 0; idx < this->n_values_; idx++) {
141  for(unsigned int i = n_comp_*idx; i < n_comp_*(idx+1); ++i )
142  out_stream << vec[i] << " ";
143  }
144 }
145 
146 
147 /// Prints the whole data vector into stream.
148 template <typename T>
149 void ElementDataCache<T>::print_binary_all(ostream &out_stream, bool print_data_size)
150 {
151  if (print_data_size) {
152  // write size of data
153  unsigned long long int data_byte_size = this->n_values_ * n_comp_ * sizeof(T);
154  out_stream.write(reinterpret_cast<const char*>(&data_byte_size), sizeof(unsigned long long int));
155  }
156  // write data
157  std::vector<T> &vec = *( this->data_[0].get() );
158  for(unsigned int idx = 0; idx < this->n_values_; idx++) {
159  for(unsigned int i = n_comp_*idx; i < n_comp_*(idx+1); ++i )
160  out_stream.write(reinterpret_cast<const char*>(&(vec[i])), sizeof(T));
161  }
162 }
163 
164 
165 template <typename T>
166 void ElementDataCache<T>::print_all_yaml(ostream &out_stream, unsigned int precision)
167 {
168  out_stream << "[ ";
169  std::vector<T> &vec = *( this->data_[0].get() );
170  for(unsigned int idx = 0; idx < this->n_values_; idx++) {
171  if (idx != 0) out_stream << " , ";
172  unsigned int vec_pos = n_comp_ * idx; // position of element value in data cache
173  switch (this->n_comp_) {
174  case NumCompValueType::N_SCALAR: {
175  out_stream << field_value_to_yaml( vec[vec_pos], precision );
176  break;
177  }
178  case NumCompValueType::N_VECTOR: {
179  typename arma::Col<T>::template fixed<3> vec_val;
180  for (unsigned int i=0; i<3; ++i, ++vec_pos)
181  vec_val(i) = vec[vec_pos];
182  out_stream << field_value_to_yaml( vec_val, precision );
183  break;
184  }
185  case NumCompValueType::N_TENSOR: {
186  typename arma::Mat<T>::template fixed<3,3> mat_val;
187  for (unsigned int i=0; i<3; ++i)
188  for (unsigned int j=0; j<3; ++j, ++vec_pos)
189  mat_val(i,j) = vec[vec_pos];
190  out_stream << field_value_to_yaml( mat_val, precision );
191  break;
192  }
193  }
194  }
195  out_stream << " ]";
196 }
197 
198 
199 template <typename T>
200 void ElementDataCache<T>::get_min_max_range(double &min, double &max)
201 {
202  min = std::numeric_limits<double>::max();
203  max = std::numeric_limits<double>::min();
204  std::vector<T> &vec = *( this->data_[0].get() );
205  for(unsigned int idx = 0; idx < this->n_values_; idx++) {
206  for(unsigned int i = n_comp_*idx; i < n_comp_*(idx+1); ++i ) {
207  if (vec[i] < min) min = vec[i];
208  if (vec[i] > max) max = vec[i];
209  }
210  }
211 }
212 
213 
214 /**
215  * Store data element of given data value under given index.
216  */
217 template <typename T>
218 void ElementDataCache<T>::store_value(unsigned int idx, const T * value) {
219  ASSERT_LT_DBG(idx, this->n_values_);
220  std::vector<T> &vec = *( this->data_[0].get() );
221  unsigned int vec_idx = idx*this->n_comp_;
222  for(unsigned int i = 0; i < this->n_comp_; i++, vec_idx++) {
223  vec[vec_idx] = value[i];
224  }
225 };
226 
227 /**
228  * Add value to given index
229  */
230 template <typename T>
231 void ElementDataCache<T>::add(unsigned int idx, const T * value) {
232  ASSERT_LT_DBG(idx, this->n_values_);
233  std::vector<T> &vec = *( this->data_[0].get() );
234  unsigned int vec_idx = idx*this->n_comp_;
235  for(unsigned int i = 0; i < this->n_comp_; i++, vec_idx++) {
236  vec[vec_idx] += value[i];
237  }
238 };
239 
240 /**
241  * Reset values at given index
242  */
243 template <typename T>
244 void ElementDataCache<T>::zero(unsigned int idx) {
245  ASSERT_LT_DBG(idx, this->n_values_);
246  std::vector<T> &vec = *( this->data_[0].get() );
247  unsigned int vec_idx = idx*this->n_comp_;
248  for(unsigned int i = 0; i < this->n_comp_; i++, vec_idx++) {
249  vec[vec_idx] = 0;
250  }
251 };
252 
253 /**
254  * Normalize values at given index
255  */
256 template <typename T>
257 void ElementDataCache<T>::normalize(unsigned int idx, unsigned int divisor) {
258  ASSERT_LT_DBG(idx, this->n_values_);
259  std::vector<T> &vec = *( this->data_[0].get() );
260  unsigned int vec_idx = idx*this->n_comp_;
261  for(unsigned int i = 0; i < this->n_comp_; i++, vec_idx++) {
262  vec[vec_idx] /= divisor;
263  }
264 };
265 
266 template <typename T>
267 CheckResult ElementDataCache<T>::check_values(double default_val, double lower_bound, double upper_bound) {
268  if (check_scale_data_ != CheckScaleData::none) return CheckResult::ok; // method is executed only once
270 
271  bool is_nan = false, out_of_limit = false;
272  for (unsigned int j=0; j<data_.size(); ++j) {
273  std::vector<T> &vec = *( this->data_[j].get() );
274  for(unsigned int i=0; i<vec.size(); ++i) {
275  if ( std::isnan(vec[i]) ) {
276  if ( std::isnan(default_val) ) is_nan = true;
277  else vec[i] = default_val;
278  }
279  if ( (vec[i] < lower_bound) || (vec[i] > upper_bound) ) out_of_limit = true;
280  }
281  }
282 
283  if (is_nan) return CheckResult::not_a_number;
284  else if (out_of_limit) return CheckResult::out_of_limits;
285  else return CheckResult::ok;
286 };
287 
288 template <typename T>
290  if (check_scale_data_ == CheckScaleData::scale) return; // method is executed only once
291  ASSERT_DBG(check_scale_data_ == CheckScaleData::check).warning("Data should be checked before scaling. Rather call 'check_values'!\n");
292 
293  for (unsigned int j=0; j<data_.size(); ++j) {
294  std::vector<T> &vec = *( this->data_[j].get() );
295  for(unsigned int i=0; i<vec.size(); ++i) {
296  vec[i] *= coef;
297  }
298  }
299 
300  check_scale_data_ = CheckScaleData::scale;
301 };
302 
303 
304 template <typename T>
305 std::shared_ptr< ElementDataCacheBase > ElementDataCache<T>::gather(Distribution *distr, LongIdx *local_to_global) {
306  std::shared_ptr< ElementDataCache<T> > gather_cache;
307  int rank = distr->myp();
308  int n_proc = distr->np();
309 
310  unsigned int n_global_data; // global number of data
311  int rec_starts[n_proc]; // displacement of first value that is received from each process
312  int rec_counts[n_proc]; // number of values that are received from each process
313  int *rec_indices_ids; // collective values of local to global indexes map of data
314  T *rec_data; // collective values of data
315 
316  // collects values of data vectors and local to global indexes map on each process
317  if (rank==0) {
318  for (int i=0; i<n_proc; ++i) {
319  rec_starts[i] = distr->begin(i);
320  rec_counts[i] = distr->lsize(i);
321  }
322  n_global_data = distr->size();
323  rec_indices_ids = new int [ n_global_data ];
324  }
325  MPI_Gatherv( local_to_global, distr->lsize(), MPI_INT, rec_indices_ids, rec_counts, rec_starts, MPI_INT, 0, MPI_COMM_WORLD);
326  if (rank==0) {
327  for (int i=0; i<n_proc; ++i) {
328  rec_starts[i] = this->n_comp()*rec_starts[i];
329  rec_counts[i] = this->n_comp()*rec_counts[i];
330  }
331  rec_data = new T [ this->n_comp() * n_global_data ];
332  }
333  auto &local_cache_vec = *( this->get_component_data(0).get() );
334  MPI_Gatherv( &local_cache_vec[0], this->n_comp()*distr->lsize(), this->mpi_data_type(), rec_data, rec_counts, rec_starts, this->mpi_data_type(), 0, MPI_COMM_WORLD) ;
335 
336  // create and fill serial cache
337  if (rank==0) {
338  gather_cache = std::make_shared<ElementDataCache<T>>(this->field_input_name_, (unsigned int)this->n_comp(), n_global_data);
339  auto &gather_vec = *( gather_cache->get_component_data(0).get() );
340  unsigned int i_global_coord; // counter over serial_mesh->nodes_ cache
341  for (unsigned int i=0; i<n_global_data; ++i) {
342  i_global_coord = this->n_comp() * rec_indices_ids[i];
343  for (unsigned int j=0; j<this->n_comp(); ++j) { //loop over coords
344  ASSERT_LT(i_global_coord+j, gather_vec.size());
345  gather_vec[ i_global_coord+j ] = rec_data[ this->n_comp()*i+j ];
346  }
347  }
348 
349  delete[] rec_indices_ids;
350  delete[] rec_data;
351  }
352 
353  return gather_cache;
354 }
355 
356 
357 template <typename T>
358 std::shared_ptr< ElementDataCacheBase > ElementDataCache<T>::element_node_cache_fixed_size(std::vector<unsigned int> &offset_vec) {
359  unsigned int n_elem = offset_vec.size();
360  std::shared_ptr< ElementDataCache<T> > elem_node_cache = std::make_shared<ElementDataCache<T>>(this->field_input_name_, 4*this->n_comp(), n_elem);
361  auto &data_out_vec = *( elem_node_cache->get_component_data(0).get() );
362  std::fill( data_out_vec.begin(), data_out_vec.end(), (T)0 );
363  auto &data_in_vec = *( this->get_component_data(0).get() );
364 
365  unsigned int i_node, i_old, i_new;
366  for (unsigned int i_el=0, i_conn=0; i_el<offset_vec.size(); i_el++) {
367  for(i_node=4*i_el; i_conn<offset_vec[i_el]; i_conn++, i_node++) {
368  i_old = i_conn*this->n_comp_;
369  i_new = i_node*this->n_comp_;
370  for(unsigned int i = 0; i < this->n_comp_; i++) {
371  ASSERT_LT(i_new+i, data_out_vec.size());
372  ASSERT_LT(i_old+i, data_in_vec.size());
373  data_out_vec[i_new+i] = data_in_vec[i_old+i];
374  }
375  }
376  }
377 
378  return elem_node_cache;
379 }
380 
381 
382 template <typename T>
383 std::shared_ptr< ElementDataCacheBase > ElementDataCache<T>::element_node_cache_optimize_size(std::vector<unsigned int> &offset_vec) {
384  std::shared_ptr< ElementDataCache<T> > elem_node_cache = std::make_shared<ElementDataCache<T>>(this->field_input_name_,
385  this->n_comp()/4, offset_vec[offset_vec.size()-1]);
386  auto &data_out_vec = *( elem_node_cache->get_component_data(0).get() );
387  auto &data_in_vec = *( this->get_component_data(0).get() );
388 
389  unsigned int i_node, i_old, i_new;
390  for (unsigned int i_el=0, i_conn=0; i_el<offset_vec.size(); i_el++) {
391  for(i_node=4*i_el; i_conn<offset_vec[i_el]; i_conn++, i_node++) {
392  i_old = i_node*elem_node_cache->n_comp_;
393  i_new = i_conn*elem_node_cache->n_comp_;
394  for(unsigned int i = 0; i < elem_node_cache->n_comp_; i++) {
395  ASSERT_LT(i_new+i, data_out_vec.size());
396  ASSERT_LT(i_old+i, data_in_vec.size());
397  data_out_vec[i_new+i] = data_in_vec[i_old+i];
398  }
399  }
400  }
401  return elem_node_cache;
402 }
403 
404 
405 template <typename T>
406 std::shared_ptr< ElementDataCacheBase > ElementDataCache<T>::compute_node_data(std::vector<unsigned int> &conn_vec, unsigned int data_size) {
407  ASSERT_EQ(conn_vec.size(), this->n_values());
408  unsigned int idx;
409 
410  // set output data to zero
411  std::shared_ptr< ElementDataCache<T> > node_cache = std::make_shared<ElementDataCache<T>>(this->field_input_name_, this->n_comp(), data_size);
412  std::vector<unsigned int> count(data_size, 0);
413  for (idx=0; idx < node_cache->n_values(); idx++)
414  node_cache->zero(idx);
415 
416  auto &data_in_vec = *( this->get_component_data(0).get() );
417  for (idx=0; idx < conn_vec.size(); idx++) {
418  ASSERT_LT(conn_vec[idx], node_cache->n_values());
419  ASSERT_LT(this->n_comp()*idx, data_in_vec.size());
420  node_cache->add( conn_vec[idx], &(data_in_vec[this->n_comp() * idx]) );
421  count[ conn_vec[idx] ]++;
422  }
423 
424  // Compute mean values at nodes
425  for(idx=0; idx < node_cache->n_values(); idx++)
426  node_cache->normalize(idx, count[idx]);
427 
428  return node_cache;
429 }
430 
431 
432 template<>
434  return MPI_DOUBLE;
435 };
436 
437 template<>
439  return MPI_INT;
440 };
441 
442 template<>
444  return MPI_UNSIGNED;
445 };
446 
447 
448 /// Access i-th element in the data vector.
449 template <class T>
451 {
452  std::vector<T> &vec = *( this->data_[0].get() );
453  ASSERT_DBG(i < vec.size());
454  return vec[i];
455 }
456 
457 
458 
459 // explicit instantiation of template class
460 template class ElementDataCache<unsigned int>;
461 template class ElementDataCache<int>;
462 template class ElementDataCache<double>;
int LongIdx
Define type that represents indices of large arrays (elements, nodes, dofs etc.)
Definition: long_idx.hh:22
unsigned int size() const
get global size
double time_
time step stored in cache
void read_binary_data(std::istream &data_stream, unsigned int n_components, unsigned int i_row) override
Implements ElementDataCacheBase::read_binary_data.
std::shared_ptr< std::vector< T > > ComponentDataPtr
CheckScaleData
Allow to hold sign, if data in cache is checked and scale (both can be executed only once) ...
#define MPI_Datatype
Definition: mpi.h:154
void print_ascii(ostream &out_stream, unsigned int idx) override
string field_value_to_yaml(const T &mat, unsigned int prec)
CheckScaleData check_scale_data_
Sign, if data in cache is checked and scale.
Some value(s) is set to NaN.
unsigned int n_values() const
std::shared_ptr< ElementDataCacheBase > compute_node_data(std::vector< unsigned int > &conn_vec, unsigned int data_size) override
Implements ElementDataCacheBase::compute_node_data.
void store_value(unsigned int idx, const T *value)
#define ASSERT_GT(a, b)
Definition of comparative assert macro (Greater Than)
Definition: asserts.hh:311
#define MPI_Gatherv(sendbuf, sendcount, sendtype, recvbuf, recvcounts, displs, recvtype, root, comm)
Definition: mpi.h:549
T & operator[](unsigned int i)
Access i-th element in the data vector of 0th component.
MPI_Datatype mpi_data_type()
Return MPI data type corresponding with template parameter of cache. Needs template specialization...
void read_ascii_data(Tokenizer &tok, unsigned int n_components, unsigned int i_row) override
Implements ElementDataCacheBase::read_ascii_data.
Some value(s) is out of limits.
static constexpr bool value
Definition: json.hpp:87
ElementDataCache()
Default constructor.
void get_min_max_range(double &min, double &max) override
void add(unsigned int idx, const T *value)
DummyInt isnan(...)
Definition: format.h:306
std::shared_ptr< ElementDataCacheBase > gather(Distribution *distr, LongIdx *local_to_global) override
Implements ElementDataCacheBase::gather.
virtual ~ElementDataCache() override
Destructor of ElementDataCache.
static CacheData create_data_cache(unsigned int size_of_cache, unsigned int row_vec_size)
unsigned int begin(int proc) const
get starting local index
void zero(unsigned int idx)
void scale_data(double coef)
unsigned int np() const
get num of processors
void print_all_yaml(ostream &out_stream, unsigned int precision) override
Data is neither checked nor scaled.
CheckResult
Return type of method that checked data stored in ElementDataCache (NaN values, limits) ...
CheckResult check_values(double default_val, double lower_bound, double upper_bound)
#define MPI_DOUBLE
Definition: mpi.h:156
void normalize(unsigned int idx, unsigned int divisor)
unsigned int myp() const
get my processor
Support classes for parallel programing.
void print_binary_all(ostream &out_stream, bool print_data_size=true) override
Print all data stored in output data to appended binary format.
std::string field_input_name_
name of field stored in cache
std::shared_ptr< ElementDataCacheBase > element_node_cache_fixed_size(std::vector< unsigned int > &offset_vec) override
Implements ElementDataCacheBase::element_node_cache_fixed_size.
#define MPI_INT
Definition: mpi.h:160
#define ASSERT_LT(a, b)
Definition of comparative assert macro (Less Than)
Definition: asserts.hh:295
std::shared_ptr< ElementDataCacheBase > element_node_cache_optimize_size(std::vector< unsigned int > &offset_vec) override
Implements ElementDataCacheBase::element_node_cache_optimize_size.
ComponentDataPtr get_component_data(unsigned int component_idx)
Return vector of element data for get component.
#define ASSERT_DBG(expr)
Definition: asserts.hh:349
#define MPI_COMM_WORLD
Definition: mpi.h:123
void print_ascii_all(ostream &out_stream) override
Print all data stored in output data ro ascii format.
All values are not NaN and are in limits.
#define MPI_UNSIGNED
Definition: mpi.h:165
unsigned int n_comp() const
T check(T value)
Definition: format.h:312
#define ASSERT_EQ(a, b)
Definition of comparative assert macro (EQual)
Definition: asserts.hh:327
#define ASSERT_LT_DBG(a, b)
Definition of comparative assert macro (Less Than) only for debug mode.
Definition: asserts.hh:299
unsigned int lsize(int proc) const
get local size