Rheolef  7.2
an efficient C++ finite element environment
disarray_mpi.icc
Go to the documentation of this file.
1 
22 # include "rheolef/config.h"
23 # ifdef _RHEOLEF_HAVE_MPI
24 
25 # include "rheolef/disarray.h"
26 
27 # include "rheolef/mpi_assembly_begin.h"
28 # include "rheolef/mpi_assembly_end.h"
29 # include "rheolef/mpi_scatter_init.h"
30 # include "rheolef/mpi_scatter_begin.h"
31 # include "rheolef/mpi_scatter_end.h"
32 # include "rheolef/load_chunk.h"
33 # include "rheolef/disarray_store.h"
34 # include "rheolef/rheostream.h"
35 
36 namespace rheolef {
37 // ----------------------------------------------------------------------------
38 // allocators
39 // ----------------------------------------------------------------------------
40 template <class T, class A>
42  : base(x),
43  _stash(),
44  _send(),
45  _receive(),
46  _receive_max_size(0),
47  _ext_x(x._ext_x)
48 {
49  assert_macro(x._stash.size() == 0 &&
50  x._send.data.size() == 0 &&
51  x._receive.data.size() == 0,
52  "copy during assembly phase: should not be done");
53 }
54 template <class T, class A>
56  const distributor& ownership,
57  const T& init_val,
58  const A& alloc)
59  : base(ownership, init_val,alloc),
60  _stash(),
61  _send(),
62  _receive(),
63  _receive_max_size(0),
64  _ext_x()
65 {
66 }
67 template <class T, class A>
68 void
70  const distributor& ownership,
71  const T& init_val)
72 {
73  base::resize(ownership, init_val);
74  _stash.clear();
75  _send.waits.clear();
76  _send.data.clear();
77  _receive.waits.clear();
78  _receive.data.clear();
79  _receive_max_size = 0;
80 }
81 // ===============================================================
82 // set_dis_entry aka operator=
83 // ===============================================================
84 namespace details {
85 
86 // insert a "U value" for simple, or variable-sized one, as index_set or pair_set types
87 template <class Map, class SetOp>
88 inline
89 void
90 stash_set (Map& stash, typename Map::size_type dis_i, const typename Map::mapped_type& val, const SetOp& set_op, std::false_type)
91 {
92  using size_type = typename Map::size_type;
93  using T = typename Map::mapped_type;
94  std::pair<typename Map::iterator,bool> status = stash.insert (std::pair<const size_type,T>(dis_i,T()));
95  set_op ((*(status.first)).second, val);
96 }
97 // disarray<std::set<double>> : more complex op= += -=
98 template <class MultiMap, class U>
99 void
100 stash_set (MultiMap& stash, typename MultiMap::size_type dis_i, const U& val, const details::generic_set_op&, std::true_type)
101 {
102  // check if a multi-value for dis_i exists and delete it; then insert the new multi-value
103  using size_type = typename MultiMap::size_type;
104  using W = typename MultiMap::mapped_type;
105  using iterator = typename MultiMap::iterator;
106  std::pair<iterator, iterator> range_dis_i = stash.equal_range (dis_i);
107  stash.erase (range_dis_i.first, range_dis_i.second); // TODO: SetOp=generic_set_op ==> extend to others set_op
108  for (typename U::const_iterator iter = val.begin(), last = val.end(); iter != last; iter++) {
109  stash.insert (std::pair<const size_type,W>(dis_i,*iter));
110  }
111 }
112 // insert a "U value" in multi-map when U has fixed size
113 template <class MultiMap, class U>
114 inline
115 void
116 stash_set_plus_multi (MultiMap& stash, typename MultiMap::size_type dis_i, const U& val, const details::generic_set_plus_op& set_op, std::false_type)
117 {
118  typedef typename MultiMap::size_type size_type;
119  typedef typename MultiMap::mapped_type W;
120  stash.insert (std::pair<const size_type,W>(dis_i,val)); // TODO: SetOp=details::generic_set_plus_op --> more general
121 }
122 // insert a "U value" in multi-map when U has variable size
123 template <class MultiMap, class U>
124 void
125 stash_set_plus_multi (MultiMap& stash, typename MultiMap::size_type dis_i, const U& val, const details::generic_set_plus_op& set_op, std::true_type)
126 {
127  typedef typename MultiMap::size_type size_type;
128  typedef typename MultiMap::mapped_type W;
129  for (typename U::const_iterator iter = val.begin(), last = val.end(); iter != last; iter++) {
130  stash.insert (std::pair<const size_type,W>(dis_i,*iter)); // TODO: SetOp=details::generic_set_plus_op --> more general
131  }
132 }
133 template <class MultiMap, class U>
134 inline
135 void
136 stash_set (MultiMap& stash, typename MultiMap::size_type dis_i, const U& val, const details::generic_set_plus_op& set_op, std::true_type)
137 {
138  stash_set_plus_multi (stash, dis_i, val, set_op, typename details::is_container<U>::type());
139 }
140 
141 } // namespace details
142 
143 // set_dis_entry aka =
144 template <class T, class A>
145 template<class U, class SetOp>
146 void
147 disarray_rep<T,distributed,A>::set_dis_entry (size_type dis_i, const U& value, const SetOp& set_op)
148 {
149  size_type first_i = ownership().first_index();
150  size_type last_i = ownership().last_index();
151  if (dis_i >= first_i && dis_i < last_i) {
152  trace_macro ("set_dis_entry: local ["<<dis_i - first_i<<"] op= " << value<<" with op="<<typename_macro(SetOp));
153  set_op (disarray_rep<T,distributed,A>::operator[] (dis_i - first_i),
154  value);
155  } else {
156  trace_macro ("set_dis_entry: non-local");
157  assert_macro (dis_i < ownership().dis_size(),
158  "index "<<dis_i << " is out of range [0:" << ownership().dis_size() << "[");
159  details::stash_set (_stash, dis_i, value, set_op, is_container());
160  // value will be immediadly available via x.dis_at(dis_i)
161  // => update _ext_x when dis_i is present
162  typename scatter_map_type::iterator iter = _ext_x.find (dis_i);
163  if (iter != _ext_x.end()) {
164  set_op ((*iter).second, value);
165  }
166  }
167 }
168 #ifdef TO_CLEAN
169 // set_plus_dis_entry aka +=
170 template <class T, class A>
171 template<class U, class SetOp>
172 void
173 disarray_rep<T,distributed,A>::set_plus_dis_entry (size_type dis_i, const U& value, const SetOp& set_op)
174 {
175  size_type start = ownership().first_index();
176  size_type last = ownership().last_index();
177  if (dis_i >= start && dis_i < last) {
178  set_op (base::operator[](dis_i - start), value);
179  } else {
180  assert_macro (dis_i < ownership().dis_size(),
181  "index "<<dis_i<<" is out of range [0:"<<ownership().dis_size() << "[");
182  details::stash_set (_stash, dis_i, value, set_op, is_container());
183  // value will be immediadly available via x.dis_at(dis_i)
184  // => update _ext_x when dis_i is present
185  typename scatter_map_type::iterator iter = _ext_x.find (dis_i);
186  if (iter != _ext_x.end()) {
187  set_op ((*iter).second, value);
188  }
189  }
190 }
191 // set_minus_dis_entry aka -=
192 template <class T, class A>
193 template<class U, class SetOp>
194 void
195 disarray_rep<T,distributed,A>::set_minus_dis_entry (size_type dis_i, const U& value, const SetOp& set_op)
196 {
197  size_type start = ownership().first_index();
198  size_type last = ownership().last_index();
199  if (dis_i >= start && dis_i < last) {
200  set_op (base::operator[](dis_i - start), value);
201  } else {
202  assert_macro (dis_i < ownership().dis_size(),
203  "index "<<dis_i<<" is out of range [0:"<<ownership().dis_size() << "[");
204  details::stash_set_minus (_stash, dis_i, value, set_op, is_container());
205  // value will be immediadly available via x.dis_at(dis_i)
206  // => update _ext_x when dis_i is present
207  typename scatter_map_type::iterator iter = _ext_x.find (dis_i);
208  if (iter != _ext_x.end()) {
209  set_op ((*iter).second, value);
210  }
211  }
212 }
213 #endif // TO_CLEAN
214 // ===============================================================
215 // assembly
216 // ===============================================================
217 template <class T, class A>
218 template <class SetOp>
219 void
221 {
222  _receive_max_size = mpi_assembly_begin (
223  _stash,
226  ownership(),
227  _receive,
228  _send);
229 
230  _stash.clear();
231 }
232 template <class T, class A>
233 template <class SetOp>
234 void
236 {
238  _receive,
239  _send,
240  _receive_max_size,
242  begin() - ownership().first_index(),
243  my_set_op,
244  size_type(0),
245  is_container()));
246 
247  _send.waits.clear();
248  _send.data.clear();
249  _receive.waits.clear();
250  _receive.data.clear();
251  _receive_max_size = 0;
252 }
253 // ===============================================================
254 // repartition
255 // ===============================================================
256 template <class T, class A>
257 template <class A2>
258 void
259 disarray_rep<T,distributed,A>::repartition ( // old_numbering for *this
260  const disarray_rep<size_type,distributed,A2>& partition, // old_ownership
261  disarray_rep<T,distributed,A>& new_disarray, // new_ownership
262  disarray_rep<size_type,distributed,A2>& old_numbering, // new_ownership
263  disarray_rep<size_type,distributed,A2>& new_numbering) const // old_ownership
264 {
265  using namespace std;
266  communicator_type comm = ownership().comm();
267  size_type nproc = comm.size();
268  size_type my_proc = comm.rank();
269  vector<size_type> send_local_elt_size (nproc, 0);
270  typename disarray_rep<size_type,distributed,A2>::const_iterator iter_part = partition.begin();
271  for (size_type ie = 0; ie < partition.size(); ie++, iter_part++) {
272  send_local_elt_size [*iter_part]++;
273  }
274  vector<size_type> recv_local_elt_size (nproc, 0);
275  all_to_all (comm, send_local_elt_size, recv_local_elt_size);
276  vector<size_type> recv_local_elt_start (nproc+1);
277  recv_local_elt_start [0] = 0;
278  for (size_type iproc = 0; iproc < nproc; iproc++) {
279  recv_local_elt_start [iproc+1] = recv_local_elt_start [iproc] + recv_local_elt_size[iproc];
280  }
281  vector<size_type> send_local_elt_start (nproc);
282  all_to_all (comm, recv_local_elt_start.begin().operator->(), send_local_elt_start.begin().operator->());
283  size_type new_local_n_elt = recv_local_elt_start [nproc];
284  size_type global_n_elt = dis_size();
285 
286  // re-distribute data:
287  distributor new_elt_ownership (global_n_elt, comm, new_local_n_elt);
288  new_disarray.resize (new_elt_ownership);
289  old_numbering.resize (new_elt_ownership, numeric_limits<size_type>::max());
290  new_numbering.resize (ownership(), numeric_limits<size_type>::max());
291  iter_part = partition.begin();
292  const_iterator iter_elt = begin();
293  typename disarray_rep<size_type,distributed,A2>::iterator iter_new_num_elt = new_numbering.begin();
294  for (size_type ie = 0, ne = partition.size(); ie < ne; ie++, iter_part++, iter_elt++, iter_new_num_elt++) {
295  size_type iproc = *iter_part;
296  const T& x = *iter_elt;
297  size_type new_global_ie = new_elt_ownership[iproc] + send_local_elt_start[iproc];
298  new_disarray.dis_entry (new_global_ie) = x;
299  *iter_new_num_elt = new_global_ie;
300  size_type old_global_ie = ownership()[my_proc] + ie;
301  old_numbering.dis_entry (new_global_ie) = old_global_ie;
302  send_local_elt_start[iproc]++;
303  }
304  new_disarray.template dis_entry_assembly<typename details::default_set_op_traits<T>::type>();
305  old_numbering.template dis_entry_assembly<typename details::default_set_op_traits<size_type>::type>();
306 }
307 template <class T, class A>
308 template <class A2>
309 void
310 disarray_rep<T,distributed,A>::reverse_permutation ( // old_ownership for *this=iold2dis_inew
311  disarray_rep<size_type,distributed,A2>& inew2dis_iold) const // new_ownership
312 {
313  check_macro (inew2dis_iold.dis_size() == dis_size(), "reverse permutation[0:"<<inew2dis_iold.dis_size()
314  <<"[ has incompatible dis_range with oriinal permutation[0:"<<dis_size()<<"[");
315  size_type first_dis_iold = ownership().first_index();
316  for (size_type iold = 0; iold < size(); iold++) {
317  size_type dis_iold = first_dis_iold + iold;
318  size_type dis_inew = base::operator[] (iold);
319  inew2dis_iold.dis_entry (dis_inew) = dis_iold;
320  }
321  inew2dis_iold.template dis_entry_assembly<typename details::default_set_op_traits<T>::type>();
322 }
323 template <class T, class A>
324 template <class A2>
325 void
327  const disarray_rep<size_type,distributed,A2>& new_numbering, // old_ownership
328  disarray_rep<T,distributed,A>& new_disarray) const // new_ownership
329 {
330  check_macro (size() == new_numbering.size(),
331  "permutation_apply: incompatible disarray("<<size()<<") and permutation("<<new_numbering.size()<<") sizes");
332  check_macro (dis_size() == new_disarray.dis_size(),
333  "permutation_apply: incompatible disarray("<<dis_size()<<") and permutation("<<new_disarray.dis_size()<<") dis_sizes");
334  typename disarray_rep<size_type,distributed,A2>::const_iterator iter_dis_new_ie = new_numbering.begin();
335  for (const_iterator iter = begin(), last = end(); iter != last; iter++, iter_dis_new_ie++) {
336  size_type dis_new_ie = *iter_dis_new_ie;
337  new_disarray.dis_entry (dis_new_ie) = *iter;
338  }
339  new_disarray.template dis_entry_assembly<typename details::default_set_op_traits<T>::type>();
340 }
342 template <class T, class A>
343 template <class Set, class Map>
344 void
345 disarray_rep<T,distributed,A>::append_dis_entry (const Set& ext_idx_set, Map& ext_idx_map, std::false_type) const
346 {
347  // 0) declare the local context
350 
351  // 1) convert set to vector, for direct acess:
352  std::vector<size_type> ext_idx (ext_idx_set.size());
353  std::copy (ext_idx_set.begin(), ext_idx_set.end(), ext_idx.begin());
354 
355  // 2) declare id[i]=i for scatter
356  std::vector<size_type> id (ext_idx.size());
357  for (size_type i = 0; i < id.size(); i++) id[i] = i;
358 
359  // 3) init scatter
362  ext_idx.size(),
363  ext_idx.begin().operator->(),
364  id.size(),
365  id.begin().operator->(),
366  ownership().dis_size(),
367  ownership().begin().operator->(),
368  tag_init,
369  ownership().comm(),
370  from,
371  to);
372 
373  // 4) begin scatter: send local data to others and get ask for missing data
374  std::vector<T,A> buffer (ext_idx.size());
377  begin().operator->(),
378  buffer.begin().operator->(),
379  from,
380  to,
381  details::generic_set_op(),
382  tag,
383  ownership().comm());
384 
385  // 5) end scatter: receive missing data
387  begin().operator->(),
388  buffer.begin(),
389  from,
390  to,
391  details::generic_set_op(),
392  tag,
393  ownership().comm());
394 
395  // 6) build the associative container: pair (ext_idx ; data)
396  for (size_type i = 0; i < buffer.size(); i++) {
397  ext_idx_map.insert (std::make_pair (ext_idx[i], buffer[i]));
398  }
399 }
400 template <class T, class A>
401 void
403 {
404  std::set<size_type> ext_idx_set;
405  for (typename scatter_map_type::const_iterator iter = _ext_x.begin(), last = _ext_x.end(); iter != last; iter++) {
406  ext_idx_set.insert ((*iter).first);
407  }
408  set_dis_indexes (ext_idx_set);
409 }
411 template <class T, class A>
412 template <class Set, class Map>
413 void
414 disarray_rep<T,distributed,A>::append_dis_entry (const Set& ext_idx_set, Map& ext_idx_map, std::true_type) const
415 {
416  typedef typename T::value_type S; // S is supposed to be MPI-simple, i.e. with fixed size
417 
418  // 0) declare the local context
419  typedef scatter_message<std::vector<T>, true> message_type; // TODO: vector<T,A> for heap_alloc
420 
421  message_type from;
422  message_type to;
423 
424  // 1) convert set to vector, for direct acess:
425  std::vector<size_type> ext_idx (ext_idx_set.size());
426  std::copy (ext_idx_set.begin(), ext_idx_set.end(), ext_idx.begin());
427 
428  // 2) declare id[i]=i for scatter
429  std::vector<size_type> id (ext_idx.size());
430  for (size_type i = 0; i < id.size(); i++) id[i] = i;
431 
432  // 3) init scatter
435  ext_idx.size(),
436  ext_idx.begin().operator->(),
437  id.size(),
438  id.begin().operator->(),
439  ownership().dis_size(),
440  ownership().begin().operator->(),
441  tag_init,
442  ownership().comm(),
443  from.get_base(),
444  to.get_base());
445 
446  // 4) copy size of multi-valued objects into a tmp
447  std::vector<size_type> data_sizes (size());
448  for (size_type i = 0, n = size(); i < n; i++) {
449  data_sizes[i] = base::operator[](i).size();
450  }
451  // 5) begin scatter: send local data to others and get ask for missing data
452  std::vector<size_type> buffer (ext_idx.size());
455  data_sizes.begin().operator->(),
456  buffer.begin().operator->(),
457  from.get_base(),
458  to.get_base(),
459  details::generic_set_op(),
460  tag,
461  ownership().comm());
462 
463  // 6) end scatter: receive missing data
465  data_sizes.begin().operator->(),
466  buffer.begin(),
467  from.get_base(),
468  to.get_base(),
469  details::generic_set_op(),
470  tag,
471  ownership().comm());
472 
473  // 7) initialize multi-valued scatter
474  from.multi_init();
475  to.multi_init();
476 
477  // 8) begin multi-valued scatter
478  std::vector<T> multi_buffer (ext_idx.size()); // TODO: vector<T,A> for heap_alloc
481  begin().operator->(),
482  multi_buffer.begin().operator->(),
483  from,
484  to,
485  details::generic_set_op(),
486  multi_tag,
487  ownership().comm());
488 
489  // 9) end scatter: receive missing data
491  begin().operator->(),
492  multi_buffer.begin(),
493  from,
494  to,
495  details::generic_set_op(),
496  multi_tag,
497  ownership().comm());
498 
499  // 10) build the associative container: pair (ext_idx ; data)
500  for (size_type i = 0; i < multi_buffer.size(); i++) {
501  ext_idx_map.insert (std::make_pair (ext_idx[i], multi_buffer[i]));
502  }
503 }
505 template <class T, class A>
506 template <class Set, class Map>
507 inline
508 void
509 disarray_rep<T,distributed,A>::append_dis_entry (const Set& ext_idx_set, Map& ext_idx_map) const
510 {
511  append_dis_entry (ext_idx_set, ext_idx_map, is_container());
512 }
513 template <class T, class A>
516 {
517  if (dis_i >= ownership().first_index() && dis_i < ownership().last_index()) {
518  size_type i = dis_i - ownership().first_index();
519  return base::operator[](i);
520  }
521  typename scatter_map_type::const_iterator iter = _ext_x.find (dis_i);
522  check_macro (iter != _ext_x.end(), "unexpected external index="<<dis_i);
523  return (*iter).second;
524 }
525 template <class T, class A>
526 void
527 disarray_rep<T,distributed,A>::get_dis_indexes (std::set<size_type>& ext_idx_set) const
528 {
529  ext_idx_set.clear();
530  for (auto x: _ext_x) {
531  ext_idx_set.insert (x.first);
532  }
533 }
534 // ===============================================================
535 // put & get
536 // ===============================================================
537 template <class T, class A>
538 template <class PutFunction>
540 disarray_rep<T,distributed,A>::put_values (odiststream& ops, PutFunction put_element) const
541 {
543  std::ostream& s = ops.os();
544 
545  // determine maximum message to arrive
546  size_type max_size = 0;
547  mpi::reduce(comm(), size(), max_size, mpi::maximum<size_type>(), 0);
548 
549  size_type io_proc = odiststream::io_proc();
550  if (ownership().process() == io_proc) {
551  for (size_type i = 0; i < size(); i++) {
552  put_element (s, base::operator[](i));
553  s << std::endl;
554  }
555  // receive and print messages
556  std::vector<T,A> values (max_size);
557  for (size_type iproc = 0; iproc < ownership().n_process(); iproc++) {
558  if (iproc == io_proc) continue;
559  size_type loc_sz_i = ownership().size(iproc);
560  if (loc_sz_i == 0) continue;
561  mpi::status status = comm().recv(iproc, tag, values.begin().operator->(), max_size);
562  boost::optional<int> n_data_opt = status.count<T>();
563  check_macro (n_data_opt, "receive failed");
564  size_type n_data = n_data_opt.get();
565  for (size_type i = 0; i < n_data; i++) {
566  put_element (s, values[i]);
567  s << std::endl;
568  }
569  }
570  s << std::flush;
571  } else {
572  if (size() != 0) {
573  comm().send(io_proc, tag, begin().operator->(), size());
574  }
575  }
576  return ops;
577 }
578 template <class T, class A>
581 {
582  return put_values (ops, _disarray_put_element_type<T>());
583 }
584 template <class T, class A>
587 {
588  ops << "[";
589  put_values (ops, _disarray_put_matlab_type<T>());
590  return ops << "];";
591 }
592 template <class T, class A>
593 template <class PutFunction, class A2>
596  odiststream& ops,
598  PutFunction put_element) const
599 {
600  assert_macro (perm.size() == size(), "permutation size does not match");
601  size_type io_proc = odiststream::io_proc();
602  size_type my_proc = comm().rank();
603  distributor io_ownership (dis_size(), comm(), (my_proc == io_proc) ? dis_size() : 0);
604  disarray_rep<T,distributed,A> perm_x (io_ownership);
605  for (size_type i = 0, n = size(); i < n; i++) {
606  perm_x.dis_entry (perm[i]) = base::operator[](i);
607  }
608  perm_x.template dis_entry_assembly_begin<typename details::default_set_op_traits<T>::type>();
609  perm_x.template dis_entry_assembly_end <typename details::default_set_op_traits<T>::type>();
610  return perm_x.base::put_values (ops, put_element);
611 }
612 template <class T, class A>
613 template <class GetFunction>
617  std::istream& s = ps.is();
618  size_type io_proc = odiststream::io_proc();
619  if (ownership().process() == io_proc) {
620  // load first chunk associated to proc 0
621  if (!load_chunk (s, begin(), end(), get_element))
622  error_macro("read failed on input stream.");
623 
624  if (ownership().n_process() > 1) {
625  // read in other chuncks and send to other processors
626  // determine maximum chunck owned by other
627  size_type size_max = 1;
628  for (size_type iproc = 0; iproc < ownership().n_process(); iproc++) {
629  size_max = std::max (size_max, ownership().size(iproc));
630  }
631  std::vector<T,A> data_proc_j (size_max);
632  T *start_j = data_proc_j.begin().operator->();
633  // bizarre qu'on lise ts les blocs dans la meme zone de memoire
634  // et qu'on attende pas que ce soit envoye pour ecraser par le suivant ?
635  for (size_type jproc = 0; jproc < ownership().n_process(); jproc++) {
636  if (jproc == io_proc) continue;
637  // load first chunk associated to proc j
638  size_type loc_sz_j = ownership().size(jproc);
639  if (loc_sz_j == 0) continue;
640  T *last_j = start_j + loc_sz_j;
641  if (!load_chunk (s, start_j, last_j, get_element))
642  error_macro("read failed on input stream.");
643  comm().send (jproc, tag, start_j, loc_sz_j);
644  }
645  }
646  } else {
647  if (size() != 0) {
648  comm().recv(io_proc, tag, begin().operator->(), size());
649  }
650  }
651  return ps;
652 }
653 template <class T, class A>
656 {
657  return get_values (ips, _disarray_get_element_type<T>());
658 }
659 template <class T, class A>
660 void
662 {
663  base::dump (name + std::to_string(comm().rank()));
664 }
665 
666 } // namespace rheolef
667 # endif // _RHEOLEF_HAVE_MPI
field::size_type size_type
Definition: branch.cc:430
dis_reference dis_entry(size_type dis_i)
Definition: disarray.h:327
details::is_container_of_mpi_datatype< T >::type is_container
Definition: disarray.h:416
typename base::size_type size_type
Definition: disarray.h:296
distributor::communicator_type communicator_type
Definition: disarray.h:229
see the distributor page for the full documentation
Definition: distributor.h:69
static tag_type get_new_tag()
returns a new tag
Definition: distributor.cc:133
idiststream: see the diststream page for the full documentation
Definition: diststream.h:336
std::istream & is()
Definition: diststream.h:400
odiststream: see the diststream page for the full documentation
Definition: diststream.h:137
std::ostream & os()
Definition: diststream.h:247
static size_type io_proc()
Definition: diststream.cc:79
size_t size_type
Definition: basis_get.cc:76
rheolef::std value
#define trace_macro(message)
Definition: dis_macros.h:111
#define assert_macro(ok_condition, message)
Definition: dis_macros.h:113
#define error_macro(message)
Definition: dis_macros.h:49
Expr1::float_type T
Definition: field_expr.h:230
check_macro(expr1.have_homogeneous_space(Xh1), "dual(expr1,expr2); expr1 should have homogeneous space. HINT: use dual(interpolate(Xh, expr1),expr2)")
verbose clean transpose logscale grid shrink ball stereo iso volume skipvtk deformation fastfieldload lattice reader_on_stdin color format format format format format format format format format format format format format format format format format format dump
void stash_set_plus_multi(MultiMap &stash, typename MultiMap::size_type dis_i, const U &val, const details::generic_set_plus_op &set_op, std::false_type)
void stash_set(Map &stash, typename Map::size_type dis_i, const typename Map::mapped_type &val, const SetOp &set_op, std::false_type)
This file is part of Rheolef.
apply_iterator< Iterator, Operator > make_apply_iterator(Iterator i, Operator op)
Definition: msg_util.h:114
Size mpi_assembly_end(Message &receive, Message &send, Size receive_max_size, Container x)
Stash::size_type mpi_assembly_begin(const Stash &stash, InputIterator first_stash_idx, InputIterator last_stash_idx, const distributor &ownership, Message &receive, Message &send)
void mpi_scatter_init(Size nidx, SizeRandomIterator1 idx, Size nidy, SizeRandomIterator2 idy, Size idy_maxval, SizeRandomIterator3 ownership, Tag tag, const distributor::communicator_type &comm, Message &from, Message &to)
disarray_store< OutputRandomIterator, SetOp, Size, IsContainer > disarray_make_store(OutputRandomIterator x, SetOp op, Size, IsContainer)
void mpi_scatter_end(InputIterator x, OutputIterator y, Message &from, Message &to, SetOp op, Tag tag, Comm comm)
bool load_chunk(std::istream &s, RandomIterator iter, RandomIterator last)
Definition: load_chunk.h:27
void mpi_scatter_begin(InputIterator x, OutputIterator y, Message &from, Message &to, SetOp op, Tag tag, Comm comm)
disarray element input helper
Definition: disarray.h:205
disarray element output helper
Definition: disarray.h:196