22# include "rheolef/config.h"
23# ifdef _RHEOLEF_HAVE_MPI
25# include "rheolef/disarray.h"
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"
40template <
class T,
class A>
50 x._send.data.size() == 0 &&
51 x._receive.data.size() == 0,
52 "copy during assembly phase: should not be done");
54template <
class T,
class A>
59 :
base(ownership, init_val,alloc),
67template <
class T,
class A>
73 base::resize(ownership, init_val);
77 _receive.waits.clear();
78 _receive.data.clear();
79 _receive_max_size = 0;
87template <
class Map,
class SetOp>
90stash_set (Map& stash,
typename Map::size_type dis_i,
const typename Map::mapped_type& val,
const SetOp& set_op, std::false_type)
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);
98template <
class MultiMap,
class U>
100stash_set (MultiMap& stash,
typename MultiMap::size_type dis_i,
const U& val,
const details::generic_set_op&, std::true_type)
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);
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));
113template <
class MultiMap,
class U>
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)
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));
123template <
class MultiMap,
class U>
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)
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));
133template <
class MultiMap,
class U>
136stash_set (MultiMap& stash,
typename MultiMap::size_type dis_i,
const U& val,
const details::generic_set_plus_op& set_op, std::true_type)
144template <
class T,
class A>
145template<
class U,
class SetOp>
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));
158 "index "<<dis_i <<
" is out of range [0:" << ownership().dis_size() <<
"[");
162 typename scatter_map_type::iterator iter = _ext_x.find (dis_i);
163 if (iter != _ext_x.end()) {
164 set_op ((*iter).second, value);
170template <
class T,
class A>
171template<
class U,
class SetOp>
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);
181 "index "<<dis_i<<
" is out of range [0:"<<ownership().dis_size() <<
"[");
185 typename scatter_map_type::iterator iter = _ext_x.find (dis_i);
186 if (iter != _ext_x.end()) {
187 set_op ((*iter).second, value);
192template <
class T,
class A>
193template<
class U,
class SetOp>
195disarray_rep<T,distributed,A>::set_minus_dis_entry (
size_type dis_i,
const U& value,
const SetOp& set_op)
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);
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());
207 typename scatter_map_type::iterator iter = _ext_x.find (dis_i);
208 if (iter != _ext_x.end()) {
209 set_op ((*iter).second, value);
217template <
class T,
class A>
218template <
class SetOp>
232template <
class T,
class A>
233template <
class SetOp>
242 begin() - ownership().first_index(),
249 _receive.waits.clear();
250 _receive.data.clear();
251 _receive_max_size = 0;
256template <
class T,
class A>
269 vector<size_type> send_local_elt_size (nproc, 0);
271 for (
size_type ie = 0; ie < partition.size(); ie++, iter_part++) {
272 send_local_elt_size [*iter_part]++;
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];
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];
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();
294 for (
size_type ie = 0, ne = partition.size(); ie < ne; ie++, iter_part++, iter_elt++, iter_new_num_elt++) {
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]++;
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>();
307template <
class T,
class A>
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;
321 inew2dis_iold.template dis_entry_assembly<typename details::default_set_op_traits<T>::type>();
323template <
class T,
class A>
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");
335 for (
const_iterator iter = begin(), last = end(); iter != last; iter++, iter_dis_new_ie++) {
337 new_disarray.dis_entry (dis_new_ie) = *iter;
339 new_disarray.template dis_entry_assembly<typename details::default_set_op_traits<T>::type>();
342template <
class T,
class A>
343template <
class Set,
class Map>
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());
356 std::vector<size_type> id (ext_idx.size());
357 for (
size_type i = 0; i <
id.size(); i++)
id[i] = i;
363 ext_idx.begin().operator->(),
365 id.begin().operator->(),
366 ownership().dis_size(),
367 ownership().begin().operator->(),
374 std::vector<T,A> buffer (ext_idx.size());
377 begin().operator->(),
378 buffer.begin().operator->(),
381 details::generic_set_op(),
387 begin().operator->(),
391 details::generic_set_op(),
396 for (
size_type i = 0; i < buffer.size(); i++) {
397 ext_idx_map.insert (std::make_pair (ext_idx[i], buffer[i]));
400template <
class T,
class A>
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);
408 set_dis_indexes (ext_idx_set);
411template <
class T,
class A>
412template <
class Set,
class Map>
416 typedef typename T::value_type S;
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());
429 std::vector<size_type> id (ext_idx.size());
430 for (
size_type i = 0; i <
id.size(); i++)
id[i] = i;
436 ext_idx.begin().operator->(),
438 id.begin().operator->(),
439 ownership().dis_size(),
440 ownership().begin().operator->(),
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();
452 std::vector<size_type> buffer (ext_idx.size());
455 data_sizes.begin().operator->(),
456 buffer.begin().operator->(),
459 details::generic_set_op(),
465 data_sizes.begin().operator->(),
469 details::generic_set_op(),
478 std::vector<T> multi_buffer (ext_idx.size());
481 begin().operator->(),
482 multi_buffer.begin().operator->(),
485 details::generic_set_op(),
491 begin().operator->(),
492 multi_buffer.begin(),
495 details::generic_set_op(),
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]));
505template <
class T,
class A>
506template <
class Set,
class Map>
511 append_dis_entry (ext_idx_set, ext_idx_map,
is_container());
513template <
class T,
class A>
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);
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;
525template <
class T,
class A>
530 for (
auto x: _ext_x) {
531 ext_idx_set.insert (x.first);
537template <
class T,
class A>
538template <
class PutFunction>
543 std::ostream& s = ops.
os();
547 mpi::reduce(comm(), size(), max_size, mpi::maximum<size_type>(), 0);
550 if (ownership().process() == io_proc) {
552 put_element (s, base::operator[](i));
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>();
566 put_element (s, values[i]);
573 comm().send(io_proc, tag, begin().operator->(), size());
578template <
class T,
class A>
584template <
class T,
class A>
592template <
class T,
class A>
593template <
class PutFunction,
class A2>
598 PutFunction put_element)
const
600 assert_macro (perm.size() == size(),
"permutation size does not match");
603 distributor io_ownership (dis_size(), comm(), (my_proc == io_proc) ? dis_size() : 0);
605 for (
size_type i = 0, n = size(); i < n; i++) {
606 perm_x.dis_entry (perm[i]) = base::operator[](i);
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);
612template <
class T,
class A>
613template <
class GetFunction>
617 std::istream& s = ps.
is();
619 if (ownership().process() == io_proc) {
621 if (!
load_chunk (s, begin(), end(), get_element))
624 if (ownership().n_process() > 1) {
628 for (
size_type iproc = 0; iproc < ownership().n_process(); iproc++) {
629 size_max = std::max (size_max, ownership().size(iproc));
631 std::vector<T,A> data_proc_j (size_max);
632 T *start_j = data_proc_j.begin().operator->();
635 for (
size_type jproc = 0; jproc < ownership().n_process(); jproc++) {
636 if (jproc == io_proc)
continue;
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))
643 comm().send (jproc, tag, start_j, loc_sz_j);
648 comm().recv(io_proc, tag, begin().operator->(), size());
653template <
class T,
class A>
659template <
class T,
class A>
663 base::dump (name + std::to_string(comm().rank()));
field::size_type size_type
details::is_container_of_mpi_datatype< T >::type is_container
distributor::communicator_type communicator_type
typename base::size_type size_type
typename base::const_iterator const_iterator
see the distributor page for the full documentation
static tag_type get_new_tag()
returns a new tag
idiststream: see the diststream page for the full documentation
odiststream: see the diststream page for the full documentation
static size_type io_proc()
#define trace_macro(message)
#define assert_macro(ok_condition, message)
#define error_macro(message)
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)
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)
Stash::size_type mpi_assembly_begin(const Stash &stash, InputIterator first_stash_idx, InputIterator last_stash_idx, const distributor &ownership, Message &receive, Message &send)
disarray element input helper
disarray element output helper