Rheolef  7.1
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 and assembly
83 // ===============================================================
84 #ifdef TO_CLEAN
85 template <class Map>
86 inline
87 typename Map::mapped_type&
88 _stash_create_new_entry (Map& stash, typename Map::size_type dis_i, std::false_type)
89 {
90  typedef typename Map::size_type size_type;
91  typedef typename Map::mapped_type T;
92  std::pair<typename Map::iterator,bool> status
93  = stash.insert (std::pair<const size_type,T>(dis_i,T()));
94  return (*(status.first)).second;
95 };
96 template <class MultiMap>
97 inline
98 typename MultiMap::mapped_type&
99 _stash_create_new_entry (MultiMap& stash, typename MultiMap::size_type dis_i, std::true_type)
100 {
101  typedef typename MultiMap::size_type size_type;
102  typedef typename MultiMap::mapped_type U;
103  std::pair<typename MultiMap::iterator,bool> status
104  = stash.insert (std::pair<const size_type,U>(dis_i,U()));
105  return (*(status.first)).second;
106 };
107 template <class T, class A>
109 disarray_rep<T,distributed,A>::new_dis_entry (size_type dis_i)
110 {
111  size_type first_dis_i = ownership().first_index();
112  size_type last_dis_i = ownership().last_index();
113  if (dis_i >= first_dis_i && dis_i < last_dis_i) {
114  return disarray_rep<T,distributed,A>::operator[](dis_i - first_dis_i);
115  } else {
116  assert_macro (dis_i < ownership().dis_size(), "index "<<dis_i
117  << " is out of range [0:" << ownership().dis_size() << "[");
118  return _stash_create_new_entry (_stash, dis_i, is_container());
119  }
120 }
121 #endif // TO_CLEAN
122 template <class Map>
123 inline
124 void
125 _stash_set (Map& stash, typename Map::size_type dis_i, const typename Map::mapped_type& val, std::false_type)
126 {
127  typedef typename Map::size_type size_type;
128  typedef typename Map::mapped_type T;
129  std::pair<typename Map::iterator,bool> status
130  = stash.insert (std::pair<const size_type,T>(dis_i,T()));
131  (*(status.first)).second = val;
132 };
133 template <class Map>
134 inline
135 void
136 _stash_set_add (Map& stash, typename Map::size_type dis_i, const typename Map::mapped_type& val, std::false_type)
137 {
138  typedef typename Map::size_type size_type;
139  typedef typename Map::mapped_type T;
140  std::pair<typename Map::iterator,bool> status
141  = stash.insert (std::pair<const size_type,T>(dis_i,T()));
142  (*(status.first)).second += val;
143 };
144 template <class MultiMap, class T>
145 inline
146 void
147 _stash_set (MultiMap& stash, typename MultiMap::size_type dis_i, const T& val, std::true_type)
148 {
149  // check if a multi-value for dis_i exists and delete it; then insert the new multi-value
150  typedef typename MultiMap::iterator iterator;
151  typedef typename MultiMap::size_type size_type;
152  typedef typename MultiMap::mapped_type U;
153  std::pair<iterator, iterator> range_dis_i = stash.equal_range (dis_i);
154  stash.erase (range_dis_i.first, range_dis_i.second);
155  for (typename T::const_iterator iter = val.begin(), last = val.end(); iter != last; iter++) {
156  stash.insert (std::pair<const size_type,U>(dis_i,*iter));
157  }
158 };
159 // insert a "T value" in multi-map when T has fixed size
160 template <class MultiMap, class U>
161 inline
162 void
163 _stash_set_add_multi (MultiMap& stash, typename MultiMap::size_type dis_i, const U& val, std::false_type)
164 {
165  typedef typename MultiMap::size_type size_type;
166  typedef typename MultiMap::mapped_type W;
167  stash.insert (std::pair<const size_type,W>(dis_i,val));
168 }
169 // insert a "T value" in multi-map when T has variable size
170 template <class MultiMap, class U>
171 inline
172 void
173 _stash_set_add_multi (MultiMap& stash, typename MultiMap::size_type dis_i, const U& val, std::true_type)
174 {
175  typedef typename MultiMap::size_type size_type;
176  typedef typename MultiMap::mapped_type W;
177  for (typename U::const_iterator iter = val.begin(), last = val.end(); iter != last; iter++) {
178  stash.insert (std::pair<const size_type,W>(dis_i,*iter));
179  }
180 }
181 // insert a "U value" for simple, or variable-sized one, as index_set or pair_set types
182 template <class MultiMap, class U>
183 inline
184 void
185 _stash_set_add (MultiMap& stash, typename MultiMap::size_type dis_i, const U& val, std::true_type)
186 {
187  _stash_set_add_multi (stash, dis_i, val, typename is_container<U>::type());
188 }
189 template <class T, class A>
190 void
192 {
193  size_type start = ownership().first_index();
194  size_type last = ownership().last_index();
195  if (dis_i >= start && dis_i < last) {
197  } else {
198  assert_macro (dis_i < ownership().dis_size(), "index "<<dis_i
199  << " is out of range [0:" << ownership().dis_size() << "[");
200  _stash_set (_stash, dis_i, value, is_container());
201  }
202 }
203 template <class T, class A>
204 template <class U>
205 void
207 {
208  size_type start = ownership().first_index();
209  size_type last = ownership().last_index();
210  if (dis_i >= start && dis_i < last) {
211  base::operator[](dis_i - start) += val;
212  } else {
213  assert_macro (dis_i < ownership().dis_size(),
214  "index "<<dis_i<<" is out of range [0:"<<ownership().dis_size());
215  _stash_set_add (_stash, dis_i, val, is_container());
216  }
217 }
218 template <class T, class A>
219 template <class SetOp>
220 void
222 {
223  _receive_max_size = mpi_assembly_begin (
224  _stash,
227  ownership(),
228  _receive,
229  _send);
230 
231  _stash.clear();
232 }
233 template <class T, class A>
234 template <class SetOp>
235 void
237 {
239  _receive,
240  _send,
241  _receive_max_size,
243  begin() - ownership().first_index(),
244  my_set_op,
245  size_type(0),
246  is_container()));
247 
248  _send.waits.clear();
249  _send.data.clear();
250  _receive.waits.clear();
251  _receive.data.clear();
252  _receive_max_size = 0;
253 }
254 // ===============================================================
255 // repartition
256 // ===============================================================
257 template <class T, class A>
258 template <class A2>
259 void
260 disarray_rep<T,distributed,A>::repartition ( // old_numbering for *this
261  const disarray_rep<size_type,distributed,A2>& partition, // old_ownership
262  disarray_rep<T,distributed,A>& new_disarray, // new_ownership
263  disarray_rep<size_type,distributed,A2>& old_numbering, // new_ownership
264  disarray_rep<size_type,distributed,A2>& new_numbering) const // old_ownership
265 {
266  using namespace std;
267  communicator_type comm = ownership().comm();
268  size_type nproc = comm.size();
269  size_type my_proc = comm.rank();
270  vector<size_type> send_local_elt_size (nproc, 0);
271  typename disarray_rep<size_type,distributed,A2>::const_iterator iter_part = partition.begin();
272  for (size_type ie = 0; ie < partition.size(); ie++, iter_part++) {
273  send_local_elt_size [*iter_part]++;
274  }
275  vector<size_type> recv_local_elt_size (nproc, 0);
276  all_to_all (comm, send_local_elt_size, recv_local_elt_size);
277  vector<size_type> recv_local_elt_start (nproc+1);
278  recv_local_elt_start [0] = 0;
279  for (size_type iproc = 0; iproc < nproc; iproc++) {
280  recv_local_elt_start [iproc+1] = recv_local_elt_start [iproc] + recv_local_elt_size[iproc];
281  }
282  vector<size_type> send_local_elt_start (nproc);
283  all_to_all (comm, recv_local_elt_start.begin().operator->(), send_local_elt_start.begin().operator->());
284  size_type new_local_n_elt = recv_local_elt_start [nproc];
285  size_type global_n_elt = dis_size();
286 
287  // re-distribute data:
288  distributor new_elt_ownership (global_n_elt, comm, new_local_n_elt);
289  new_disarray.resize (new_elt_ownership);
290  old_numbering.resize (new_elt_ownership, numeric_limits<size_type>::max());
291  new_numbering.resize (ownership(), numeric_limits<size_type>::max());
292  iter_part = partition.begin();
293  const_iterator iter_elt = begin();
294  typename disarray_rep<size_type,distributed,A2>::iterator iter_new_num_elt = new_numbering.begin();
295  for (size_type ie = 0, ne = partition.size(); ie < ne; ie++, iter_part++, iter_elt++, iter_new_num_elt++) {
296  size_type iproc = *iter_part;
297  const T& x = *iter_elt;
298  size_type new_global_ie = new_elt_ownership[iproc] + send_local_elt_start[iproc];
299  new_disarray.dis_entry (new_global_ie) = x;
300  *iter_new_num_elt = new_global_ie;
301  size_type old_global_ie = ownership()[my_proc] + ie;
302  old_numbering.dis_entry (new_global_ie) = old_global_ie;
303  send_local_elt_start[iproc]++;
304  }
305  new_disarray.template dis_entry_assembly<typename default_set_op<T>::type>();
306  old_numbering.template dis_entry_assembly<typename default_set_op<size_type>::type>();
307 }
308 template <class T, class A>
309 template <class A2>
310 void
311 disarray_rep<T,distributed,A>::reverse_permutation ( // old_ownership for *this=iold2dis_inew
312  disarray_rep<size_type,distributed,A2>& inew2dis_iold) const // new_ownership
313 {
314  check_macro (inew2dis_iold.dis_size() == dis_size(), "reverse permutation[0:"<<inew2dis_iold.dis_size()
315  <<"[ has incompatible dis_range with oriinal permutation[0:"<<dis_size()<<"[");
316  size_type first_dis_iold = ownership().first_index();
317  for (size_type iold = 0; iold < size(); iold++) {
318  size_type dis_iold = first_dis_iold + iold;
319  size_type dis_inew = base::operator[] (iold);
320  inew2dis_iold.dis_entry (dis_inew) = dis_iold;
321  }
322  inew2dis_iold.template dis_entry_assembly<typename default_set_op<T>::type>();
323 }
324 template <class T, class A>
325 template <class A2>
326 void
328  const disarray_rep<size_type,distributed,A2>& new_numbering, // old_ownership
329  disarray_rep<T,distributed,A>& new_disarray) const // new_ownership
330 {
331  check_macro (size() == new_numbering.size(),
332  "permutation_apply: incompatible disarray("<<size()<<") and permutation("<<new_numbering.size()<<") sizes");
333  check_macro (dis_size() == new_disarray.dis_size(),
334  "permutation_apply: incompatible disarray("<<dis_size()<<") and permutation("<<new_disarray.dis_size()<<") dis_sizes");
335  typename disarray_rep<size_type,distributed,A2>::const_iterator iter_dis_new_ie = new_numbering.begin();
336  for (const_iterator iter = begin(), last = end(); iter != last; iter++, iter_dis_new_ie++) {
337  size_type dis_new_ie = *iter_dis_new_ie;
338  new_disarray.dis_entry (dis_new_ie) = *iter;
339  }
340  new_disarray.template dis_entry_assembly<typename default_set_op<T>::type>();
341 }
343 template <class T, class A>
344 template <class Set, class Map>
345 void
346 disarray_rep<T,distributed,A>::append_dis_entry (const Set& ext_idx_set, Map& ext_idx_map, std::false_type) const
347 {
348  // 0) declare the local context
351 
352  // 1) convert set to vector, for direct acess:
353  std::vector<size_type> ext_idx (ext_idx_set.size());
354  std::copy (ext_idx_set.begin(), ext_idx_set.end(), ext_idx.begin());
355 
356  // 2) declare id[i]=i for scatter
357  std::vector<size_type> id (ext_idx.size());
358  for (size_type i = 0; i < id.size(); i++) id[i] = i;
359 
360  // 3) init scatter
363  ext_idx.size(),
364  ext_idx.begin().operator->(),
365  id.size(),
366  id.begin().operator->(),
367  ownership().dis_size(),
368  ownership().begin().operator->(),
369  tag_init,
370  ownership().comm(),
371  from,
372  to);
373 
374  // 4) begin scatter: send local data to others and get ask for missing data
375  std::vector<T,A> buffer (ext_idx.size());
378  begin().operator->(),
379  buffer.begin().operator->(),
380  from,
381  to,
382  set_op<T,T>(),
383  tag,
384  ownership().comm());
385 
386  // 5) end scatter: receive missing data
388  begin().operator->(),
389  buffer.begin(),
390  from,
391  to,
392  set_op<T,T>(),
393  tag,
394  ownership().comm());
395 
396  // 6) build the associative container: pair (ext_idx ; data)
397  for (size_type i = 0; i < buffer.size(); i++) {
398  ext_idx_map.insert (std::make_pair (ext_idx[i], buffer[i]));
399  }
400 }
401 template <class T, class A>
402 void
404 {
405  std::set<size_type> ext_idx_set;
406  for (typename scatter_map_type::const_iterator iter = _ext_x.begin(), last = _ext_x.end(); iter != last; iter++) {
407  ext_idx_set.insert ((*iter).first);
408  }
409  set_dis_indexes (ext_idx_set);
410 }
412 template <class T, class A>
413 template <class Set, class Map>
414 void
415 disarray_rep<T,distributed,A>::append_dis_entry (const Set& ext_idx_set, Map& ext_idx_map, std::true_type) const
416 {
417  typedef typename T::value_type S; // S is supposed to be MPI-simple, i.e. with fixed size
418 
419  // 0) declare the local context
420  typedef scatter_message<std::vector<T>, true> message_type; // TODO: vector<T,A> for heap_alloc
421 
422  message_type from;
423  message_type to;
424 
425  // 1) convert set to vector, for direct acess:
426  std::vector<size_type> ext_idx (ext_idx_set.size());
427  std::copy (ext_idx_set.begin(), ext_idx_set.end(), ext_idx.begin());
428 
429  // 2) declare id[i]=i for scatter
430  std::vector<size_type> id (ext_idx.size());
431  for (size_type i = 0; i < id.size(); i++) id[i] = i;
432 
433  // 3) init scatter
436  ext_idx.size(),
437  ext_idx.begin().operator->(),
438  id.size(),
439  id.begin().operator->(),
440  ownership().dis_size(),
441  ownership().begin().operator->(),
442  tag_init,
443  ownership().comm(),
444  from.get_base(),
445  to.get_base());
446 
447  // 4) copy size of multi-valued objects into a tmp
448  std::vector<size_type> data_sizes (size());
449  for (size_type i = 0, n = size(); i < n; i++) {
450  data_sizes[i] = base::operator[](i).size();
451  }
452  // 5) begin scatter: send local data to others and get ask for missing data
453  std::vector<size_type> buffer (ext_idx.size());
456  data_sizes.begin().operator->(),
457  buffer.begin().operator->(),
458  from.get_base(),
459  to.get_base(),
461  tag,
462  ownership().comm());
463 
464  // 6) end scatter: receive missing data
466  data_sizes.begin().operator->(),
467  buffer.begin(),
468  from.get_base(),
469  to.get_base(),
471  tag,
472  ownership().comm());
473 
474  // 7) initialize multi-valued scatter
475  from.multi_init();
476  to.multi_init();
477 
478  // 8) begin multi-valued scatter
479  std::vector<T> multi_buffer (ext_idx.size()); // TODO: vector<T,A> for heap_alloc
482  begin().operator->(),
483  multi_buffer.begin().operator->(),
484  from,
485  to,
486  set_op<T,T>(),
487  multi_tag,
488  ownership().comm());
489 
490  // 9) end scatter: receive missing data
492  begin().operator->(),
493  multi_buffer.begin(),
494  from,
495  to,
496  set_op<T,T>(),
497  multi_tag,
498  ownership().comm());
499 
500  // 10) build the associative container: pair (ext_idx ; data)
501  for (size_type i = 0; i < multi_buffer.size(); i++) {
502  ext_idx_map.insert (std::make_pair (ext_idx[i], multi_buffer[i]));
503  }
504 }
506 template <class T, class A>
507 template <class Set, class Map>
508 inline
509 void
510 disarray_rep<T,distributed,A>::append_dis_entry (const Set& ext_idx_set, Map& ext_idx_map) const
511 {
512  append_dis_entry (ext_idx_set, ext_idx_map, is_container());
513 }
514 template <class T, class A>
517 {
518  if (dis_i >= ownership().first_index() && dis_i < ownership().last_index()) {
519  size_type i = dis_i - ownership().first_index();
520  return base::operator[](i);
521  }
522  typename scatter_map_type::const_iterator iter = _ext_x.find (dis_i);
523  check_macro (iter != _ext_x.end(), "unexpected external index="<<dis_i);
524  return (*iter).second;
525 }
526 template <class T, class A>
527 void
528 disarray_rep<T,distributed,A>::get_dis_indexes (std::set<size_type>& ext_idx_set) const
529 {
530  ext_idx_set.clear();
531  for (auto x: _ext_x) {
532  ext_idx_set.insert (x.first);
533  }
534 }
535 // ===============================================================
536 // put & get
537 // ===============================================================
538 template <class T, class A>
539 template <class PutFunction>
541 disarray_rep<T,distributed,A>::put_values (odiststream& ops, PutFunction put_element) const
542 {
544  std::ostream& s = ops.os();
545 
546  // determine maximum message to arrive
547  size_type max_size = 0;
548  mpi::reduce(comm(), size(), max_size, mpi::maximum<size_type>(), 0);
549 
550  size_type io_proc = odiststream::io_proc();
551  if (ownership().process() == io_proc) {
552  for (size_type i = 0; i < size(); i++) {
553  put_element (s, base::operator[](i));
554  s << std::endl;
555  }
556  // receive and print messages
557  std::vector<T,A> values (max_size);
558  for (size_type iproc = 0; iproc < ownership().n_process(); iproc++) {
559  if (iproc == io_proc) continue;
560  size_type loc_sz_i = ownership().size(iproc);
561  if (loc_sz_i == 0) continue;
562  mpi::status status = comm().recv(iproc, tag, values.begin().operator->(), max_size);
563  boost::optional<int> n_data_opt = status.count<T>();
564  check_macro (n_data_opt, "receive failed");
565  size_type n_data = n_data_opt.get();
566  for (size_type i = 0; i < n_data; i++) {
567  put_element (s, values[i]);
568  s << std::endl;
569  }
570  }
571  s << std::flush;
572  } else {
573  if (size() != 0) {
574  comm().send(io_proc, tag, begin().operator->(), size());
575  }
576  }
577  return ops;
578 }
579 template <class T, class A>
582 {
583  return put_values (ops, _disarray_put_element_type<T>());
584 }
585 template <class T, class A>
588 {
589  ops << "[";
590  put_values (ops, _disarray_put_matlab_type<T>());
591  return ops << "];";
592 }
593 template <class T, class A>
594 template <class PutFunction, class A2>
597  odiststream& ops,
599  PutFunction put_element) const
600 {
601  assert_macro (perm.size() == size(), "permutation size does not match");
602  size_type io_proc = odiststream::io_proc();
603  size_type my_proc = comm().rank();
604  distributor io_ownership (dis_size(), comm(), (my_proc == io_proc) ? dis_size() : 0);
605  disarray_rep<T,distributed,A> perm_x (io_ownership);
606  for (size_type i = 0, n = size(); i < n; i++) {
607  perm_x.dis_entry (perm[i]) = base::operator[](i);
608  }
609  perm_x.template dis_entry_assembly_begin<typename default_set_op<T>::type>();
610  perm_x.template dis_entry_assembly_end <typename default_set_op<T>::type>();
611  return perm_x.base::put_values (ops, put_element);
612 }
613 template <class T, class A>
614 template <class GetFunction>
615 idiststream&
616 disarray_rep<T,distributed,A>::get_values (idiststream& ps, GetFunction get_element) {
618  std::istream& s = ps.is();
619  size_type io_proc = odiststream::io_proc();
620  if (ownership().process() == io_proc) {
621  // load first chunk associated to proc 0
622  if (!load_chunk (s, begin(), end(), get_element))
623  error_macro("read failed on input stream.");
624 
625  if (ownership().n_process() > 1) {
626  // read in other chuncks and send to other processors
627  // determine maximum chunck owned by other
628  size_type size_max = 1;
629  for (size_type iproc = 0; iproc < ownership().n_process(); iproc++) {
630  size_max = std::max (size_max, ownership().size(iproc));
631  }
632  std::vector<T,A> data_proc_j (size_max);
633  T *start_j = data_proc_j.begin().operator->();
634  // bizarre qu'on lise ts les blocs dans la meme zone de memoire
635  // et qu'on attende pas que ce soit envoye pour ecraser par le suivant ?
636  for (size_type jproc = 0; jproc < ownership().n_process(); jproc++) {
637  if (jproc == io_proc) continue;
638  // load first chunk associated to proc j
639  size_type loc_sz_j = ownership().size(jproc);
640  if (loc_sz_j == 0) continue;
641  T *last_j = start_j + loc_sz_j;
642  if (!load_chunk (s, start_j, last_j, get_element))
643  error_macro("read failed on input stream.");
644  comm().send (jproc, tag, start_j, loc_sz_j);
645  }
646  }
647  } else {
648  if (size() != 0) {
649  comm().recv(io_proc, tag, begin().operator->(), size());
650  }
651  }
652  return ps;
653 }
654 template <class T, class A>
655 idiststream&
657 {
658  return get_values (ips, _disarray_get_element_type<T>());
659 }
660 template <class T, class A>
661 void
663 {
664  base::dump (name + itos(comm().rank()));
665 }
666 
667 } // namespace rheolef
668 # endif // _RHEOLEF_HAVE_MPI
field::size_type size_type
Definition: branch.cc:425
dis_reference dis_entry(size_type dis_i)
Definition: disarray.h:344
is_container_of_mpi_datatype< T >::type is_container
Definition: disarray.h:428
reference operator[](size_type i)
Definition: disarray.h:248
distributor::communicator_type communicator_type
Definition: disarray.h:230
see the distributor page for the full documentation
Definition: distributor.h:62
static tag_type get_new_tag()
returns a new tag
Definition: distributor.cc:133
odiststream: see the diststream page for the full documentation
Definition: diststream.h:126
std::ostream & os()
Definition: diststream.h:236
static size_type io_proc()
Definition: diststream.cc:78
size_t size_type
Definition: basis_get.cc:76
rheolef::std value
#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:261
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
This file is part of Rheolef.
apply_iterator< Iterator, Operator > make_apply_iterator(Iterator i, Operator op)
Definition: msg_util.h:142
Size mpi_assembly_end(Message &receive, Message &send, Size receive_max_size, Container x)
void _stash_set(Map &stash, typename Map::size_type dis_i, const typename Map::mapped_type &val, std::false_type)
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)
std::string itos(std::string::size_type i)
itos: see the rheostream page for the full documentation
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)
void _stash_set_add(Map &stash, typename Map::size_type dis_i, const typename Map::mapped_type &val, std::false_type)
void _stash_set_add_multi(MultiMap &stash, typename MultiMap::size_type dis_i, const U &val, std::false_type)
disarray element input helper
Definition: disarray.h:206
disarray element output helper
Definition: disarray.h:197
std::false_type type