Rheolef  7.2
an efficient C++ finite element environment
 
Loading...
Searching...
No Matches
disarray_mpi.icc
Go to the documentation of this file.
1
21
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
36namespace rheolef {
37// ----------------------------------------------------------------------------
38// allocators
39// ----------------------------------------------------------------------------
40template <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}
54template <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}
67template <class T, class A>
68void
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// ===============================================================
84namespace details {
85
86// insert a "U value" for simple, or variable-sized one, as index_set or pair_set types
87template <class Map, class SetOp>
88inline
89void
90stash_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= += -=
98template <class MultiMap, class U>
99void
100stash_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
113template <class MultiMap, class U>
114inline
115void
116stash_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
123template <class MultiMap, class U>
124void
125stash_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}
133template <class MultiMap, class U>
134inline
135void
136stash_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 =
144template <class T, class A>
145template<class U, class SetOp>
146void
147disarray_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 +=
170template <class T, class A>
171template<class U, class SetOp>
172void
173disarray_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 -=
192template <class T, class A>
193template<class U, class SetOp>
194void
195disarray_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// ===============================================================
217template <class T, class A>
218template <class SetOp>
219void
221{
222 _receive_max_size = mpi_assembly_begin (
223 _stash,
226 ownership(),
227 _receive,
228 _send);
229
230 _stash.clear();
231}
232template <class T, class A>
233template <class SetOp>
234void
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// ===============================================================
256template <class T, class A>
257template <class A2>
258void
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}
307template <class T, class A>
308template <class A2>
309void
310disarray_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}
323template <class T, class A>
324template <class A2>
325void
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}
342template <class T, class A>
343template <class Set, class Map>
344void
345disarray_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}
400template <class T, class A>
401void
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}
411template <class T, class A>
412template <class Set, class Map>
413void
414disarray_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}
505template <class T, class A>
506template <class Set, class Map>
507inline
508void
509disarray_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}
513template <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}
525template <class T, class A>
526void
527disarray_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// ===============================================================
537template <class T, class A>
538template <class PutFunction>
540disarray_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
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}
578template <class T, class A>
581{
582 return put_values (ops, _disarray_put_element_type<T>());
583}
584template <class T, class A>
587{
588 ops << "[";
589 put_values (ops, _disarray_put_matlab_type<T>());
590 return ops << "];";
591}
592template <class T, class A>
593template <class PutFunction, class A2>
596 odiststream& ops,
598 PutFunction put_element) const
599{
600 assert_macro (perm.size() == size(), "permutation size does not match");
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}
612template <class T, class A>
613template <class GetFunction>
617 std::istream& s = ps.is();
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}
653template <class T, class A>
659template <class T, class A>
660void
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
details::is_container_of_mpi_datatype< T >::type is_container
Definition disarray.h:416
distributor::communicator_type communicator_type
Definition disarray.h:304
typename base::size_type size_type
Definition disarray.h:296
typename base::const_iterator const_iterator
Definition disarray.h:300
see the distributor page for the full documentation
Definition distributor.h:69
static tag_type get_new_tag()
returns a new tag
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
#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)")
void stash_set(Map &stash, typename Map::size_type dis_i, const typename Map::mapped_type &val, const SetOp &set_op, std::false_type)
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)
This file is part of Rheolef.
Size mpi_assembly_end(Message &receive, Message &send, Size receive_max_size, Container x)
void mpi_scatter_end(InputIterator x, OutputIterator y, Message &from, Message &to, SetOp op, Tag tag, Comm comm)
void mpi_scatter_begin(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
disarray_store< OutputRandomIterator, SetOp, Size, IsContainer > disarray_make_store(OutputRandomIterator x, SetOp op, Size, IsContainer)
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)
apply_iterator< Iterator, Operator > make_apply_iterator(Iterator i, Operator op)
Definition msg_util.h:114
Stash::size_type mpi_assembly_begin(const Stash &stash, InputIterator first_stash_idx, InputIterator last_stash_idx, const distributor &ownership, Message &receive, Message &send)
STL namespace.
disarray element input helper
Definition disarray.h:205
disarray element output helper
Definition disarray.h:196