12 #include "libmesh/communicator.h" 13 #include "libmesh/parallel.h" 14 #include "libmesh/parallel_sync.h" 15 #include "libmesh/libmesh_common.h" 32 void swap(std::vector<T> & data,
33 const std::size_t idx0,
34 const std::size_t idx1,
37 void swap(std::vector<T> & data,
38 const std::size_t idx0,
39 const std::size_t idx1,
73 void shuffle(std::vector<T> & data,
MooseRandom & generator,
const std::size_t seed_index = 0);
75 void shuffle(std::vector<T> & data,
79 void shuffle(std::vector<T> & data,
81 const std::size_t seed_index,
84 void shuffle(std::vector<T> & data,
86 const std::size_t seed_index,
101 resample(
const std::vector<T> & data,
MooseRandom & generator,
const std::size_t seed_index = 0);
102 template <
typename T>
103 std::vector<T>
resample(
const std::vector<T> & data,
106 template <
typename T>
107 std::vector<T>
resample(
const std::vector<T> & data,
109 const std::size_t seed_index,
111 template <
typename T>
112 std::vector<T>
resample(
const std::vector<T> & data,
114 const std::size_t seed_index,
128 template <
typename T,
typename ActionFunctor>
130 const ActionFunctor & functor,
132 const std::size_t seed_index = 0);
133 template <
typename T,
typename ActionFunctor>
135 const ActionFunctor & functor,
138 template <
typename T,
typename ActionFunctor>
140 const ActionFunctor & functor,
142 const std::size_t seed_index,
144 template <
typename T,
typename ActionFunctor>
146 const ActionFunctor & functor,
148 const std::size_t seed_index,
153 template <
typename T>
156 const std::size_t idx0,
157 const std::size_t idx1,
160 if (!comm_ptr || comm_ptr->
size() == 1)
162 mooseAssert(idx0 < data.size(),
163 "idx0 (" << idx0 <<
") out of range, data.size() is " << data.size());
164 mooseAssert(idx1 < data.size(),
165 "idx1 (" << idx1 <<
") out of range, data.size() is " << data.size());
172 const auto n_local = data.size();
173 const auto rank = comm_ptr->
rank();
176 std::size_t n_global = n_local;
177 comm_ptr->
sum(n_global);
178 mooseAssert(idx0 < n_global,
179 "idx0 (" << idx0 <<
") out of range, the global data size is " << n_global);
180 mooseAssert(idx1 < n_global,
181 "idx1 (" << idx1 <<
") out of range, the global data size is " << n_global);
184 std::vector<std::size_t> offsets(comm_ptr->
size());
186 std::vector<std::size_t> local_sizes;
187 comm_ptr->
allgather(n_local, local_sizes);
188 for (std::size_t i = 0; i < local_sizes.size() - 1; ++i)
189 offsets[i + 1] = offsets[i] + local_sizes[i];
193 auto idx0_offset_iter = std::prev(std::upper_bound(offsets.begin(), offsets.end(), idx0));
194 auto idx0_rank = std::distance(offsets.begin(), idx0_offset_iter);
195 auto idx0_local_idx = idx0 - *idx0_offset_iter;
197 auto idx1_offset_iter = std::prev(std::upper_bound(offsets.begin(), offsets.end(), idx1));
198 auto idx1_rank = std::distance(offsets.begin(), idx1_offset_iter);
199 auto idx1_local_idx = idx1 - *idx1_offset_iter;
202 std::unordered_map<processor_id_type, std::vector<std::size_t>> needs;
203 if (idx0_rank != rank && idx1_rank == rank)
204 needs[idx0_rank].push_back(idx0_local_idx);
205 if (idx0_rank == rank && idx1_rank != rank)
206 needs[idx1_rank].push_back(idx1_local_idx);
209 std::unordered_map<processor_id_type, std::vector<T>> returns;
210 auto return_functor =
211 [&data, &returns](
processor_id_type pid,
const std::vector<std::size_t> & indices)
213 auto & returns_pid = returns[pid];
214 for (
auto idx : indices)
215 returns_pid.push_back(data[
idx]);
217 Parallel::push_parallel_vector_data(*comm_ptr, needs, return_functor);
220 std::vector<T> incoming;
221 auto recv_functor = [&incoming](
processor_id_type ,
const std::vector<T> & values)
222 { incoming = values; };
223 Parallel::push_parallel_vector_data(*comm_ptr, returns, recv_functor);
225 if (idx0_rank == rank && idx1_rank == rank)
228 else if (idx0_rank == rank)
230 mooseAssert(incoming.size() == 1,
"Only one value should be received");
231 data[idx0_local_idx] = incoming[0];
233 else if (idx1_rank == rank)
235 mooseAssert(incoming.size() == 1,
"Only one value should be received");
236 data[idx1_local_idx] = incoming[0];
241 template <
typename T>
245 const std::size_t seed_index,
249 if (!comm_ptr || comm_ptr->
size() == 1)
251 std::size_t n_global = data.size();
252 for (std::size_t i = n_global - 1; i > 0; --i)
254 auto j = generator.
randl(seed_index, 0, i);
263 std::size_t n_local = data.size();
264 std::size_t n_global = n_local;
265 comm_ptr->
sum(n_global);
268 std::vector<std::size_t> offsets(comm_ptr->
size());
270 std::vector<std::size_t> local_sizes;
271 comm_ptr->
allgather(n_local, local_sizes);
272 for (std::size_t i = 0; i < local_sizes.size() - 1; ++i)
273 offsets[i + 1] = offsets[i] + local_sizes[i];
277 auto rank = comm_ptr->
rank();
278 for (std::size_t idx0 = n_global - 1; idx0 > 0; --idx0)
280 auto idx1 = generator.
randl(seed_index, 0, idx0);
283 auto idx0_offset_iter = std::prev(std::upper_bound(offsets.begin(), offsets.end(), idx0));
284 auto idx0_rank = std::distance(offsets.begin(), idx0_offset_iter);
285 auto idx0_local_idx = idx0 - *idx0_offset_iter;
287 auto idx1_offset_iter = std::prev(std::upper_bound(offsets.begin(), offsets.end(), idx1));
288 auto idx1_rank = std::distance(offsets.begin(), idx1_offset_iter);
289 auto idx1_local_idx = idx1 - *idx1_offset_iter;
292 std::unordered_map<processor_id_type, std::vector<std::size_t>> needs;
293 if (idx0_rank != rank && idx1_rank == rank)
294 needs[idx0_rank].push_back(idx0_local_idx);
295 if (idx0_rank == rank && idx1_rank != rank)
296 needs[idx1_rank].push_back(idx1_local_idx);
299 std::unordered_map<processor_id_type, std::vector<T>> returns;
300 auto return_functor =
301 [&data, &returns](
processor_id_type pid,
const std::vector<std::size_t> & indices)
303 auto & returns_pid = returns[pid];
304 for (
auto idx : indices)
305 returns_pid.push_back(data[
idx]);
307 Parallel::push_parallel_vector_data(*comm_ptr, needs, return_functor);
310 std::vector<T> incoming;
311 auto recv_functor = [&incoming](
processor_id_type ,
const std::vector<T> & values)
312 { incoming = values; };
313 Parallel::push_parallel_vector_data(*comm_ptr, returns, recv_functor);
315 if (idx0_rank == rank && idx1_rank == rank)
318 else if (idx0_rank == rank)
320 mooseAssert(incoming.size() == 1,
"Only one value should be received");
321 data[idx0_local_idx] = incoming[0];
323 else if (idx1_rank == rank)
325 mooseAssert(incoming.size() == 1,
"Only one value should be received");
326 data[idx1_local_idx] = incoming[0];
332 template <
typename T>
336 const std::size_t seed_index,
340 const std::size_t n_local = data.size();
343 std::vector<T> replicate(n_local);
346 if (!comm_ptr || comm_ptr->
size() == 1)
348 replicate.resize(n_local);
349 for (std::size_t j = 0; j < n_local; ++j)
351 auto index = generator.
randl(seed_index, 0, n_local);
352 replicate[j] = data[index];
360 std::size_t n_global = n_local;
361 comm_ptr->
sum(n_global);
364 std::vector<std::size_t> offsets(comm_ptr->
size());
366 std::vector<std::size_t> local_sizes;
367 comm_ptr->
allgather(n_local, local_sizes);
368 for (std::size_t i = 0; i < local_sizes.size() - 1; ++i)
369 offsets[i + 1] = offsets[i] + local_sizes[i];
373 const auto rank = comm_ptr->
rank();
374 for (std::size_t i = 0; i < offsets[rank]; ++i)
375 generator.
randl(seed_index, 0, n_global);
378 std::unordered_map<processor_id_type, std::vector<std::pair<std::size_t, std::size_t>>> needs;
379 for (std::size_t i = 0; i < n_local; ++i)
381 const auto idx = generator.
randl(seed_index, 0, n_global);
384 const auto idx_offset_iter = std::prev(std::upper_bound(offsets.begin(), offsets.end(),
idx));
385 const auto idx_rank = std::distance(offsets.begin(), idx_offset_iter);
386 const auto idx_local_idx =
idx - *idx_offset_iter;
390 if (idx_rank == rank)
391 replicate[i] = data[idx_local_idx];
393 needs[idx_rank].emplace_back(idx_local_idx, i);
397 for (std::size_t i = offsets[rank] + n_local; i < n_global; ++i)
398 generator.
randl(seed_index, 0, n_global);
401 std::unordered_map<processor_id_type, std::vector<std::pair<T, std::size_t>>> returns;
402 auto return_functor =
404 const std::vector<std::pair<std::size_t, std::size_t>> & indices)
406 auto & returns_pid = returns[pid];
407 for (
const auto &
idx : indices)
408 returns_pid.emplace_back(data[
idx.first],
idx.second);
410 Parallel::push_parallel_vector_data(*comm_ptr, needs, return_functor);
414 [&replicate](
processor_id_type,
const std::vector<std::pair<T, std::size_t>> & values)
416 for (
const auto &
value : values)
419 Parallel::push_parallel_vector_data(*comm_ptr, returns, recv_functor);
424 template <
typename T,
typename ActionFunctor>
427 const ActionFunctor & functor,
429 const std::size_t seed_index,
432 const std::size_t n_local = data.size();
434 if (!comm_ptr || comm_ptr->
size() == 1)
436 for (std::size_t j = 0; j < n_local; ++j)
438 auto index = generator.
randl(seed_index, 0, n_local);
439 functor(data[index]);
445 std::size_t n_global = n_local;
446 comm_ptr->
sum(n_global);
449 std::vector<std::size_t> offsets(comm_ptr->
size());
451 std::vector<std::size_t> local_sizes;
452 comm_ptr->
allgather(n_local, local_sizes);
453 for (std::size_t i = 0; i < local_sizes.size() - 1; ++i)
454 offsets[i + 1] = offsets[i] + local_sizes[i];
458 const auto rank = comm_ptr->
rank();
459 for (std::size_t i = 0; i < offsets[rank]; ++i)
460 generator.
randl(seed_index, 0, n_global);
463 std::unordered_map<processor_id_type, std::vector<std::size_t>> indices;
464 for (std::size_t i = 0; i < n_local; ++i)
466 const auto idx = generator.
randl(seed_index, 0, n_global);
469 const auto idx_offset_iter = std::prev(std::upper_bound(offsets.begin(), offsets.end(),
idx));
470 const auto idx_rank = std::distance(offsets.begin(), idx_offset_iter);
471 const auto idx_local_idx =
idx - *idx_offset_iter;
474 indices[idx_rank].push_back(idx_local_idx);
478 for (std::size_t i = offsets[rank] + n_local; i < n_global; ++i)
479 generator.
randl(seed_index, 0, n_global);
485 for (
const auto &
idx : indices)
488 Parallel::push_parallel_vector_data(*comm_ptr, indices, act_functor);
492 template <
typename T>
495 const std::size_t idx0,
496 const std::size_t idx1,
499 MooseUtils::swap<T>(data, idx0, idx1, &comm);
502 template <
typename T>
509 template <
typename T>
518 template <
typename T>
522 const std::size_t seed_index,
528 template <
typename T>
532 const std::size_t seed_index)
537 template <
typename T>
546 template <
typename T>
550 const std::size_t seed_index,
556 template <
typename T,
typename ActionFunctor>
559 const ActionFunctor & functor,
561 const std::size_t seed_index)
566 template <
typename T,
typename ActionFunctor>
569 const ActionFunctor & functor,
576 template <
typename T,
typename ActionFunctor>
579 const ActionFunctor & functor,
581 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...