Flow123d  JS_before_hm-1003-g4e68d2c
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  ASSERT_DBG(idx < vec.size());
95  vec[idx] = boost::lexical_cast<T>(*tok);
96  ++tok;
97  }
98  }
99 }
100 
101 
102 template <typename T>
103 void ElementDataCache<T>::read_binary_data(std::istream &data_stream, unsigned int n_components, unsigned int i_row) {
104  unsigned int idx;
105  for (unsigned int i_vec=0; i_vec<data_.size(); ++i_vec) {
106  idx = i_row * n_components;
107  std::vector<T> &vec = *( data_[i_vec].get() );
108  for (unsigned int i_col=0; i_col < n_components; ++i_col, ++idx) {
109  data_stream.read(reinterpret_cast<char *>(&vec[idx]), sizeof(T));
110  }
111  }
112 }
113 
114 
115 /**
116  * Output data element on given index @p idx. Method for writing data
117  * to output stream.
118  *
119  * \note This method is used only by MSH file format.
120  */
121 template <typename T>
122 void ElementDataCache<T>::print_ascii(ostream &out_stream, unsigned int idx)
123 {
124  ASSERT_LT(idx, this->n_values_).error();
125  std::vector<T> &vec = *( this->data_[0].get() );
126  for(unsigned int i = n_comp_*idx; i < n_comp_*(idx+1); ++i )
127  out_stream << vec[i] << " ";
128 }
129 
130 /**
131  * \brief Print all data stored in output data
132  *
133  * TODO: indicate if the tensor data are output in column-first or raw-first order
134  * and possibly implement transposition. Set such property for individual file formats.
135  * Class OutputData stores always in raw-first order.
136  */
137 template <typename T>
138 void ElementDataCache<T>::print_ascii_all(ostream &out_stream)
139 {
140  std::vector<T> &vec = *( this->data_[0].get() );
141  for(unsigned int idx = 0; idx < this->n_values_; idx++) {
142  for(unsigned int i = n_comp_*idx; i < n_comp_*(idx+1); ++i )
143  out_stream << vec[i] << " ";
144  }
145 }
146 
147 
148 /// Prints the whole data vector into stream.
149 template <typename T>
150 void ElementDataCache<T>::print_binary_all(ostream &out_stream, bool print_data_size)
151 {
152  if (print_data_size) {
153  // write size of data
154  unsigned long long int data_byte_size = this->n_values_ * n_comp_ * sizeof(T);
155  out_stream.write(reinterpret_cast<const char*>(&data_byte_size), sizeof(unsigned long long int));
156  }
157  // write data
158  std::vector<T> &vec = *( this->data_[0].get() );
159  for(unsigned int idx = 0; idx < this->n_values_; idx++) {
160  for(unsigned int i = n_comp_*idx; i < n_comp_*(idx+1); ++i )
161  out_stream.write(reinterpret_cast<const char*>(&(vec[i])), sizeof(T));
162  }
163 }
164 
165 
166 template <typename T>
167 void ElementDataCache<T>::print_yaml_subarray(ostream &out_stream, unsigned int precision, unsigned int begin, unsigned int end)
168 {
169  out_stream << "[ ";
170  std::vector<T> &vec = *( this->data_[0].get() );
171  for(unsigned int idx = begin; idx < end; idx++) {
172  if (idx != begin) out_stream << " , ";
173  unsigned int vec_pos = n_comp_ * idx; // position of element value in data cache
174  switch (this->n_comp_) {
175  case NumCompValueType::N_SCALAR: {
176  out_stream << field_value_to_yaml( vec[vec_pos], precision );
177  break;
178  }
179  case NumCompValueType::N_VECTOR: {
180  typename arma::Col<T>::template fixed<3> vec_val;
181  for (unsigned int i=0; i<3; ++i, ++vec_pos)
182  vec_val(i) = vec[vec_pos];
183  out_stream << field_value_to_yaml( vec_val, precision );
184  break;
185  }
186  case NumCompValueType::N_TENSOR: {
187  typename arma::Mat<T>::template fixed<3,3> mat_val;
188  for (unsigned int i=0; i<3; ++i)
189  for (unsigned int j=0; j<3; ++j, ++vec_pos)
190  mat_val(i,j) = vec[vec_pos];
191  out_stream << field_value_to_yaml( mat_val, precision );
192  break;
193  }
194  }
195  }
196  out_stream << " ]";
197 }
198 
199 
200 template <typename T>
201 void ElementDataCache<T>::get_min_max_range(double &min, double &max)
202 {
203  min = std::numeric_limits<double>::max();
204  max = std::numeric_limits<double>::min();
205  std::vector<T> &vec = *( this->data_[0].get() );
206  for(unsigned int idx = 0; idx < this->n_values_; idx++) {
207  for(unsigned int i = n_comp_*idx; i < n_comp_*(idx+1); ++i ) {
208  if (vec[i] < min) min = vec[i];
209  if (vec[i] > max) max = vec[i];
210  }
211  }
212 }
213 
214 
215 /**
216  * Store data element of given data value under given index.
217  */
218 template <typename T>
219 void ElementDataCache<T>::store_value(unsigned int idx, const T * value) {
220  ASSERT_LT_DBG(idx, this->n_values_)(this->field_name_);
221  std::vector<T> &vec = *( this->data_[0].get() );
222  unsigned int vec_idx = idx*this->n_comp_;
223  for(unsigned int i = 0; i < this->n_comp_; i++, vec_idx++) {
224  vec[vec_idx] = value[i];
225  }
226 }
227 
228 /**
229  * Add value to given index
230  */
231 template <typename T>
232 void ElementDataCache<T>::add(unsigned int idx, const T * value) {
233  ASSERT_LT_DBG(idx, this->n_values_);
234  std::vector<T> &vec = *( this->data_[0].get() );
235  unsigned int vec_idx = idx*this->n_comp_;
236  for(unsigned int i = 0; i < this->n_comp_; i++, vec_idx++) {
237  vec[vec_idx] += value[i];
238  }
239 }
240 
241 /**
242  * Reset values at given index
243  */
244 template <typename T>
245 void ElementDataCache<T>::zero(unsigned int idx) {
246  ASSERT_LT_DBG(idx, this->n_values_);
247  std::vector<T> &vec = *( this->data_[0].get() );
248  unsigned int vec_idx = idx*this->n_comp_;
249  for(unsigned int i = 0; i < this->n_comp_; i++, vec_idx++) {
250  vec[vec_idx] = 0;
251  }
252 }
253 
254 /**
255  * Normalize values at given index
256  */
257 template <typename T>
258 void ElementDataCache<T>::normalize(unsigned int idx, unsigned int divisor) {
259  ASSERT_LT_DBG(idx, this->n_values_);
260  std::vector<T> &vec = *( this->data_[0].get() );
261  unsigned int vec_idx = idx*this->n_comp_;
262  for(unsigned int i = 0; i < this->n_comp_; i++, vec_idx++) {
263  vec[vec_idx] /= divisor;
264  }
265 }
266 
267 template <typename T>
268 CheckResult ElementDataCache<T>::check_values(double default_val, double lower_bound, double upper_bound) {
269  if (check_scale_data_ != CheckScaleData::none) return CheckResult::ok; // method is executed only once
271 
272  bool is_nan = false, out_of_limit = false;
273  for (unsigned int j=0; j<data_.size(); ++j) {
274  std::vector<T> &vec = *( this->data_[j].get() );
275  for(unsigned int i=0; i<vec.size(); ++i) {
276  if ( std::isnan(vec[i]) ) {
277  if ( std::isnan(default_val) ) is_nan = true;
278  else vec[i] = default_val;
279  }
280  if ( (vec[i] < lower_bound) || (vec[i] > upper_bound) ) out_of_limit = true;
281  }
282  }
283 
284  if (is_nan) return CheckResult::not_a_number;
285  else if (out_of_limit) return CheckResult::out_of_limits;
286  else return CheckResult::ok;
287 }
288 
289 template <typename T>
291  if (check_scale_data_ == CheckScaleData::scale) return; // method is executed only once
292  ASSERT_DBG(check_scale_data_ == CheckScaleData::check).warning("Data should be checked before scaling. Rather call 'check_values'!\n");
293 
294  for (unsigned int j=0; j<data_.size(); ++j) {
295  std::vector<T> &vec = *( this->data_[j].get() );
296  for(unsigned int i=0; i<vec.size(); ++i) {
297  vec[i] *= coef;
298  }
299  }
300 
301  check_scale_data_ = CheckScaleData::scale;
302 }
303 
304 
305 template <typename T>
306 std::shared_ptr< ElementDataCacheBase > ElementDataCache<T>::gather(Distribution *distr, LongIdx *local_to_global) {
307  std::shared_ptr< ElementDataCache<T> > gather_cache;
308  int rank = distr->myp();
309  int n_proc = distr->np();
310 
311  unsigned int n_global_data; // global number of data
312  int rec_starts[n_proc]; // displacement of first value that is received from each process
313  int rec_counts[n_proc]; // number of values that are received from each process
314  int *rec_indices_ids = nullptr; // collective values of local to global indexes map of data
315  T *rec_data = nullptr; // collective values of data
316 
317  // collects values of data vectors and local to global indexes map on each process
318  if (rank==0) {
319  for (int i=0; i<n_proc; ++i) {
320  rec_starts[i] = distr->begin(i);
321  rec_counts[i] = distr->lsize(i);
322  }
323  n_global_data = distr->size();
324  rec_indices_ids = new int [ n_global_data ];
325  }
326  MPI_Gatherv( local_to_global, distr->lsize(), MPI_INT, rec_indices_ids, rec_counts, rec_starts, MPI_INT, 0, MPI_COMM_WORLD);
327  if (rank==0) {
328  for (int i=0; i<n_proc; ++i) {
329  rec_starts[i] = this->n_comp()*rec_starts[i];
330  rec_counts[i] = this->n_comp()*rec_counts[i];
331  }
332  rec_data = new T [ this->n_comp() * n_global_data ];
333  }
334  auto &local_cache_vec = *( this->get_component_data(0).get() );
335  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) ;
336 
337  // create and fill serial cache
338  if (rank==0) {
339  gather_cache = std::make_shared<ElementDataCache<T>>(this->field_input_name_, (unsigned int)this->n_comp(), n_global_data);
340  auto &gather_vec = *( gather_cache->get_component_data(0).get() );
341  unsigned int i_global_coord; // counter over serial_mesh->nodes_ cache
342  for (unsigned int i=0; i<n_global_data; ++i) {
343  i_global_coord = this->n_comp() * rec_indices_ids[i];
344  for (unsigned int j=0; j<this->n_comp(); ++j) { //loop over coords
345  ASSERT_LT(i_global_coord+j, gather_vec.size());
346  gather_vec[ i_global_coord+j ] = rec_data[ this->n_comp()*i+j ];
347  }
348  }
349 
350  delete[] rec_indices_ids;
351  delete[] rec_data;
352  }
353 
354  return gather_cache;
355 }
356 
357 
358 template <typename T>
359 std::shared_ptr< ElementDataCacheBase > ElementDataCache<T>::element_node_cache_fixed_size(std::vector<unsigned int> &offset_vec) {
360  unsigned int n_elem = offset_vec.size();
361  std::shared_ptr< ElementDataCache<T> > elem_node_cache = std::make_shared<ElementDataCache<T>>(this->field_input_name_, 4*this->n_comp(), n_elem);
362  auto &data_out_vec = *( elem_node_cache->get_component_data(0).get() );
363  std::fill( data_out_vec.begin(), data_out_vec.end(), (T)0 );
364  auto &data_in_vec = *( this->get_component_data(0).get() );
365 
366  unsigned int i_node, i_old, i_new;
367  for (unsigned int i_el=0, i_conn=0; i_el<offset_vec.size(); i_el++) {
368  for(i_node=4*i_el; i_conn<offset_vec[i_el]; i_conn++, i_node++) {
369  i_old = i_conn*this->n_comp_;
370  i_new = i_node*this->n_comp_;
371  for(unsigned int i = 0; i < this->n_comp_; i++) {
372  ASSERT_LT(i_new+i, data_out_vec.size());
373  ASSERT_LT(i_old+i, data_in_vec.size());
374  data_out_vec[i_new+i] = data_in_vec[i_old+i];
375  }
376  }
377  }
378 
379  return elem_node_cache;
380 }
381 
382 
383 template <typename T>
384 std::shared_ptr< ElementDataCacheBase > ElementDataCache<T>::element_node_cache_optimize_size(std::vector<unsigned int> &offset_vec) {
385  std::shared_ptr< ElementDataCache<T> > elem_node_cache = std::make_shared<ElementDataCache<T>>(this->field_input_name_,
386  this->n_comp()/4, offset_vec[offset_vec.size()-1]);
387  auto &data_out_vec = *( elem_node_cache->get_component_data(0).get() );
388  auto &data_in_vec = *( this->get_component_data(0).get() );
389 
390  unsigned int i_node, i_old, i_new;
391  for (unsigned int i_el=0, i_conn=0; i_el<offset_vec.size(); i_el++) {
392  for(i_node=4*i_el; i_conn<offset_vec[i_el]; i_conn++, i_node++) {
393  i_old = i_node*elem_node_cache->n_comp_;
394  i_new = i_conn*elem_node_cache->n_comp_;
395  for(unsigned int i = 0; i < elem_node_cache->n_comp_; i++) {
396  ASSERT_LT(i_new+i, data_out_vec.size());
397  ASSERT_LT(i_old+i, data_in_vec.size());
398  data_out_vec[i_new+i] = data_in_vec[i_old+i];
399  }
400  }
401  }
402  return elem_node_cache;
403 }
404 
405 
406 template <typename T>
407 std::shared_ptr< ElementDataCacheBase > ElementDataCache<T>::compute_node_data(std::vector<unsigned int> &conn_vec, unsigned int data_size) {
408  ASSERT_EQ(conn_vec.size(), this->n_values());
409  unsigned int idx;
410 
411  // set output data to zero
412  std::shared_ptr< ElementDataCache<T> > node_cache = std::make_shared<ElementDataCache<T>>(this->field_input_name_, this->n_comp(), data_size);
413  std::vector<unsigned int> count(data_size, 0);
414  for (idx=0; idx < node_cache->n_values(); idx++)
415  node_cache->zero(idx);
416 
417  auto &data_in_vec = *( this->get_component_data(0).get() );
418  for (idx=0; idx < conn_vec.size(); idx++) {
419  ASSERT_LT(conn_vec[idx], node_cache->n_values());
420  ASSERT_LT(this->n_comp()*idx, data_in_vec.size());
421  node_cache->add( conn_vec[idx], &(data_in_vec[this->n_comp() * idx]) );
422  count[ conn_vec[idx] ]++;
423  }
424 
425  // Compute mean values at nodes
426  for(idx=0; idx < node_cache->n_values(); idx++)
427  node_cache->normalize(idx, count[idx]);
428 
429  return node_cache;
430 }
431 
432 
433 template<>
435  return MPI_DOUBLE;
436 }
437 
438 template<>
440  return MPI_INT;
441 }
442 
443 template<>
445  return MPI_UNSIGNED;
446 }
447 
448 
449 /// Access i-th element in the data vector.
450 template <class T>
452 {
453  std::vector<T> &vec = *( this->data_[0].get() );
454  ASSERT_DBG(i < vec.size());
455  return vec[i];
456 }
457 
458 
459 
460 // explicit instantiation of template class
461 template class ElementDataCache<unsigned int>;
462 template class ElementDataCache<int>;
463 template class ElementDataCache<double>;
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) ...
ArmaVec< double, N > vec
Definition: armor.hh:861
#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:312
#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)
void print_yaml_subarray(ostream &out_stream, unsigned int precision, unsigned int begin, unsigned int end) override
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
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.
int LongIdx
Define type that represents indices of large arrays (elements, nodes, dofs etc.)
Definition: index_types.hh:24
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:296
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)
#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:328
#define ASSERT_LT_DBG(a, b)
Definition of comparative assert macro (Less Than) only for debug mode.
Definition: asserts.hh:300
unsigned int lsize(int proc) const
get local size