13 #include "libmesh/communicator.h" 14 #include "libmesh/parallel.h" 15 #include "libmesh/parallel_sync.h" 16 #include "libmesh/libmesh_common.h" 33 void swap(std::vector<T> & data,
34 const std::size_t idx0,
35 const std::size_t idx1,
38 void swap(std::vector<T> & data,
39 const std::size_t idx0,
40 const std::size_t idx1,
74 void shuffle(std::vector<T> & data,
MooseRandom & generator,
const std::size_t seed_index = 0);
76 void shuffle(std::vector<T> & data,
80 void shuffle(std::vector<T> & data,
82 const std::size_t seed_index,
85 void shuffle(std::vector<T> & data,
87 const std::size_t seed_index,
100 template <
typename T>
102 resample(
const std::vector<T> & data,
MooseRandom & generator,
const std::size_t seed_index = 0);
103 template <
typename T>
104 std::vector<T>
resample(
const std::vector<T> & data,
107 template <
typename T>
108 std::vector<T>
resample(
const std::vector<T> & data,
110 const std::size_t seed_index,
112 template <
typename T>
113 std::vector<T>
resample(
const std::vector<T> & data,
115 const std::size_t seed_index,
129 template <
typename T,
typename ActionFunctor>
131 const ActionFunctor & functor,
133 const std::size_t seed_index = 0);
134 template <
typename T,
typename ActionFunctor>
136 const ActionFunctor & functor,
139 template <
typename T,
typename ActionFunctor>
141 const ActionFunctor & functor,
143 const std::size_t seed_index,
145 template <
typename T,
typename ActionFunctor>
147 const ActionFunctor & functor,
149 const std::size_t seed_index,
154 template <
typename T>
157 const std::size_t idx0,
158 const std::size_t idx1,
161 if (!comm_ptr || comm_ptr->
size() == 1)
163 mooseAssert(idx0 < data.size(),
164 "idx0 (" << idx0 <<
") out of range, data.size() is " << data.size());
165 mooseAssert(idx1 < data.size(),
166 "idx1 (" << idx1 <<
") out of range, data.size() is " << data.size());
173 const auto n_local = data.size();
174 const auto rank = comm_ptr->
rank();
177 std::size_t n_global = n_local;
178 comm_ptr->
sum(n_global);
179 mooseAssert(idx0 < n_global,
180 "idx0 (" << idx0 <<
") out of range, the global data size is " << n_global);
181 mooseAssert(idx1 < n_global,
182 "idx1 (" << idx1 <<
") out of range, the global data size is " << n_global);
185 std::vector<std::size_t> offsets(comm_ptr->
size());
187 std::vector<std::size_t> local_sizes;
188 comm_ptr->
allgather(n_local, local_sizes);
189 for (std::size_t i = 0; i < local_sizes.size() - 1; ++i)
190 offsets[i + 1] = offsets[i] + local_sizes[i];
194 auto idx0_offset_iter = std::prev(std::upper_bound(offsets.begin(), offsets.end(), idx0));
195 auto idx0_rank = std::distance(offsets.begin(), idx0_offset_iter);
196 auto idx0_local_idx = idx0 - *idx0_offset_iter;
198 auto idx1_offset_iter = std::prev(std::upper_bound(offsets.begin(), offsets.end(), idx1));
199 auto idx1_rank = std::distance(offsets.begin(), idx1_offset_iter);
200 auto idx1_local_idx = idx1 - *idx1_offset_iter;
203 std::unordered_map<processor_id_type, std::vector<std::size_t>> needs;
204 if (idx0_rank != rank && idx1_rank == rank)
205 needs[idx0_rank].push_back(idx0_local_idx);
206 if (idx0_rank == rank && idx1_rank != rank)
207 needs[idx1_rank].push_back(idx1_local_idx);
210 std::unordered_map<processor_id_type, std::vector<T>> returns;
211 auto return_functor =
212 [&data, &returns](
processor_id_type pid,
const std::vector<std::size_t> & indices)
214 auto & returns_pid = returns[pid];
215 for (
auto idx : indices)
216 returns_pid.push_back(data[
idx]);
218 Parallel::push_parallel_vector_data(*comm_ptr, needs, return_functor);
221 std::vector<T> incoming;
222 auto recv_functor = [&incoming](
processor_id_type ,
const std::vector<T> & values)
223 { incoming = values; };
224 Parallel::push_parallel_vector_data(*comm_ptr, returns, recv_functor);
226 if (idx0_rank == rank && idx1_rank == rank)
229 else if (idx0_rank == rank)
231 mooseAssert(incoming.size() == 1,
"Only one value should be received");
232 data[idx0_local_idx] = incoming[0];
234 else if (idx1_rank == rank)
236 mooseAssert(incoming.size() == 1,
"Only one value should be received");
237 data[idx1_local_idx] = incoming[0];
242 template <
typename T>
246 const std::size_t seed_index,
250 if (!comm_ptr || comm_ptr->
size() == 1)
252 std::size_t n_global = data.size();
253 for (std::size_t i = n_global - 1; i > 0; --i)
255 auto j = generator.
randl(seed_index, 0, i);
264 std::size_t n_local = data.size();
265 std::size_t n_global = n_local;
266 comm_ptr->
sum(n_global);
269 std::vector<std::size_t> offsets(comm_ptr->
size());
271 std::vector<std::size_t> local_sizes;
272 comm_ptr->
allgather(n_local, local_sizes);
273 for (std::size_t i = 0; i < local_sizes.size() - 1; ++i)
274 offsets[i + 1] = offsets[i] + local_sizes[i];
278 auto rank = comm_ptr->
rank();
279 for (std::size_t idx0 = n_global - 1; idx0 > 0; --idx0)
281 auto idx1 = generator.
randl(seed_index, 0, idx0);
284 auto idx0_offset_iter = std::prev(std::upper_bound(offsets.begin(), offsets.end(), idx0));
285 auto idx0_rank = std::distance(offsets.begin(), idx0_offset_iter);
286 auto idx0_local_idx = idx0 - *idx0_offset_iter;
288 auto idx1_offset_iter = std::prev(std::upper_bound(offsets.begin(), offsets.end(), idx1));
289 auto idx1_rank = std::distance(offsets.begin(), idx1_offset_iter);
290 auto idx1_local_idx = idx1 - *idx1_offset_iter;
293 std::unordered_map<processor_id_type, std::vector<std::size_t>> needs;
294 if (idx0_rank != rank && idx1_rank == rank)
295 needs[idx0_rank].push_back(idx0_local_idx);
296 if (idx0_rank == rank && idx1_rank != rank)
297 needs[idx1_rank].push_back(idx1_local_idx);
300 std::unordered_map<processor_id_type, std::vector<T>> returns;
301 auto return_functor =
302 [&data, &returns](
processor_id_type pid,
const std::vector<std::size_t> & indices)
304 auto & returns_pid = returns[pid];
305 for (
auto idx : indices)
306 returns_pid.push_back(data[
idx]);
308 Parallel::push_parallel_vector_data(*comm_ptr, needs, return_functor);
311 std::vector<T> incoming;
312 auto recv_functor = [&incoming](
processor_id_type ,
const std::vector<T> & values)
313 { incoming = values; };
314 Parallel::push_parallel_vector_data(*comm_ptr, returns, recv_functor);
316 if (idx0_rank == rank && idx1_rank == rank)
319 else if (idx0_rank == rank)
321 mooseAssert(incoming.size() == 1,
"Only one value should be received");
322 data[idx0_local_idx] = incoming[0];
324 else if (idx1_rank == rank)
326 mooseAssert(incoming.size() == 1,
"Only one value should be received");
327 data[idx1_local_idx] = incoming[0];
333 template <
typename T>
337 const std::size_t seed_index,
341 const std::size_t n_local = data.size();
344 std::vector<T> replicate(n_local);
347 if (!comm_ptr || comm_ptr->
size() == 1)
349 replicate.resize(n_local);
350 for (std::size_t j = 0; j < n_local; ++j)
352 auto index = generator.
randl(seed_index, 0, n_local);
353 replicate[j] = data[index];
361 std::size_t n_global = n_local;
362 comm_ptr->
sum(n_global);
365 std::vector<std::size_t> offsets(comm_ptr->
size());
367 std::vector<std::size_t> local_sizes;
368 comm_ptr->
allgather(n_local, local_sizes);
369 for (std::size_t i = 0; i < local_sizes.size() - 1; ++i)
370 offsets[i + 1] = offsets[i] + local_sizes[i];
374 const auto rank = comm_ptr->
rank();
375 for (std::size_t i = 0; i < offsets[rank]; ++i)
376 generator.
randl(seed_index, 0, n_global);
379 std::unordered_map<processor_id_type, std::vector<std::pair<std::size_t, std::size_t>>> needs;
380 for (std::size_t i = 0; i < n_local; ++i)
382 const auto idx = generator.
randl(seed_index, 0, n_global);
385 const auto idx_offset_iter = std::prev(std::upper_bound(offsets.begin(), offsets.end(),
idx));
386 const auto idx_rank = std::distance(offsets.begin(), idx_offset_iter);
387 const auto idx_local_idx =
idx - *idx_offset_iter;
391 if (idx_rank == rank)
392 replicate[i] = data[idx_local_idx];
394 needs[idx_rank].emplace_back(idx_local_idx, i);
398 for (std::size_t i = offsets[rank] + n_local; i < n_global; ++i)
399 generator.
randl(seed_index, 0, n_global);
402 std::unordered_map<processor_id_type, std::vector<std::pair<T, std::size_t>>> returns;
403 auto return_functor =
405 const std::vector<std::pair<std::size_t, std::size_t>> & indices)
407 auto & returns_pid = returns[pid];
408 for (
const auto &
idx : indices)
409 returns_pid.emplace_back(data[
idx.first],
idx.second);
411 Parallel::push_parallel_vector_data(*comm_ptr, needs, return_functor);
415 [&replicate](
processor_id_type,
const std::vector<std::pair<T, std::size_t>> & values)
417 for (
const auto &
value : values)
420 Parallel::push_parallel_vector_data(*comm_ptr, returns, recv_functor);
425 template <
typename T,
typename ActionFunctor>
428 const ActionFunctor & functor,
430 const std::size_t seed_index,
433 const std::size_t n_local = data.size();
435 if (!comm_ptr || comm_ptr->
size() == 1)
437 for (std::size_t j = 0; j < n_local; ++j)
439 auto index = generator.
randl(seed_index, 0, n_local);
440 functor(data[index]);
446 std::size_t n_global = n_local;
447 comm_ptr->
sum(n_global);
450 std::vector<std::size_t> offsets(comm_ptr->
size());
452 std::vector<std::size_t> local_sizes;
453 comm_ptr->
allgather(n_local, local_sizes);
454 for (std::size_t i = 0; i < local_sizes.size() - 1; ++i)
455 offsets[i + 1] = offsets[i] + local_sizes[i];
459 const auto rank = comm_ptr->
rank();
460 for (std::size_t i = 0; i < offsets[rank]; ++i)
461 generator.
randl(seed_index, 0, n_global);
464 std::unordered_map<processor_id_type, std::vector<std::size_t>> indices;
465 for (std::size_t i = 0; i < n_local; ++i)
467 const auto idx = generator.
randl(seed_index, 0, n_global);
470 const auto idx_offset_iter = std::prev(std::upper_bound(offsets.begin(), offsets.end(),
idx));
471 const auto idx_rank = std::distance(offsets.begin(), idx_offset_iter);
472 const auto idx_local_idx =
idx - *idx_offset_iter;
475 indices[idx_rank].push_back(idx_local_idx);
479 for (std::size_t i = offsets[rank] + n_local; i < n_global; ++i)
480 generator.
randl(seed_index, 0, n_global);
486 for (
const auto &
idx : indices)
489 Parallel::push_parallel_vector_data(*comm_ptr, indices, act_functor);
493 template <
typename T>
496 const std::size_t idx0,
497 const std::size_t idx1,
500 MooseUtils::swap<T>(data, idx0, idx1, &comm);
503 template <
typename T>
510 template <
typename T>
519 template <
typename T>
523 const std::size_t seed_index,
529 template <
typename T>
533 const std::size_t seed_index)
538 template <
typename T>
547 template <
typename T>
551 const std::size_t seed_index,
557 template <
typename T,
typename ActionFunctor>
560 const ActionFunctor & functor,
562 const std::size_t seed_index)
567 template <
typename T,
typename ActionFunctor>
570 const ActionFunctor & functor,
577 template <
typename T,
typename ActionFunctor>
580 const ActionFunctor & functor,
582 const std::size_t seed_index,
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
static uint32_t randl()
This method returns the next random number (long format) from the generator.
void swap(std::vector< T > &data, const std::size_t idx0, const std::size_t idx1, const libMesh::Parallel::Communicator &comm)
Swap function for serial or distributed vector of data.
void shuffle(std::vector< T > &data, MooseRandom &generator, const std::size_t seed_index=0)
Shuffle function for serial or distributed vector of data that shuffles in place. ...
processor_id_type rank() const
std::vector< T > resample(const std::vector< T > &data, MooseRandom &generator, const std::size_t seed_index=0)
Randomly resample a vector of data, allowing a value to be repeated.
processor_id_type size() const
void resampleWithFunctor(const std::vector< T > &data, const ActionFunctor &functor, MooseRandom &generator, const std::size_t seed_index=0)
Randomly resample a vector of data and apply a functor, allowing a value to be repeated.
uint8_t processor_id_type
void swap(std::vector< T > &data, const std::size_t idx0, const std::size_t idx1, const libMesh::Parallel::Communicator *comm_ptr=nullptr)
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
This class encapsulates a useful, consistent, cross-platform random number generator with multiple ut...